From 95d43a093c080e672552ddc4e4d2caf9bfe16f1f Mon Sep 17 00:00:00 2001 From: arnabcs17b006 Date: Sat, 25 Jul 2020 11:57:37 +0530 Subject: [PATCH 1/6] event support for xen --- Cargo.toml | 8 ++- examples/cr-events.rs | 15 ++--- examples/regs-dump.rs | 2 +- src/driver/xen.rs | 126 ++++++++++++++++++++++++++++++++++++++---- 4 files changed, 129 insertions(+), 22 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5f1cc3c5..19a4d154 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,16 +28,20 @@ hyper-v = ["winapi", "widestring", "ntapi", "vid-sys"] log = "0.4.8" env_logger = "0.7.1" libc = { version = "0.2.58", optional = true } -xenctrl = { git = "https://github.com/Wenzel/xenctrl", optional = true } +xenctrl = { git = "https://github.com/arnabcs17b006/xenctrl", branch = "write_register", optional = true } xenstore = { git = "https://github.com/Wenzel/xenstore", optional = true } xenforeignmemory = { git = "https://github.com/Wenzel/xenforeignmemory", optional = true } -kvmi = { git = "https://github.com/Wenzel/kvmi", rev = "dd10135a27bb3658d399dfb5477299ca0f4baeac", optional = true } +xenevtchn = { git = "https://github.com/arnabcs17b006/xenevtchn", branch = "event-notification"} +xenvmevent-sys = { git = "https://github.com/Wenzel/xenvmevent-sys"} +kvmi = { git = "https://github.com/Wenzel/kvmi", optional = true } +>>>>>>> event support for xen fdp = { git = "https://github.com/Wenzel/fdp", optional = true } winapi = { version = "0.3.8", features = ["tlhelp32", "winnt", "handleapi", "securitybaseapi"], optional = true } widestring = { version = "0.4.0", optional = true } ntapi = { version = "0.3.3", optional = true } vid-sys = { version = "0.3.0", features = ["deprecated-apis"], optional = true } cty = "0.2.1" +nix = "0.18.0" [dev-dependencies] ctrlc = "3.1.3" diff --git a/examples/cr-events.rs b/examples/cr-events.rs index 8bd89c2e..4810748f 100644 --- a/examples/cr-events.rs +++ b/examples/cr-events.rs @@ -42,10 +42,11 @@ fn toggle_cr_intercepts(drv: &mut Box, vec_cr: &Vec, let intercept = InterceptType::Cr(*cr); let status_str = if enabled { "Enabling" } else { "Disabling" }; println!("{} intercept on {:?}", status_str, cr); - for vcpu in 0..drv.get_vcpu_count().unwrap() { - drv.toggle_intercept(vcpu, intercept, enabled) - .expect(&format!("Failed to enable {:?}", cr)); - } + //for vcpu in 0..drv.get_vcpu_count().unwrap() { + let vcpu = 0; + drv.toggle_intercept(vcpu, intercept, enabled) + .expect(&format!("Failed to enable {:?}", cr)); + //} } drv.resume().expect("Failed to resume VM"); @@ -101,7 +102,7 @@ fn main() { // listen let mut i: u64 = 0; while running.load(Ordering::SeqCst) { - let event = drv.listen(1000).expect("Failed to listen for events"); + let event = drv.listen(10).expect("Failed to listen for events"); match event { Some(ev) => { let (cr_type, new, old) = match ev.kind { @@ -120,8 +121,8 @@ fn main() { "[{}] {} - {}: old value: 0x{:x} new value: 0x{:x}", ev_nb_output, vcpu_output, cr_output, old, new ); - drv.reply_event(ev, EventReplyType::Continue) - .expect("Failed to send event reply"); + // drv.reply_event(ev, EventReplyType::Continue) + // .expect("Failed to send event reply"); i = i + 1; } None => println!("No events yet..."), diff --git a/examples/regs-dump.rs b/examples/regs-dump.rs index 9495f9d3..68295913 100644 --- a/examples/regs-dump.rs +++ b/examples/regs-dump.rs @@ -33,7 +33,7 @@ fn main() { println!("pausing the VM"); drv.pause().expect("Failed to pause VM"); - let total_vcpu_count: u16 = drv.get_vcpu_count().expect("Failed to get vcpu count"); + let total_vcpu_count: u16 = 1; for vcpu in 0..total_vcpu_count { println!("dumping registers on VCPU {}", vcpu); let regs = drv.read_registers(vcpu).expect("Failed to read registers"); diff --git a/src/driver/xen.rs b/src/driver/xen.rs index 388c90d0..fc8fa9e1 100644 --- a/src/driver/xen.rs +++ b/src/driver/xen.rs @@ -1,17 +1,32 @@ -use crate::api::{DriverInitParam, Introspectable, Registers, SegmentReg, X86Registers}; -use libc::PROT_READ; use std::error::Error; +use std::mem; + +use crate::api::{ + CrType, Event, EventType, InterceptType, Introspectable, Registers, SegmentReg, X86Registers, DriverInitParam, +}; + +use libc::PROT_READ; +use nix::poll::PollFlags; +use nix::poll::{poll, PollFd}; +use std::convert::TryInto; use xenctrl::consts::{PAGE_SHIFT, PAGE_SIZE}; -use xenctrl::XenControl; +use xenctrl::RING_HAS_UNCONSUMED_REQUESTS; +use xenctrl::{XenControl, XenCr, XenEventType}; +use xenevtchn::XenEventChannel; +use xenforeignmemory::XenForeignMem; use xenstore::{XBTransaction, Xs, XsOpenFlags}; +use xenvmevent_sys::{ + vm_event_back_ring, vm_event_response_t, VM_EVENT_FLAG_VCPU_PAUSED, VM_EVENT_INTERFACE_VERSION, +}; -// unit struct #[derive(Debug)] pub struct Xen { xc: XenControl, - xen_fgn: xenforeignmemory::XenForeignMem, + xev: XenEventChannel, + xen_fgn: XenForeignMem, dom_name: String, domid: u32, + back_ring: vm_event_back_ring, } impl Xen { @@ -33,21 +48,25 @@ impl Xen { if !found { panic!("Cannot find domain {}", domain_name); } - let xc = XenControl::new(None, None, 0).unwrap(); - let xen_fgn = xenforeignmemory::XenForeignMem::new().unwrap(); + + let mut xc = XenControl::new(None, None, 0).unwrap(); + let (_ring_page, back_ring, remote_port) = xc + .monitor_enable(cand_domid) + .expect("Failed to map event ring page"); + let xev = XenEventChannel::new(cand_domid, remote_port).unwrap(); + + let xen_fgn = XenForeignMem::new().unwrap(); let xen = Xen { xc, + xev, xen_fgn, dom_name: domain_name.to_string(), domid: cand_domid, + back_ring, }; debug!("Initialized {:#?}", xen); xen } - - fn close(&mut self) { - debug!("close"); - } } impl Introspectable for Xen { @@ -164,6 +183,86 @@ impl Introspectable for Xen { })) } + fn listen(&mut self, timeout: u32) -> Result, Box> { + let fd = self.xev.xenevtchn_fd()?; + let fd_struct = PollFd::new(fd, PollFlags::POLLIN | PollFlags::POLLERR); + let mut fds = [fd_struct]; + let mut vcpu: u16 = 0; + let mut event_type = unsafe { mem::MaybeUninit::::zeroed().assume_init() }; + let poll_result = poll(&mut fds, timeout.try_into().unwrap()).unwrap(); + let mut pending_event_port = -1; + if poll_result == 1 { + pending_event_port = self.xev.xenevtchn_pending()?; + if pending_event_port != -1 { + self.xev + .xenevtchn_unmask(pending_event_port.try_into().unwrap())?; + } + } + let back_ring_ptr = &mut self.back_ring; + let mut flag = false; + if poll_result > 0 + && self.xev.get_bind_port() == pending_event_port + && RING_HAS_UNCONSUMED_REQUESTS!(back_ring_ptr) != 0 + { + flag = true; + let req = self.xc.get_request(back_ring_ptr)?; + if req.version != VM_EVENT_INTERFACE_VERSION { + panic!("version mismatch"); + } + let xen_event_type = (self.xc.get_event_type(req)).unwrap(); + event_type = match xen_event_type { + XenEventType::Cr { cr_type, new, old } => EventType::Cr { + cr_type: match cr_type { + XenCr::Cr0 => CrType::Cr0, + XenCr::Cr3 => CrType::Cr3, + XenCr::Cr4 => CrType::Cr4, + }, + new, + old, + }, + _ => unimplemented!(), + }; + vcpu = req.vcpu_id.try_into().unwrap(); + let mut rsp = + unsafe { mem::MaybeUninit::::zeroed().assume_init() }; + rsp.reason = req.reason; + rsp.version = VM_EVENT_INTERFACE_VERSION; + rsp.vcpu_id = req.vcpu_id; + rsp.flags = req.flags & VM_EVENT_FLAG_VCPU_PAUSED; + self.xc.put_response(&mut rsp, &mut self.back_ring)?; + } + self.xev.xenevtchn_notify()?; + if flag { + Ok(Some(Event { + vcpu, + kind: event_type, + })) + } else { + Ok(None) + } + } + + fn toggle_intercept( + &mut self, + _vcpu: u16, + intercept_type: InterceptType, + enabled: bool, + ) -> Result<(), Box> { + match intercept_type { + InterceptType::Cr(micro_cr_type) => { + let xen_cr = match micro_cr_type { + CrType::Cr0 => XenCr::Cr0, + CrType::Cr3 => XenCr::Cr3, + CrType::Cr4 => XenCr::Cr4, + }; + Ok(self + .xc + .monitor_write_ctrlreg(self.domid, xen_cr, enabled, true, true)?) + } + _ => unimplemented!(), + } + } + fn pause(&mut self) -> Result<(), Box> { debug!("pause"); Ok(self.xc.domain_pause(self.domid)?) @@ -177,6 +276,9 @@ impl Introspectable for Xen { impl Drop for Xen { fn drop(&mut self) { - self.close(); + debug!("Closing Xen driver"); + self.xc + .monitor_disable(self.domid) + .expect("Failed to unmap event ring page"); } } From 8df7708b6d42b2156a50db0d797dc4496e9495af Mon Sep 17 00:00:00 2001 From: arnabcs17b006 Date: Fri, 14 Aug 2020 22:55:00 +0530 Subject: [PATCH 2/6] msr event support added --- Cargo.toml | 2 +- src/api.rs | 5 ++--- src/driver/kvm.rs | 3 +-- src/driver/xen.rs | 6 ++++++ 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 19a4d154..4fbc7d4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ hyper-v = ["winapi", "widestring", "ntapi", "vid-sys"] log = "0.4.8" env_logger = "0.7.1" libc = { version = "0.2.58", optional = true } -xenctrl = { git = "https://github.com/arnabcs17b006/xenctrl", branch = "write_register", optional = true } +xenctrl = { git = "https://github.com/arnabcs17b006/xenctrl", branch = "msr_events", optional = true } xenstore = { git = "https://github.com/Wenzel/xenstore", optional = true } xenforeignmemory = { git = "https://github.com/Wenzel/xenforeignmemory", optional = true } xenevtchn = { git = "https://github.com/arnabcs17b006/xenevtchn", branch = "event-notification"} diff --git a/src/api.rs b/src/api.rs index c7de2b13..ce42e816 100644 --- a/src/api.rs +++ b/src/api.rs @@ -274,6 +274,7 @@ pub enum InterceptType { #[repr(C)] #[derive(Debug)] pub enum EventType { +<<<<<<< HEAD ///Cr register interception Cr { ///Type of control register @@ -288,9 +289,7 @@ pub enum EventType { ///Type of model specific register msr_type: u32, /// new value after msr register has been intercepted by the guest. - new: u64, - /// old value before cr register has been intercepted by the guest. - old: u64, + value: u64, }, ///int3 interception Breakpoint { diff --git a/src/driver/kvm.rs b/src/driver/kvm.rs index 1229db33..f6a8f92e 100644 --- a/src/driver/kvm.rs +++ b/src/driver/kvm.rs @@ -250,8 +250,7 @@ impl Introspectable for Kvm { }, KVMiEventType::Msr { msr_type, new, old } => EventType::Msr { msr_type, - new, - old, + value, }, KVMiEventType::Breakpoint {gpa, insn_len } => EventType::Breakpoint { gpa, diff --git a/src/driver/xen.rs b/src/driver/xen.rs index fc8fa9e1..6173b1b6 100644 --- a/src/driver/xen.rs +++ b/src/driver/xen.rs @@ -220,6 +220,7 @@ impl Introspectable for Xen { new, old, }, + XenEventType::Msr { msr_type, value } => EventType::Msr { msr_type, value }, _ => unimplemented!(), }; vcpu = req.vcpu_id.try_into().unwrap(); @@ -259,6 +260,11 @@ impl Introspectable for Xen { .xc .monitor_write_ctrlreg(self.domid, xen_cr, enabled, true, true)?) } + InterceptType::Msr(micro_msr_type) => { + Ok(self + .xc + .monitor_mov_to_msr(self.domid, micro_msr_type, enabled)?) + } _ => unimplemented!(), } } From 4f1937e68bedc1366082f8c95c8faf9583a2e7fb Mon Sep 17 00:00:00 2001 From: arnabcs17b006 Date: Sat, 15 Aug 2020 00:11:09 +0530 Subject: [PATCH 3/6] breakpoint support added --- Cargo.toml | 2 +- src/api.rs | 1 - src/driver/xen.rs | 6 ++++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4fbc7d4b..30483bc6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ hyper-v = ["winapi", "widestring", "ntapi", "vid-sys"] log = "0.4.8" env_logger = "0.7.1" libc = { version = "0.2.58", optional = true } -xenctrl = { git = "https://github.com/arnabcs17b006/xenctrl", branch = "msr_events", optional = true } +xenctrl = { git = "https://github.com/arnabcs17b006/xenctrl", branch = "breakpoint", optional = true } xenstore = { git = "https://github.com/Wenzel/xenstore", optional = true } xenforeignmemory = { git = "https://github.com/Wenzel/xenforeignmemory", optional = true } xenevtchn = { git = "https://github.com/arnabcs17b006/xenevtchn", branch = "event-notification"} diff --git a/src/api.rs b/src/api.rs index ce42e816..1f9df9f5 100644 --- a/src/api.rs +++ b/src/api.rs @@ -274,7 +274,6 @@ pub enum InterceptType { #[repr(C)] #[derive(Debug)] pub enum EventType { -<<<<<<< HEAD ///Cr register interception Cr { ///Type of control register diff --git a/src/driver/xen.rs b/src/driver/xen.rs index 6173b1b6..33929201 100644 --- a/src/driver/xen.rs +++ b/src/driver/xen.rs @@ -221,6 +221,9 @@ impl Introspectable for Xen { old, }, XenEventType::Msr { msr_type, value } => EventType::Msr { msr_type, value }, + XenEventType::Breakpoint { gpa, insn_len } => { + EventType::Breakpoint { gpa, insn_len } + } _ => unimplemented!(), }; vcpu = req.vcpu_id.try_into().unwrap(); @@ -265,6 +268,9 @@ impl Introspectable for Xen { .xc .monitor_mov_to_msr(self.domid, micro_msr_type, enabled)?) } + InterceptType::Breakpoint => { + Ok(self.xc.monitor_software_breakpoint(self.domid, enabled)?) + } _ => unimplemented!(), } } From 535e45e5d10951e96fa139881f4cec0f06446fd4 Mon Sep 17 00:00:00 2001 From: arnabcs17b006 Date: Sun, 16 Aug 2020 20:00:57 +0530 Subject: [PATCH 4/6] pagefault event support added --- Cargo.toml | 3 +- examples/mem-events.rs | 104 +++++++++++++++++++++++++++++++++++++++++ src/api.rs | 25 ++++++++++ src/driver/kvm.rs | 2 +- src/driver/xen.rs | 64 ++++++++++++++++++++++--- src/lib.rs | 2 + 6 files changed, 192 insertions(+), 8 deletions(-) create mode 100644 examples/mem-events.rs diff --git a/Cargo.toml b/Cargo.toml index 30483bc6..c8dc3858 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ hyper-v = ["winapi", "widestring", "ntapi", "vid-sys"] log = "0.4.8" env_logger = "0.7.1" libc = { version = "0.2.58", optional = true } -xenctrl = { git = "https://github.com/arnabcs17b006/xenctrl", branch = "breakpoint", optional = true } +xenctrl = { git = "https://github.com/cs17b006/xenctrl", branch = "pagefault", optional = true } xenstore = { git = "https://github.com/Wenzel/xenstore", optional = true } xenforeignmemory = { git = "https://github.com/Wenzel/xenforeignmemory", optional = true } xenevtchn = { git = "https://github.com/arnabcs17b006/xenevtchn", branch = "event-notification"} @@ -42,6 +42,7 @@ ntapi = { version = "0.3.3", optional = true } vid-sys = { version = "0.3.0", features = ["deprecated-apis"], optional = true } cty = "0.2.1" nix = "0.18.0" +bitflags = "1.2.1" [dev-dependencies] ctrlc = "3.1.3" diff --git a/examples/mem-events.rs b/examples/mem-events.rs new file mode 100644 index 00000000..f11c4663 --- /dev/null +++ b/examples/mem-events.rs @@ -0,0 +1,104 @@ +use clap::{App, Arg, ArgMatches}; +use colored::*; +use env_logger; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::time::Instant; + +use microvmi::api::{ + Access, EventReplyType, EventType, InterceptType, Introspectable, PAGE_SHIFT, PAGE_SIZE, +}; + +fn parse_args() -> ArgMatches<'static> { + App::new(file!()) + .version("0.1") + .about("Watches memory VMI events") + .arg(Arg::with_name("vm_name").index(1).required(true)) + .get_matches() +} + +fn toggle_pf_intercept(drv: &mut Box, enabled: bool) { + drv.pause().expect("Failed to pause VM"); + + let intercept = InterceptType::Pagefault; + let status_str = if enabled { "Enabling" } else { "Disabling" }; + println!("{} memory events", status_str); + for vcpu in 0..1 { + drv.toggle_intercept(vcpu, intercept, enabled) + .expect(&format!("Failed to enable page faults")); + } + + drv.resume().expect("Failed to resume VM"); +} + +fn main() { + env_logger::init(); + + let matches = parse_args(); + + let domain_name = matches.value_of("vm_name").unwrap(); + + // set CTRL-C handler + let running = Arc::new(AtomicBool::new(true)); + let r = running.clone(); + ctrlc::set_handler(move || { + r.store(false, Ordering::SeqCst); + }) + .expect("Error setting Ctrl-C handler"); + + println!("Initialize Libmicrovmi"); + let mut drv: Box = microvmi::init(domain_name, None); + println!("Listen for memory events..."); + // record elapsed time + let start = Instant::now(); + toggle_pf_intercept(&mut drv, true); + let mut i: u64 = 0; + + //Code snippet to get page fault + let max_addr = drv.get_max_physical_addr().unwrap(); + //println!("max_gpfn: {}", max_addr>>PAGE_SHIFT); + for cur_addr in (0..max_addr).step_by(PAGE_SIZE as usize) { + let mut access: Access = drv.get_page_access(cur_addr).unwrap(); + access &= !Access::X; + drv.set_page_access(cur_addr, !Access::X) + .expect("failed to set page access"); + } + + while running.load(Ordering::SeqCst) { + let event = drv.listen(1000).expect("Failed to listen for events"); + match event { + Some(ev) => { + let (gva, gpa, pf_access) = match ev.kind { + EventType::Pagefault { gva, gpa, access } => (gva, gpa, access), + _ => panic!("Not pf event"), + }; + let ev_nb_output = format!("{}", i).cyan(); + let vcpu_output = format!("VCPU {}", ev.vcpu).yellow(); + let pagefault_output = format!("pagefault occurred!").color("blue"); + println!( + "[{}] {} - {}: gva = 0x{:x} gpa = 0x{:x} access = {:?} ", + ev_nb_output, vcpu_output, pagefault_output, gva, gpa, pf_access + ); + let mut page_access = drv.get_page_access(gpa).expect("Failed to get page access"); + //setting the access bits in the page due to which page fault occurred + page_access |= pf_access; + drv.set_page_access(gpa, Access::RWX) + .expect("Failed to set page access"); + //drv.reply_event(ev, EventReplyType::Continue) + // .expect("Failed to send event reply"); + i = i + 1; + } + None => println!("No events yet..."), + } + } + let duration = start.elapsed(); + toggle_pf_intercept(&mut drv, false); + + let ev_per_sec = i as f64 / duration.as_secs_f64(); + println!( + "Caught {} events in {:.2} seconds ({:.2} events/sec)", + i, + duration.as_secs_f64(), + ev_per_sec + ); +} diff --git a/src/api.rs b/src/api.rs index 1f9df9f5..7f3e928d 100644 --- a/src/api.rs +++ b/src/api.rs @@ -4,6 +4,20 @@ use std::ffi::{CStr, IntoStringError}; use crate::capi::DriverInitParamFFI; + +bitflags! { + pub struct Access: u32 { + const R=0b00000001; + const W=0b00000010; + const X=0b00000100; + const NIL=0b00000000; + const RW=Self::R.bits | Self::W.bits; + const WX=Self::W.bits | Self::X.bits; + const RX=Self::R.bits | Self::X.bits; + const RWX=Self::R.bits | Self::W.bits | Self::X.bits; + } +} + ///Represents the available hypervisor VMI drivers supported by libmicrovmi #[repr(C)] #[derive(Debug)] @@ -206,6 +220,16 @@ pub trait Introspectable { unimplemented!(); } + //get page access + fn get_page_access(&self, _paddr: u64) -> Result> { + unimplemented!(); + } + + //set page access + fn set_page_access(&self, _paddr: u64, _access: Access) -> Result<(), Box> { + unimplemented!(); + } + /// Used to pause the VM /// fn pause(&mut self) -> Result<(), Box> { @@ -268,6 +292,7 @@ pub enum InterceptType { Msr(u32), /// Intercept when guest requests an access to a page for which the requested type of access is not granted. For example , guest tries to write on a read only page. Breakpoint, + Pagefault, } /// Various types of events along with their relevant attributes being handled by this driver diff --git a/src/driver/kvm.rs b/src/driver/kvm.rs index f6a8f92e..49757942 100644 --- a/src/driver/kvm.rs +++ b/src/driver/kvm.rs @@ -250,7 +250,7 @@ impl Introspectable for Kvm { }, KVMiEventType::Msr { msr_type, new, old } => EventType::Msr { msr_type, - value, + value: new, }, KVMiEventType::Breakpoint {gpa, insn_len } => EventType::Breakpoint { gpa, diff --git a/src/driver/xen.rs b/src/driver/xen.rs index 33929201..78b7b643 100644 --- a/src/driver/xen.rs +++ b/src/driver/xen.rs @@ -1,9 +1,14 @@ -use std::error::Error; -use std::mem; - use crate::api::{ +<<<<<<< HEAD CrType, Event, EventType, InterceptType, Introspectable, Registers, SegmentReg, X86Registers, DriverInitParam, +======= + Access, CrType, Event, EventType, InterceptType, Introspectable, Registers, SegmentReg, + X86Registers, +>>>>>>> pagefault event support added }; +use std::convert::{From, TryFrom}; +use std::error::Error; +use std::mem; use libc::PROT_READ; use nix::poll::PollFlags; @@ -11,7 +16,7 @@ use nix::poll::{poll, PollFd}; use std::convert::TryInto; use xenctrl::consts::{PAGE_SHIFT, PAGE_SIZE}; use xenctrl::RING_HAS_UNCONSUMED_REQUESTS; -use xenctrl::{XenControl, XenCr, XenEventType}; +use xenctrl::{XenControl, XenCr, XenEventType, XenPageAccess}; use xenevtchn::XenEventChannel; use xenforeignmemory::XenForeignMem; use xenstore::{XBTransaction, Xs, XsOpenFlags}; @@ -19,6 +24,38 @@ use xenvmevent_sys::{ vm_event_back_ring, vm_event_response_t, VM_EVENT_FLAG_VCPU_PAUSED, VM_EVENT_INTERFACE_VERSION, }; +impl TryFrom for XenPageAccess { + type Error = &'static str; + fn try_from(access: Access) -> Result { + match access { + Access::NIL => Ok(XenPageAccess::NIL), + Access::R => Ok(XenPageAccess::R), + Access::W => Ok(XenPageAccess::W), + Access::RW => Ok(XenPageAccess::RW), + Access::X => Ok(XenPageAccess::X), + Access::RX => Ok(XenPageAccess::RX), + Access::WX => Ok(XenPageAccess::WX), + Access::RWX => Ok(XenPageAccess::RWX), + _ => Err("invalid access value"), + } + } +} + +impl From for Access { + fn from(access: XenPageAccess) -> Self { + match access { + XenPageAccess::NIL => Access::NIL, + XenPageAccess::R => Access::R, + XenPageAccess::W => Access::W, + XenPageAccess::RW => Access::RW, + XenPageAccess::X => Access::X, + XenPageAccess::RX => Access::RX, + XenPageAccess::WX => Access::WX, + XenPageAccess::RWX => Access::RWX, + } + } +} + #[derive(Debug)] pub struct Xen { xc: XenControl, @@ -224,7 +261,11 @@ impl Introspectable for Xen { XenEventType::Breakpoint { gpa, insn_len } => { EventType::Breakpoint { gpa, insn_len } } - _ => unimplemented!(), + XenEventType::Pagefault { gva, gpa, access } => EventType::Pagefault { + gva, + gpa, + access: access.into(), + }, }; vcpu = req.vcpu_id.try_into().unwrap(); let mut rsp = @@ -246,6 +287,17 @@ impl Introspectable for Xen { } } + fn get_page_access(&self, paddr: u64) -> Result> { + let access = self.xc.get_mem_access(self.domid, paddr >> PAGE_SHIFT)?; + Ok(access.into()) + } + + fn set_page_access(&self, paddr: u64, access: Access) -> Result<(), Box> { + Ok(self + .xc + .set_mem_access(self.domid, access.try_into().unwrap(), paddr >> PAGE_SHIFT)?) + } + fn toggle_intercept( &mut self, _vcpu: u16, @@ -271,7 +323,7 @@ impl Introspectable for Xen { InterceptType::Breakpoint => { Ok(self.xc.monitor_software_breakpoint(self.domid, enabled)?) } - _ => unimplemented!(), + InterceptType::Pagefault => Ok(()), } } diff --git a/src/lib.rs b/src/lib.rs index a3fe0978..1a93c4ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,8 @@ mod driver; #[macro_use] extern crate log; +#[macro_use] +extern crate bitflags; use api::Introspectable; use api::{DriverInitParam, DriverType}; From 960b97cb84c3b4bec96ae01bef43c4d4fc4fa6fb Mon Sep 17 00:00:00 2001 From: arnabcs17b006 Date: Tue, 18 Aug 2020 13:36:18 +0000 Subject: [PATCH 5/6] singlestep support added --- Cargo.toml | 3 +- examples/mem-events.rs | 8 ++- examples/msr-events.rs | 8 +-- examples/singlestep-events.rs | 96 +++++++++++++++++++++++++++ src/api.rs | 16 ++++- src/capi.rs | 119 +++++++++++++++++++++++++++++++++- src/driver/xen.rs | 10 ++- 7 files changed, 243 insertions(+), 17 deletions(-) create mode 100644 examples/singlestep-events.rs diff --git a/Cargo.toml b/Cargo.toml index c8dc3858..298aaf07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,13 +28,12 @@ hyper-v = ["winapi", "widestring", "ntapi", "vid-sys"] log = "0.4.8" env_logger = "0.7.1" libc = { version = "0.2.58", optional = true } -xenctrl = { git = "https://github.com/cs17b006/xenctrl", branch = "pagefault", optional = true } +xenctrl = { git = "https://github.com/arnabcs17b006/xenctrl", branch = "singlestep", optional = true } xenstore = { git = "https://github.com/Wenzel/xenstore", optional = true } xenforeignmemory = { git = "https://github.com/Wenzel/xenforeignmemory", optional = true } xenevtchn = { git = "https://github.com/arnabcs17b006/xenevtchn", branch = "event-notification"} xenvmevent-sys = { git = "https://github.com/Wenzel/xenvmevent-sys"} kvmi = { git = "https://github.com/Wenzel/kvmi", optional = true } ->>>>>>> event support for xen fdp = { git = "https://github.com/Wenzel/fdp", optional = true } winapi = { version = "0.3.8", features = ["tlhelp32", "winnt", "handleapi", "securitybaseapi"], optional = true } widestring = { version = "0.4.0", optional = true } diff --git a/examples/mem-events.rs b/examples/mem-events.rs index f11c4663..1e4f39e8 100644 --- a/examples/mem-events.rs +++ b/examples/mem-events.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use std::time::Instant; use microvmi::api::{ - Access, EventReplyType, EventType, InterceptType, Introspectable, PAGE_SHIFT, PAGE_SIZE, + Access, DriverInitParam, EventReplyType, EventType, InterceptType, Introspectable, PAGE_SIZE, }; fn parse_args() -> ArgMatches<'static> { @@ -38,6 +38,10 @@ fn main() { let domain_name = matches.value_of("vm_name").unwrap(); + let init_option = matches + .value_of("kvmi_socket") + .map(|socket| DriverInitParam::KVMiSocket(socket.into())); + // set CTRL-C handler let running = Arc::new(AtomicBool::new(true)); let r = running.clone(); @@ -47,7 +51,7 @@ fn main() { .expect("Error setting Ctrl-C handler"); println!("Initialize Libmicrovmi"); - let mut drv: Box = microvmi::init(domain_name, None); + let mut drv: Box = microvmi::init(domain_name, None, init_option); println!("Listen for memory events..."); // record elapsed time let start = Instant::now(); diff --git a/examples/msr-events.rs b/examples/msr-events.rs index d496cf6e..43beb667 100644 --- a/examples/msr-events.rs +++ b/examples/msr-events.rs @@ -109,8 +109,8 @@ fn main() { let event = drv.listen(1000).expect("Failed to listen for events"); match event { Some(ev) => { - let (msr_type, new, old) = match ev.kind { - EventType::Msr { msr_type, new, old } => (msr_type, new, old), + let (msr_type, value) = match ev.kind { + EventType::Msr { msr_type, value } => (msr_type, value), _ => panic!("not msr event"), }; let msr_color = "blue"; @@ -118,8 +118,8 @@ fn main() { let vcpu_output = format!("VCPU {}", ev.vcpu).yellow(); let msr_output = format!("0x{:x}", msr_type).color(msr_color); println!( - "[{}] {} - {}: old value: 0x{:x} new value: 0x{:x}", - ev_nb_output, vcpu_output, msr_output, old, new + "[{}] {} - {}: new value: 0x{:x}", + ev_nb_output, vcpu_output, msr_output, value, ); drv.reply_event(ev, EventReplyType::Continue) .expect("Failed to send event reply"); diff --git a/examples/singlestep-events.rs b/examples/singlestep-events.rs new file mode 100644 index 00000000..2d21fc36 --- /dev/null +++ b/examples/singlestep-events.rs @@ -0,0 +1,96 @@ +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::time::Instant; + +use clap::{App, Arg, ArgMatches}; +use colored::*; +use env_logger; + +use microvmi::api::*; + +fn parse_args() -> ArgMatches<'static> { + App::new(file!()) + .version("0.1") + .about("Watches singlestep VMI events") + .arg(Arg::with_name("vm_name").index(1).required(true)) + .get_matches() +} + +fn toggle_singlestep_interception(drv: &mut Box, enabled: bool) { + drv.pause().expect("Failed to pause VM"); + + let intercept = InterceptType::Singlestep; + let status_str = if enabled { "Enabling" } else { "Disabling" }; + println!("{} singlestep events", status_str); + for vcpu in 0..1 { + drv.toggle_intercept(vcpu, intercept, enabled) + .expect(&format!("Failed to enable singlestep")); + } + + drv.resume().expect("Failed to resume VM"); +} + +fn main() { + env_logger::init(); + + let matches = parse_args(); + + let domain_name = matches.value_of("vm_name").unwrap(); + + let init_option = matches + .value_of("kvmi_socket") + .map(|socket| DriverInitParam::KVMiSocket(socket.into())); + // set CTRL-C handler + let running = Arc::new(AtomicBool::new(true)); + let r = running.clone(); + ctrlc::set_handler(move || { + r.store(false, Ordering::SeqCst); + }) + .expect("Error setting Ctrl-C handler"); + + println!("Initialize Libmicrovmi"); + let mut drv: Box = microvmi::init(domain_name, None, init_option); + + //Enable singlestep interception + toggle_singlestep_interception(&mut drv, true); + + println!("Listen for singlestep events..."); + // record elapsed time + let start = Instant::now(); + // listen + let mut i: u64 = 0; + while running.load(Ordering::SeqCst) { + let event = drv.listen(1000).expect("Failed to listen for events"); + match event { + Some(ev) => { + let gpa = match ev.kind { + EventType::Singlestep { gpa } => (gpa), + _ => panic!("Not singlestep event"), + }; + let ev_nb_output = format!("{}", i).cyan(); + let vcpu_output = format!("VCPU {}", ev.vcpu).yellow(); + let singlestep_output = format!("singlestep occurred!").color("blue"); + println!( + "[{}] {} - {}: gpa = 0x{:x} ", + ev_nb_output, vcpu_output, singlestep_output, gpa + ); + //drv.reply_event(ev, EventReplyType::Continue) + // .expect("Failed to send event reply"); + i = i + 1; + } + None => println!("No events yet..."), + } + } + let duration = start.elapsed(); + + //disable singlestep interception + toggle_singlestep_interception(&mut drv, false); + + let ev_per_sec = i as f64 / duration.as_secs_f64(); + println!( + "Caught {} events in {:.2} seconds ({:.2} events/sec)", + i, + duration.as_secs_f64(), + ev_per_sec + ); +} diff --git a/src/api.rs b/src/api.rs index 7f3e928d..4e6b41d5 100644 --- a/src/api.rs +++ b/src/api.rs @@ -4,7 +4,6 @@ use std::ffi::{CStr, IntoStringError}; use crate::capi::DriverInitParamFFI; - bitflags! { pub struct Access: u32 { const R=0b00000001; @@ -293,6 +292,7 @@ pub enum InterceptType { /// Intercept when guest requests an access to a page for which the requested type of access is not granted. For example , guest tries to write on a read only page. Breakpoint, Pagefault, + Singlestep, } /// Various types of events along with their relevant attributes being handled by this driver @@ -322,6 +322,20 @@ pub enum EventType { /// instruction length. Generally it should be one. Anything other than one implies malicious guest. insn_len: u8, }, + ///Pagefault interception + Pagefault { + /// Virtual memory address of the guest + gva: u64, + /// Physical memory address of the guest + gpa: u64, + /// Acsess responsible for thr pagefault + access: Access, + }, + ///Singlestep event + Singlestep { + ///Physical memory address of the guest + gpa: u64, + }, } ///Types of x86 control registers are listed here diff --git a/src/capi.rs b/src/capi.rs index 4caac4ac..3c03b040 100644 --- a/src/capi.rs +++ b/src/capi.rs @@ -1,6 +1,9 @@ -use crate::api::{DriverInitParam, DriverType, Introspectable, Registers}; +use crate::api::{ + Access, DriverInitParam, DriverType, Event, EventReplyType, InterceptType, Introspectable, + Registers, +}; use crate::init; -use cty::{c_char, size_t, uint16_t, uint64_t, uint8_t}; +use cty::{c_char, size_t, uint16_t, uint32_t, uint64_t, uint8_t}; use std::convert::TryInto; use std::ffi::{c_void, CStr}; use std::slice; @@ -82,6 +85,20 @@ pub unsafe extern "C" fn microvmi_read_physical( .is_ok() } +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn microvmi_write_physical( + context: *mut c_void, + physical_address: uint64_t, + buffer: *mut uint8_t, + size: size_t, +) -> bool { + let driver = get_driver_mut_ptr(context); + (*driver) + .write_physical(physical_address, slice::from_raw_parts_mut(buffer, size)) + .is_ok() +} + #[allow(clippy::missing_safety_doc)] #[no_mangle] pub unsafe extern "C" fn microvmi_get_max_physical_addr( @@ -115,6 +132,104 @@ pub unsafe extern "C" fn microvmi_read_registers( } } +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn microvmi_write_registers( + context: *mut c_void, + vcpu: uint16_t, + registers: Registers, +) -> bool { + let driver = get_driver_mut_ptr(context); + (*driver).write_registers(vcpu, registers).is_ok() +} + +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn microvmi_get_page_access( + context: *mut c_void, + paddr: uint64_t, + access: *mut Access, +) -> bool { + let driver = get_driver_mut_ptr(context); + match (*driver).get_page_access(paddr) { + Ok(flags) => { + access.write(flags); + true + } + Err(_) => false, + } +} + +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn microvmi_set_page_access( + context: *mut c_void, + paddr: uint64_t, + access: Access, +) -> bool { + let driver = get_driver_mut_ptr(context); + (*driver).set_page_access(paddr, access).is_ok() +} + +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn microvmi_toggle_intercept( + context: *mut c_void, + vcpu: uint16_t, + intercept_type: InterceptType, + enabled: bool, +) -> bool { + let driver = get_driver_mut_ptr(context); + (*driver) + .toggle_intercept(vcpu, intercept_type, enabled) + .is_ok() +} + +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn microvmi_listen( + context: *mut c_void, + timeout: uint32_t, + event_ptr: *mut Event, +) -> bool { + let driver = get_driver_mut_ptr(context); + match (*driver).listen(timeout) { + Ok(Some(event)) => { + event_ptr.write(event); + true + } + Ok(None) => true, + Err(_) => false, + } +} + +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn microvmi_reply_event( + context: *mut c_void, + event: Event, + reply_type: EventReplyType, +) -> bool { + let driver = get_driver_mut_ptr(context); + (*driver).reply_event(event, reply_type).is_ok() +} + +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn microvmi_get_vcpu_count( + context: *mut c_void, + vcpu_ptr: *mut uint16_t, +) -> bool { + let driver = get_driver_mut_ptr(context); + match (*driver).get_vcpu_count() { + Ok(vcpu_count) => { + vcpu_ptr.write(vcpu_count); + true + } + Err(_) => false, + } +} + unsafe fn get_driver_mut_ptr(context: *mut c_void) -> *mut dyn Introspectable { let driver: *mut *mut dyn Introspectable = context as *mut _; driver.read() diff --git a/src/driver/xen.rs b/src/driver/xen.rs index 78b7b643..a159cdaf 100644 --- a/src/driver/xen.rs +++ b/src/driver/xen.rs @@ -1,10 +1,6 @@ use crate::api::{ -<<<<<<< HEAD - CrType, Event, EventType, InterceptType, Introspectable, Registers, SegmentReg, X86Registers, DriverInitParam, -======= - Access, CrType, Event, EventType, InterceptType, Introspectable, Registers, SegmentReg, - X86Registers, ->>>>>>> pagefault event support added + Access, CrType, DriverInitParam, Event, EventType, InterceptType, Introspectable, Registers, + SegmentReg, X86Registers, }; use std::convert::{From, TryFrom}; use std::error::Error; @@ -266,6 +262,7 @@ impl Introspectable for Xen { gpa, access: access.into(), }, + XenEventType::Singlestep { gpa } => EventType::Singlestep { gpa }, }; vcpu = req.vcpu_id.try_into().unwrap(); let mut rsp = @@ -324,6 +321,7 @@ impl Introspectable for Xen { Ok(self.xc.monitor_software_breakpoint(self.domid, enabled)?) } InterceptType::Pagefault => Ok(()), + InterceptType::Singlestep => Ok(self.xc.monitor_singlestep(self.domid, enabled)?), } } From 78db587f6321344723f141dccec4bdced54ca0fa Mon Sep 17 00:00:00 2001 From: arnabcs17b006 Date: Thu, 20 Aug 2020 02:57:50 +0530 Subject: [PATCH 6/6] c examples for various events added --- .vscode/settings.json | 5 +++ c_examples/Makefile | 16 +++++++- c_examples/cr-events.c | 69 ++++++++++++++++++++++++++++++++++ c_examples/interrupt-events.c | 43 +++++++++++++++++++++ c_examples/msr-events.c | 42 +++++++++++++++++++++ c_examples/regs-dump.c | 47 +++++++++++++++++++++++ c_examples/singlestep-events.c | 42 +++++++++++++++++++++ examples/cr-events.rs | 2 +- examples/interrupt-events.rs | 2 +- examples/mem-events.rs | 2 +- examples/msr-events.rs | 2 +- examples/singlestep-events.rs | 2 +- src/api.rs | 15 ++++---- src/capi.rs | 4 +- src/driver/kvm.rs | 6 +-- src/driver/xen.rs | 10 ++--- 16 files changed, 285 insertions(+), 24 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 c_examples/cr-events.c create mode 100644 c_examples/interrupt-events.c create mode 100644 c_examples/msr-events.c create mode 100644 c_examples/singlestep-events.c diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..14004e0e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "type_traits": "c" + } +} \ No newline at end of file diff --git a/c_examples/Makefile b/c_examples/Makefile index 728dde05..9554b95c 100644 --- a/c_examples/Makefile +++ b/c_examples/Makefile @@ -5,7 +5,7 @@ CWD := $(shell pwd) .PHONY: all clean -all: mem-dump pause regs-dump +all: mem-dump pause regs-dump cr-events msr-events interrupt-events singlestep-events libmicrovmi.h: ../target/debug/libmicrovmi.so cd ..; \ @@ -20,5 +20,17 @@ pause: libmicrovmi.h pause.c regs-dump: libmicrovmi.h regs-dump.c $(CC) $(CFLAGS) regs-dump.c -o $@ $(LDFLAGS) +cr-events: libmicrovmi.h cr-events.c + $(CC) $(CFLAGS) cr-events.c -o $@ $(LDFLAGS) + +msr-events: libmicrovmi.h msr-events.c + $(CC) $(CFLAGS) msr-events.c -o $@ $(LDFLAGS) + +interrupt-events: libmicrovmi.h interrupt-events.c + $(CC) $(CFLAGS) interrupt-events.c -o $@ $(LDFLAGS) + +singlestep-events: libmicrovmi.h singlestep-events.c + $(CC) $(CFLAGS) singlestep-events.c -o $@ $(LDFLAGS) + clean: - rm -f libmicrovmi.h mem-dump pause regs-dump + rm -f libmicrovmi.h mem-dump pause regs-dump cr-events msr-events interrupt-events singlestep-events diff --git a/c_examples/cr-events.c b/c_examples/cr-events.c new file mode 100644 index 00000000..a2474e19 --- /dev/null +++ b/c_examples/cr-events.c @@ -0,0 +1,69 @@ +#include +#include +#include + +#include "libmicrovmi.h" + +bool display_cr(int index) +{ + switch (index) + { + case 0: + printf("Cr0 "); + return true; + case 1: + printf("Cr3 "); + return true; + case 2: + printf("Cr4 "); + return true; + default: + break; + } + return false; +} + +int main(int argc, char* argv[]) { + if (argc < 2) { + printf("No domain name given.\n"); + return 1; + } + microvmi_envlogger_init(); + void* driver = microvmi_init(argv[1], NULL, NULL); + InterceptType intercept = { .tag = Cr, .cr = {._0 = Cr3} }; + for(uint16_t vcpu =0; vcpu<2;vcpu++) + microvmi_toggle_intercept(driver, vcpu, intercept, true); + while(true) + { + Event ev; + if(microvmi_listen(driver, 1000, &ev)==true) + { + switch(ev.kind.tag) + { + case CrEvents: + + if(display_cr(ev.kind.cr_events.cr_type)==true) + { + printf("vcpu: %d ", ev.vcpu); + printf("old value: 0x%" PRIx64 " ", ev.kind.cr_events.old); + printf("new value: 0x%" PRIx64 "\n", ev.kind.cr_events.new_); + } + else + { + printf("No Events..\n"); + } + + break; + default: + printf("No Events..\n"); + } + } + else + { + printf("No events..\n"); + } + + } + microvmi_destroy(driver); + return 0; +} diff --git a/c_examples/interrupt-events.c b/c_examples/interrupt-events.c new file mode 100644 index 00000000..62d4423a --- /dev/null +++ b/c_examples/interrupt-events.c @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "libmicrovmi.h" + + +int main(int argc, char* argv[]) { + if (argc < 2) { + printf("No domain name given.\n"); + return 1; + } + microvmi_envlogger_init(); + void* driver = microvmi_init(argv[1], NULL, NULL); + InterceptType intercept = { .tag = Breakpoint}; + for(uint16_t vcpu =0; vcpu<2;vcpu++) + microvmi_toggle_intercept(driver, vcpu, intercept, true); + while(true) + { + Event ev; + if(microvmi_listen(driver, 1000, &ev)==true) + { + switch(ev.kind.tag) + { + case BreakpointEvents: + printf("vcpu: %d ", ev.vcpu); + printf("Breakpoint detected!! "); + printf("gpa: 0x%" PRIx64 ": ", ev.kind.breakpoint_events.gpa); + printf("insn_len: 0x%" PRIx16 "\n", ev.kind.breakpoint_events.insn_len); + break; + default: + printf("No Events..\n"); + } + } + else + { + printf("No events..\n"); + } + + } + microvmi_destroy(driver); + return 0; +} diff --git a/c_examples/msr-events.c b/c_examples/msr-events.c new file mode 100644 index 00000000..e6b7c4e4 --- /dev/null +++ b/c_examples/msr-events.c @@ -0,0 +1,42 @@ +#include +#include +#include + +#include "libmicrovmi.h" + + +int main(int argc, char* argv[]) { + if (argc < 2) { + printf("No domain name given.\n"); + return 1; + } + microvmi_envlogger_init(); + void* driver = microvmi_init(argv[1], NULL, NULL); + InterceptType intercept = { .tag = Msr, .msr = {._0 = (uint32_t)0xc0000080} }; + for(uint16_t vcpu =0; vcpu<2;vcpu++) + microvmi_toggle_intercept(driver, vcpu, intercept, true); + while(true) + { + Event ev; + if(microvmi_listen(driver, 1000, &ev)==true) + { + switch(ev.kind.tag) + { + case MsrEvents: + printf("vcpu: %d ", ev.vcpu); + printf("msr index: 0x%" PRIx32 ": ", ev.kind.msr_events.msr_type); + printf("old value: 0x%" PRIx64 "\n", ev.kind.msr_events.value); + break; + default: + printf("No Events..\n"); + } + } + else + { + printf("No events..\n"); + } + + } + microvmi_destroy(driver); + return 0; +} diff --git a/c_examples/regs-dump.c b/c_examples/regs-dump.c index 602c1265..63ff7916 100644 --- a/c_examples/regs-dump.c +++ b/c_examples/regs-dump.c @@ -4,6 +4,13 @@ #include "libmicrovmi.h" + +void display_segment_register(SegmentReg segment) +{ + printf("base: 0x%" PRIx64 "\n", segment.base); + printf("base: 0x%" PRIx32 "\n", segment.limit); + printf("base: 0x%" PRIx16 "\n", segment.selector); +} void read_registers(void* driver, const char* vm_name) { if (microvmi_pause(driver)) { printf("Paused.\n"); @@ -24,7 +31,47 @@ void read_registers(void* driver, const char* vm_name) { printf("rbp: 0x%" PRIx64 "\n", regs.x86._0.rbp); printf("rip: 0x%" PRIx64 "\n", regs.x86._0.rip); printf("rflags: 0x%" PRIx64 "\n", regs.x86._0.rflags); + printf("r8: 0x%" PRIx64 "\n", regs.x86._0.r8); + printf("r9: 0x%" PRIx64 "\n", regs.x86._0.r9); + printf("r10: 0x%" PRIx64 "\n", regs.x86._0.r10); + printf("r11: 0x%" PRIx64 "\n", regs.x86._0.r11); + printf("r12: 0x%" PRIx64 "\n", regs.x86._0.r12); + printf("r13: 0x%" PRIx64 "\n", regs.x86._0.r13); + printf("r14: 0x%" PRIx64 "\n", regs.x86._0.r14); + printf("r15: 0x%" PRIx64 "\n", regs.x86._0.r15); + printf("cr0: 0x%" PRIx64 "\n", regs.x86._0.cr0); + printf("cr2: 0x%" PRIx64 "\n", regs.x86._0.cr2); printf("cr3: 0x%" PRIx64 "\n", regs.x86._0.cr3); + printf("sysenter_cs: 0x%" PRIx64 "\n", regs.x86._0.sysenter_cs); + printf("sysenter_esp: 0x%" PRIx64 "\n", regs.x86._0.sysenter_esp); + printf("sysenter_eip: 0x%" PRIx64 "\n", regs.x86._0.sysenter_eip); + printf("msr_star: 0x%" PRIx64 "\n", regs.x86._0.msr_star); + printf("msr_lstar: 0x%" PRIx64 "\n", regs.x86._0.msr_lstar); + printf("msr_efer: 0x%" PRIx64 "\n", regs.x86._0.msr_efer); + printf("cs {\n"); + display_segment_register(regs.x86._0.cs); + printf("}\n"); + printf("ds {\n"); + display_segment_register(regs.x86._0.ds); + printf("}\n"); + printf("es {\n"); + display_segment_register(regs.x86._0.es); + printf("}\n"); + printf("fs {\n"); + display_segment_register(regs.x86._0.fs); + printf("}\n"); + printf("gs {\n"); + display_segment_register(regs.x86._0.gs); + printf("}\n"); + printf("ss {\n"); + display_segment_register(regs.x86._0.ss); + printf("}\n"); + printf("tr {\n"); + display_segment_register(regs.x86._0.tr); + printf("}\n"); + printf("ldt {\n"); + display_segment_register(regs.x86._0.ldt); + printf("}\n"); } else { printf("Unable to read registers.\n"); } diff --git a/c_examples/singlestep-events.c b/c_examples/singlestep-events.c new file mode 100644 index 00000000..63a36221 --- /dev/null +++ b/c_examples/singlestep-events.c @@ -0,0 +1,42 @@ +#include +#include +#include + +#include "libmicrovmi.h" + + +int main(int argc, char* argv[]) { + if (argc < 2) { + printf("No domain name given.\n"); + return 1; + } + microvmi_envlogger_init(); + void* driver = microvmi_init(argv[1], NULL, NULL); + InterceptType intercept = { .tag = Breakpoint}; + for(uint16_t vcpu =0; vcpu<2;vcpu++) + microvmi_toggle_intercept(driver, vcpu, intercept, true); + while(true) + { + Event ev; + if(microvmi_listen(driver, 1000, &ev)==true) + { + switch(ev.kind.tag) + { + case SinglestepEvents: + printf("vcpu: %d ", ev.vcpu); + printf("Breakpoint detected!! "); + printf("gpa: 0x%" PRIx64 ": ", ev.kind.singlestep_events.gpa); + break; + default: + printf("No Events..\n"); + } + } + else + { + printf("No events..\n"); + } + + } + microvmi_destroy(driver); + return 0; +} diff --git a/examples/cr-events.rs b/examples/cr-events.rs index 4810748f..e5ac592d 100644 --- a/examples/cr-events.rs +++ b/examples/cr-events.rs @@ -106,7 +106,7 @@ fn main() { match event { Some(ev) => { let (cr_type, new, old) = match ev.kind { - EventType::Cr { cr_type, new, old } => (cr_type, new, old), + EventType::CrEvents { cr_type, new, old } => (cr_type, new, old), _ => panic!("not cr event"), }; let cr_color = match cr_type { diff --git a/examples/interrupt-events.rs b/examples/interrupt-events.rs index 4d8d150b..eb38d8e8 100644 --- a/examples/interrupt-events.rs +++ b/examples/interrupt-events.rs @@ -72,7 +72,7 @@ fn main() { match event { Some(ev) => { let (gpa, insn_len) = match ev.kind { - EventType::Breakpoint { gpa, insn_len } => (gpa, insn_len), + EventType::BreakpointEvents { gpa, insn_len } => (gpa, insn_len), _ => panic!("Not interrupt event"), }; let ev_nb_output = format!("{}", i).cyan(); diff --git a/examples/mem-events.rs b/examples/mem-events.rs index 1e4f39e8..f530a63d 100644 --- a/examples/mem-events.rs +++ b/examples/mem-events.rs @@ -73,7 +73,7 @@ fn main() { match event { Some(ev) => { let (gva, gpa, pf_access) = match ev.kind { - EventType::Pagefault { gva, gpa, access } => (gva, gpa, access), + EventType::PagefaultEvents { gva, gpa, access } => (gva, gpa, access), _ => panic!("Not pf event"), }; let ev_nb_output = format!("{}", i).cyan(); diff --git a/examples/msr-events.rs b/examples/msr-events.rs index 43beb667..12ea2426 100644 --- a/examples/msr-events.rs +++ b/examples/msr-events.rs @@ -110,7 +110,7 @@ fn main() { match event { Some(ev) => { let (msr_type, value) = match ev.kind { - EventType::Msr { msr_type, value } => (msr_type, value), + EventType::MsrEvents { msr_type, value } => (msr_type, value), _ => panic!("not msr event"), }; let msr_color = "blue"; diff --git a/examples/singlestep-events.rs b/examples/singlestep-events.rs index 2d21fc36..d1496efb 100644 --- a/examples/singlestep-events.rs +++ b/examples/singlestep-events.rs @@ -64,7 +64,7 @@ fn main() { match event { Some(ev) => { let gpa = match ev.kind { - EventType::Singlestep { gpa } => (gpa), + EventType::SinglestepEvents { gpa } => (gpa), _ => panic!("Not singlestep event"), }; let ev_nb_output = format!("{}", i).cyan(); diff --git a/src/api.rs b/src/api.rs index 4e6b41d5..88f98e72 100644 --- a/src/api.rs +++ b/src/api.rs @@ -5,6 +5,7 @@ use std::ffi::{CStr, IntoStringError}; use crate::capi::DriverInitParamFFI; bitflags! { + #[repr(C)] pub struct Access: u32 { const R=0b00000001; const W=0b00000010; @@ -300,7 +301,7 @@ pub enum InterceptType { #[derive(Debug)] pub enum EventType { ///Cr register interception - Cr { + CrEvents { ///Type of control register cr_type: CrType, /// new value after cr register has been intercepted by the guest. @@ -309,30 +310,30 @@ pub enum EventType { old: u64, }, ///Msr register interception - Msr { + MsrEvents { ///Type of model specific register msr_type: u32, /// new value after msr register has been intercepted by the guest. value: u64, }, ///int3 interception - Breakpoint { + BreakpointEvents { /// Physical memory address of the guest gpa: u64, /// instruction length. Generally it should be one. Anything other than one implies malicious guest. insn_len: u8, }, ///Pagefault interception - Pagefault { + PagefaultEvents { /// Virtual memory address of the guest gva: u64, /// Physical memory address of the guest gpa: u64, - /// Acsess responsible for thr pagefault - access: Access, + //Acsess responsible for thr pagefault + //access: Access, }, ///Singlestep event - Singlestep { + SinglestepEvents { ///Physical memory address of the guest gpa: u64, }, diff --git a/src/capi.rs b/src/capi.rs index 3c03b040..d527f123 100644 --- a/src/capi.rs +++ b/src/capi.rs @@ -143,7 +143,7 @@ pub unsafe extern "C" fn microvmi_write_registers( (*driver).write_registers(vcpu, registers).is_ok() } -#[allow(clippy::missing_safety_doc)] +/*#[allow(clippy::missing_safety_doc)] #[no_mangle] pub unsafe extern "C" fn microvmi_get_page_access( context: *mut c_void, @@ -169,7 +169,7 @@ pub unsafe extern "C" fn microvmi_set_page_access( ) -> bool { let driver = get_driver_mut_ptr(context); (*driver).set_page_access(paddr, access).is_ok() -} +}*/ #[allow(clippy::missing_safety_doc)] #[no_mangle] diff --git a/src/driver/kvm.rs b/src/driver/kvm.rs index 49757942..40eabf6a 100644 --- a/src/driver/kvm.rs +++ b/src/driver/kvm.rs @@ -239,7 +239,7 @@ impl Introspectable for Kvm { None => Ok(None), Some(kvmi_event) => { let microvmi_event_kind = match kvmi_event.ev_type { - KVMiEventType::Cr { cr_type, new, old } => EventType::Cr { + KVMiEventType::Cr { cr_type, new, old } => EventType::CrEvents { cr_type: match cr_type { KVMiCr::Cr0 => CrType::Cr0, KVMiCr::Cr3 => CrType::Cr3, @@ -248,11 +248,11 @@ impl Introspectable for Kvm { new, old, }, - KVMiEventType::Msr { msr_type, new, old } => EventType::Msr { + KVMiEventType::Msr { msr_type, new, old } => EventType::MsrEvents { msr_type, value: new, }, - KVMiEventType::Breakpoint {gpa, insn_len } => EventType::Breakpoint { + KVMiEventType::Breakpoint {gpa, insn_len } => EventType::BreakpointEvents { gpa, insn_len, }, diff --git a/src/driver/xen.rs b/src/driver/xen.rs index a159cdaf..f5df2bea 100644 --- a/src/driver/xen.rs +++ b/src/driver/xen.rs @@ -244,7 +244,7 @@ impl Introspectable for Xen { } let xen_event_type = (self.xc.get_event_type(req)).unwrap(); event_type = match xen_event_type { - XenEventType::Cr { cr_type, new, old } => EventType::Cr { + XenEventType::Cr { cr_type, new, old } => EventType::CrEvents { cr_type: match cr_type { XenCr::Cr0 => CrType::Cr0, XenCr::Cr3 => CrType::Cr3, @@ -253,16 +253,16 @@ impl Introspectable for Xen { new, old, }, - XenEventType::Msr { msr_type, value } => EventType::Msr { msr_type, value }, + XenEventType::Msr { msr_type, value } => EventType::MsrEvents { msr_type, value }, XenEventType::Breakpoint { gpa, insn_len } => { - EventType::Breakpoint { gpa, insn_len } + EventType::BreakpointEvents { gpa, insn_len } } - XenEventType::Pagefault { gva, gpa, access } => EventType::Pagefault { + XenEventType::Pagefault { gva, gpa, access } => EventType::PagefaultEvents { gva, gpa, access: access.into(), }, - XenEventType::Singlestep { gpa } => EventType::Singlestep { gpa }, + XenEventType::Singlestep { gpa } => EventType::SinglestepEvents { gpa }, }; vcpu = req.vcpu_id.try_into().unwrap(); let mut rsp =