diff --git a/Cargo.toml b/Cargo.toml index 1f2dfbcd..c2f22c70 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/arnabcs17b006/xenctrl", branch = "pagefault", optional = true } xenstore = { git = "https://github.com/Wenzel/xenstore", optional = true } xenforeignmemory = { git = "https://github.com/Wenzel/xenforeignmemory", optional = true } kvmi = { version = "0.2.1", optional = true } diff --git a/examples/mem-events.rs b/examples/mem-events.rs index 30cd926a..647f89d9 100644 --- a/examples/mem-events.rs +++ b/examples/mem-events.rs @@ -6,11 +6,9 @@ use std::sync::Arc; use std::time::Instant; use microvmi::api::{ - Access, DriverInitParam, EventReplyType, EventType, InterceptType, Introspectable, + Access, DriverInitParam, EventReplyType, EventType, InterceptType, Introspectable, PAGE_SIZE, }; -const PAGE_SIZE: usize = 4096; - fn parse_args() -> ArgMatches<'static> { App::new(file!()) .version("0.1") @@ -25,7 +23,7 @@ fn toggle_pf_intercept(drv: &mut Box, enabled: bool) { let intercept = InterceptType::Pagefault; let status_str = if enabled { "Enabling" } else { "Disabling" }; println!("{} memory events", status_str); - for vcpu in 0..drv.get_vcpu_count().unwrap() { + for vcpu in 0..1 { drv.toggle_intercept(vcpu, intercept, enabled) .expect(&format!("Failed to enable page faults")); } @@ -39,7 +37,6 @@ fn main() { 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(); @@ -61,11 +58,11 @@ fn main() { //Code snippet to get page fault let max_addr = drv.get_max_physical_addr().unwrap(); - - for cur_addr in (0..max_addr).step_by(PAGE_SIZE) { + //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) + drv.set_page_access(cur_addr, !Access::X) .expect("failed to set page access"); } @@ -87,10 +84,10 @@ fn main() { 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, page_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"); + //drv.reply_event(ev, EventReplyType::Continue) + // .expect("Failed to send event reply"); i = i + 1; } None => println!("No events yet..."), 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/src/api.rs b/src/api.rs index d6f23643..bac73863 100644 --- a/src/api.rs +++ b/src/api.rs @@ -335,7 +335,6 @@ pub enum EventType { msr_type: u32, /// new value after msr register has been intercepted by the guest. value: u64, - }, ///int3 interception Breakpoint { @@ -344,6 +343,7 @@ 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, diff --git a/src/driver/kvm.rs b/src/driver/kvm.rs index 30225f1c..d99c4c12 100644 --- a/src/driver/kvm.rs +++ b/src/driver/kvm.rs @@ -309,9 +309,9 @@ impl Introspectable for Kvm { new, old, }, - KVMiEventType::Msr { msr_type, new, old } => EventType::Msr { + 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 899e0ced..4efb8593 100644 --- a/src/driver/xen.rs +++ b/src/driver/xen.rs @@ -1,21 +1,17 @@ use crate::api::{ - DriverInitParam, Introspectable, Registers, SegmentReg, SystemTableReg, X86Registers, + Access, CrType, DriverInitParam, Event, EventType, InterceptType, Introspectable, Registers, + SegmentReg, SystemTableReg, X86Registers, }; use libc::{PROT_READ, PROT_WRITE}; -use std::error::Error; -use std::mem; - -use crate::api::{ - CrType, Event, EventType, InterceptType, Introspectable, Registers, SegmentReg, X86Registers, -}; - -use libc::PROT_READ; use nix::poll::PollFlags; use nix::poll::{poll, PollFd}; use std::convert::TryInto; +use std::convert::{From, TryFrom}; +use std::error::Error; +use std::mem; 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}; @@ -23,6 +19,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, @@ -267,7 +295,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 = @@ -289,6 +321,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, @@ -314,7 +357,7 @@ impl Introspectable for Xen { InterceptType::Breakpoint => { Ok(self.xc.monitor_software_breakpoint(self.domid, enabled)?) } - _ => unimplemented!(), + InterceptType::Pagefault => Ok(()), } }