Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ crate-type = ["cdylib", "lib"]

[features]
# Xen driver
xen = ["xenctrl", "xenstore", "xenforeignmemory", "libc"]
xen = ["xenctrl", "xenstore", "xenforeignmemory", "libc", "xenvmevent-sys", "xenevtchn"]
# KVM driver
kvm = ["kvmi"]
# VirtualBox driver
Expand All @@ -28,21 +28,26 @@ 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 }
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 }
xenctrl = { git = "https://github.com/arnabcs17b006/xenctrl", branch = "mockable_crate", optional = true }
xenstore = { git = "https://github.com/arnabcs17b006/xenstore", branch = "mockable_crate", optional = true }
xenforeignmemory = { git = "https://github.com/arnabcs17b006/xenforeignmemory", branch = "mockable_crate", optional = true }
xenevtchn = { git = "https://github.com/arnabcs17b006/xenevtchn", branch = "mockable_crate", optional = true}
xenvmevent-sys = { git = "https://github.com/arnabcs17b006/xenvmevent-sys", branch = "derive_default", optional = true}
kvmi = { git = "https://github.com/Wenzel/kvmi", optional = true }
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 }
bitflags = "1.2.1"
cty = "0.2.1"
nix = "0.18.0"
bitflags = "1.2.1"
failure = "0.1.7"

[dev-dependencies]
ctrlc = "3.1.3"
clap = "2.33.0"
colored = "1.9.3"
mockall = "0.7.1"
test-case = "1.0.0"

15 changes: 8 additions & 7 deletions examples/cr-events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ fn toggle_cr_intercepts(drv: &mut Box<dyn Introspectable>, vec_cr: &Vec<CrType>,
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");
Expand Down Expand Up @@ -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 {
Expand All @@ -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..."),
Expand Down
25 changes: 12 additions & 13 deletions examples/mem-events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -25,7 +23,7 @@ fn toggle_pf_intercept(drv: &mut Box<dyn Introspectable>, 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"));
}
Expand All @@ -40,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();
Expand All @@ -49,9 +51,6 @@ fn main() {
.expect("Error setting Ctrl-C handler");

println!("Initialize Libmicrovmi");
let init_option = matches
.value_of("kvmi_socket")
.map(|socket| DriverInitParam::KVMiSocket(socket.into()));
let mut drv: Box<dyn Introspectable> = microvmi::init(domain_name, None, init_option);
println!("Listen for memory events...");
// record elapsed time
Expand All @@ -61,11 +60,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");
}

Expand All @@ -87,10 +86,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..."),
Expand Down
8 changes: 4 additions & 4 deletions examples/msr-events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,17 @@ 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";
let ev_nb_output = format!("{}", i).cyan();
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");
Expand Down
2 changes: 1 addition & 1 deletion examples/regs-dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
96 changes: 96 additions & 0 deletions examples/singlestep-events.rs
Original file line number Diff line number Diff line change
@@ -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<dyn Introspectable>, 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<dyn Introspectable> = 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
);
}
20 changes: 12 additions & 8 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl TryInto<DriverInitParam> for DriverInitParamFFI {

///an x86 segment register
#[repr(C)]
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct SegmentReg {
///Stores the base address of a code segment
pub base: u64,
Expand All @@ -75,7 +75,7 @@ pub struct SegmentReg {
/// x86 System Table Registers
/// (GDTR, IDTR)
#[repr(C)]
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct SystemTableReg {
/// 32/64 bits linear base address
pub base: u64,
Expand All @@ -85,7 +85,7 @@ pub struct SystemTableReg {

///Represents all x86 registers on a specific VCPU
#[repr(C)]
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct X86Registers {
/// 8 byte general purpose register.
pub rax: u64,
Expand Down Expand Up @@ -314,11 +314,12 @@ 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
#[repr(C)]
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum EventType {
///Cr register interception
Cr {
Expand All @@ -334,9 +335,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 {
Expand All @@ -353,11 +352,16 @@ pub enum EventType {
/// 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
#[repr(C)]
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CrType {
///Has various control flags that modify the basic operation of the processor.
Cr0,
Expand Down
6 changes: 3 additions & 3 deletions src/driver/kvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ impl<T: KVMIntrospectable> Introspectable for Kvm<T> {
.kvmi
.control_events(vcpu, KVMiInterceptType::Pagefault, enabled)?)
}
_ => unimplemented!(),
}
}

Expand All @@ -309,10 +310,9 @@ impl<T: KVMIntrospectable> Introspectable for Kvm<T> {
new,
old,
},
KVMiEventType::Msr { msr_type, new, old } => EventType::Msr {
KVMiEventType::Msr { msr_type, new, old: _ } => EventType::Msr {
msr_type,
new,
old,
value: new,
},
KVMiEventType::Breakpoint {gpa, insn_len } => EventType::Breakpoint {
gpa,
Expand Down
Loading