use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::time::Instant; use std::u32; use clap::{App, Arg, ArgMatches}; use colored::*; use microvmi::api::events::{EventReplyType, EventType, InterceptType}; use microvmi::api::params::DriverInitParams; use microvmi::api::Introspectable; use utilities::Clappable; // default set of MSRs to be intercepted const DEFAULT_MSR: [u32; 6] = [0x174, 0x175, 0x176, 0xc0000080, 0xc0000081, 0xc0000082]; fn parse_args() -> ArgMatches<'static> { App::new(file!()) .version("0.2") .about( "Watches MSR register VMI events\n\ - MSR_IA32_SYSENTER_CS: 0x174\n\ - MSR_IA32_SYSENTER_ESP: 0x175\n\ - MSR_IA32_SYSENTER_EIP: 0x176\n\ - MSR_EFER: 0xc0000080\n\ - MSR_STAR: 0xc0000081\n\ - MSR_LSTAR: 0xc0000082\ ", ) .arg( Arg::with_name("MSR index") .help("Specific set of MSRs to be intercepted") .multiple(true) .takes_value(true) .short("r"), ) .args(DriverInitParams::to_clap_args().as_ref()) .get_matches() } fn toggle_msr_intercepts(drv: &mut Box, vec_msr: &[u32], enabled: bool) { drv.pause().expect("Failed to pause VM"); for msr in vec_msr { let intercept = InterceptType::Msr(*msr); let status_str = if enabled { "Enabling" } else { "Disabling" }; println!("{} intercept on 0x{:x}", status_str, msr); for vcpu in 0..drv.get_vcpu_count().unwrap() { drv.toggle_intercept(vcpu, intercept, enabled) .unwrap_or_else(|_| panic!("Failed to enable 0x{:x}", msr)); } } drv.resume().expect("Failed to resume VM"); } fn main() { env_logger::init(); let matches = parse_args(); let mut registers: Vec = matches.values_of("register").map_or(Vec::new(), |v| { v.map(|s| { s.parse::() .expect("Unable to convert MSR index to u32") }) .collect() }); if registers.is_empty() { // use default set registers = DEFAULT_MSR.to_vec(); } // 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 init_params = DriverInitParams::from_matches(&matches); let mut drv: Box = microvmi::init(None, Some(init_params)).expect("Failed to init libmicrovmi"); toggle_msr_intercepts(&mut drv, ®isters, true); println!("Listen for MSR 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 (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!( "[{}] {} - {}: new value: 0x{:x}", ev_nb_output, vcpu_output, msr_output, value, ); drv.reply_event(ev, EventReplyType::Continue) .expect("Failed to send event reply"); i += 1; } None => println!("No events yet..."), } } let duration = start.elapsed(); // disable control register interception toggle_msr_intercepts(&mut drv, ®isters, 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 ); }