Skip to content

Commit

Permalink
pagefault event support added
Browse files Browse the repository at this point in the history
  • Loading branch information
arnabcs17b006 committed Aug 18, 2020
1 parent d635e05 commit 6c0cd3f
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 6 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
Expand All @@ -41,6 +41,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"
Expand Down
104 changes: 104 additions & 0 deletions examples/mem-events.rs
Original file line number Diff line number Diff line change
@@ -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<dyn Introspectable>, 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<dyn Introspectable> = 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
);
}
25 changes: 25 additions & 0 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,22 @@ use std::convert::TryInto;
use std::error::Error;
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)]
Expand Down Expand Up @@ -206,6 +220,16 @@ pub trait Introspectable {
unimplemented!();
}

//get page access
fn get_page_access(&self, _paddr: u64) -> Result<Access, Box<dyn Error>> {
unimplemented!();
}

//set page access
fn set_page_access(&self, _paddr: u64, _access: Access) -> Result<(), Box<dyn Error>> {
unimplemented!();
}

/// Used to pause the VM
///
fn pause(&mut self) -> Result<(), Box<dyn Error>> {
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/driver/kvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ impl<T: KVMIntrospectable> Introspectable for Kvm<T> {
},
KVMiEventType::Msr { msr_type, new, old } => EventType::Msr {
msr_type,
value,
value: new,
},
KVMiEventType::Breakpoint {gpa, insn_len } => EventType::Breakpoint {
gpa,
Expand Down
62 changes: 58 additions & 4 deletions src/driver/xen.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,65 @@
<<<<<<< HEAD
use crate::api::{DriverInitParam, Introspectable, Registers, SegmentReg, X86Registers};
use libc::PROT_READ;
use std::error::Error;
use std::mem;

=======
>>>>>>> pagefault event support added
use crate::api::{
CrType, Event, EventType, InterceptType, Introspectable, Registers, SegmentReg, X86Registers,
Access, CrType, Event, EventType, InterceptType, Introspectable, Registers, SegmentReg,
X86Registers,
};
use std::convert::{From, TryFrom};
use std::error::Error;
use std::mem;

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::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};
use xenvmevent_sys::{
vm_event_back_ring, vm_event_response_t, VM_EVENT_FLAG_VCPU_PAUSED, VM_EVENT_INTERFACE_VERSION,
};

impl TryFrom<Access> for XenPageAccess {
type Error = &'static str;
fn try_from(access: Access) -> Result<Self, Self::Error> {
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<XenPageAccess> 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,
Expand Down Expand Up @@ -226,7 +265,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 =
Expand All @@ -248,6 +291,17 @@ impl Introspectable for Xen {
}
}

fn get_page_access(&self, paddr: u64) -> Result<Access, Box<dyn Error>> {
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<dyn Error>> {
Ok(self
.xc
.set_mem_access(self.domid, access.try_into().unwrap(), paddr >> PAGE_SHIFT)?)
}

fn toggle_intercept(
&mut self,
_vcpu: u16,
Expand All @@ -273,7 +327,7 @@ impl Introspectable for Xen {
InterceptType::Breakpoint => {
Ok(self.xc.monitor_software_breakpoint(self.domid, enabled)?)
}
_ => unimplemented!(),
InterceptType::Pagefault => Ok(()),
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ mod driver;

#[macro_use]
extern crate log;
#[macro_use]
extern crate bitflags;

use api::Introspectable;
use api::{DriverInitParam, DriverType};
Expand Down

0 comments on commit 6c0cd3f

Please sign in to comment.