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/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)?), } }