Skip to content

Commit

Permalink
unit tests added
Browse files Browse the repository at this point in the history
  • Loading branch information
arnabcs17b006 committed Sep 5, 2020
1 parent 03e452c commit c89ed33
Show file tree
Hide file tree
Showing 5 changed files with 1,431 additions and 144 deletions.
6 changes: 3 additions & 3 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 @@ -31,8 +31,8 @@ libc = { version = "0.2.58", 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"}
xenvmevent-sys = { git = "https://github.com/Wenzel/xenvmevent-sys"}
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 }
Expand Down
47 changes: 34 additions & 13 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 @@ -72,9 +72,20 @@ pub struct SegmentReg {
pub selector: u16,
}

/// x86 System Table Registers
/// (GDTR, IDTR)
#[repr(C)]
#[derive(Debug, Default)]
pub struct SystemTableReg {
/// 32/64 bits linear base address
pub base: u64,
/// 16 bits table limit
pub limit: u16,
}

///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 @@ -152,6 +163,8 @@ pub struct X86Registers {
pub tr: SegmentReg,
/// Local descriptor table register
pub ldt: SegmentReg,
pub idt: SystemTableReg,
pub gdt: SystemTableReg,
}

#[repr(C)]
Expand Down Expand Up @@ -209,23 +222,32 @@ pub trait Introspectable {
unimplemented!();
}

/// Write register values
///get page access
///
/// # Arguments
/// * 'vcpu' - vcpu id for which the value of registers are to be set
/// * 'reg' - Registers enum having values to be set
/// * 'paddr' - physical address of the page whose access we want to know.
///
fn write_registers(&self, _vcpu: u16, _reg: Registers) -> Result<(), Box<dyn Error>> {
fn get_page_access(&self, _paddr: u64) -> Result<Access, Box<dyn Error>> {
unimplemented!();
}

//get page access
fn get_page_access(&self, _paddr: u64) -> Result<Access, Box<dyn Error>> {
///set page access
///
/// # Arguments
/// * 'paddr' - physical address of the page whose access we want to set
/// * 'access' - access flags to be set on the given page
///
fn set_page_access(&self, _paddr: u64, _access: Access) -> Result<(), Box<dyn Error>> {
unimplemented!();
}

//set page access
fn set_page_access(&self, _paddr: u64, _access: Access) -> Result<(), Box<dyn Error>> {
/// Write register values
///
/// # Arguments
/// * 'vcpu' - vcpu id for which the value of registers are to be set
/// * 'reg' - Registers enum having values to be set
///
fn write_registers(&self, _vcpu: u16, _reg: Registers) -> Result<(), Box<dyn Error>> {
unimplemented!();
}

Expand Down Expand Up @@ -297,7 +319,7 @@ pub enum InterceptType {

/// 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 @@ -322,7 +344,6 @@ 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,
Expand All @@ -340,7 +361,7 @@ pub enum EventType {

///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
90 changes: 78 additions & 12 deletions src/driver/kvm.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,51 @@
use kvmi::{
kvm_regs, kvm_segment, KVMIntrospectable, KVMiCr, KVMiEvent, KVMiEventReply, KVMiEventType,
KVMiInterceptType,
kvm_dtable, kvm_regs, kvm_segment, KVMIntrospectable, KVMiCr, KVMiEvent, KVMiEventReply,
KVMiEventType, KVMiInterceptType, KVMiPageAccess,
};
use std::convert::From;
use std::convert::TryFrom;
use std::convert::TryInto;
use std::error::Error;
use std::mem;
use std::vec::Vec;

use crate::api::{
CrType, DriverInitParam, Event, EventReplyType, EventType, InterceptType, Introspectable,
Registers, SegmentReg, X86Registers, PAGE_SHIFT,
Access, CrType, DriverInitParam, Event, EventReplyType, EventType, InterceptType,
Introspectable, Registers, SegmentReg, SystemTableReg, X86Registers, PAGE_SHIFT,
};

impl TryFrom<Access> for KVMiPageAccess {
type Error = &'static str;
fn try_from(access: Access) -> Result<Self, Self::Error> {
match access {
Access::NIL => Ok(KVMiPageAccess::NIL),
Access::R => Ok(KVMiPageAccess::R),
Access::W => Ok(KVMiPageAccess::W),
Access::RW => Ok(KVMiPageAccess::RW),
Access::X => Ok(KVMiPageAccess::X),
Access::RX => Ok(KVMiPageAccess::RX),
Access::WX => Ok(KVMiPageAccess::WX),
Access::RWX => Ok(KVMiPageAccess::RWX),
_ => Err("invalid access value"),
}
}
}

impl From<KVMiPageAccess> for Access {
fn from(access: KVMiPageAccess) -> Self {
match access {
KVMiPageAccess::NIL => Access::NIL,
KVMiPageAccess::R => Access::R,
KVMiPageAccess::W => Access::W,
KVMiPageAccess::RW => Access::RW,
KVMiPageAccess::X => Access::X,
KVMiPageAccess::RX => Access::RX,
KVMiPageAccess::WX => Access::WX,
KVMiPageAccess::RWX => Access::RWX,
}
}
}

impl From<kvm_segment> for SegmentReg {
fn from(segment: kvm_segment) -> Self {
SegmentReg {
Expand All @@ -22,6 +56,15 @@ impl From<kvm_segment> for SegmentReg {
}
}

impl From<kvm_dtable> for SystemTableReg {
fn from(dtable: kvm_dtable) -> Self {
SystemTableReg {
base: dtable.base,
limit: dtable.limit,
}
}
}

impl From<X86Registers> for kvm_regs {
fn from(register: X86Registers) -> Self {
kvm_regs {
Expand Down Expand Up @@ -86,7 +129,7 @@ impl<T: KVMIntrospectable> Kvm<T> {
.control_events(vcpu, KVMiInterceptType::Msr, true)
.unwrap();
kvm.kvmi
.control_events(vcpu, KVMiInterceptType::Breakpoint, true)
.control_events(vcpu, KVMiInterceptType::Pagefault, true)
.unwrap();
}

Expand Down Expand Up @@ -155,6 +198,8 @@ impl<T: KVMIntrospectable> Introspectable for Kvm<T> {
ss: sregs.ss.into(),
tr: sregs.tr.into(),
ldt: sregs.ldt.into(),
idt: sregs.idt.into(),
gdt: sregs.gdt.into(),
}))
}

Expand All @@ -167,6 +212,17 @@ impl<T: KVMIntrospectable> Introspectable for Kvm<T> {
Ok(())
}

fn get_page_access(&self, paddr: u64) -> Result<Access, Box<dyn Error>> {
let access = self.kvmi.get_page_access(paddr).unwrap();
Ok(access.try_into().unwrap())
}

fn set_page_access(&self, paddr: u64, access: Access) -> Result<(), Box<dyn Error>> {
self.kvmi
.set_page_access(paddr, access.try_into().unwrap())?;
Ok(())
}

fn pause(&mut self) -> Result<(), Box<dyn Error>> {
debug!("pause");
// already paused ?
Expand Down Expand Up @@ -228,6 +284,12 @@ impl<T: KVMIntrospectable> Introspectable for Kvm<T> {
.kvmi
.control_events(vcpu, KVMiInterceptType::Breakpoint, enabled)?)
}
InterceptType::Pagefault => {
Ok(self
.kvmi
.control_events(vcpu, KVMiInterceptType::Pagefault, enabled)?)
}
_ => unimplemented!(),
}
}

Expand All @@ -248,16 +310,20 @@ 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,
value: new,
},
KVMiEventType::Breakpoint {gpa, insn_len } => EventType::Breakpoint {
gpa,
insn_len,
},
KVMiEventType::Pagefault {gva, gpa, access, view: _} => EventType::Pagefault {
gva,
gpa,
access: access.into(),
},
KVMiEventType::PauseVCPU => panic!("Unexpected PauseVCPU event. It should have been popped by resume VM. (Did you forget to resume your VM ?)"),
_ => unimplemented!(),
};

let vcpu = kvmi_event.vcpu;
Expand Down Expand Up @@ -299,7 +365,7 @@ impl<T: KVMIntrospectable> Drop for Kvm<T> {
.control_events(vcpu, KVMiInterceptType::Msr, false)
.unwrap();
self.kvmi
.control_events(vcpu, KVMiInterceptType::Breakpoint, false)
.control_events(vcpu, KVMiInterceptType::Pagefault, false)
.unwrap();
}
}
Expand Down Expand Up @@ -383,7 +449,7 @@ mod tests {
.expect_control_events()
.with(
eq(vcpu as u16),
function(|x| matches!(x, KVMiInterceptType::Breakpoint)),
function(|x| matches!(x, KVMiInterceptType::Pagefault)),
eq(true),
)
.times(1)
Expand All @@ -392,7 +458,7 @@ mod tests {
.expect_control_events()
.with(
eq(vcpu as u16),
function(|x| matches!(x, KVMiInterceptType::Breakpoint)),
function(|x| matches!(x, KVMiInterceptType::Pagefault)),
eq(false),
)
.times(1)
Expand Down Expand Up @@ -425,8 +491,8 @@ mod tests {
fn control_msr(&self, vcpu: u16, reg: u32, enabled: bool) -> Result<(), std::io::Error>;
fn read_physical(&self, gpa: u64, buffer: &mut [u8]) -> Result<(), std::io::Error>;
fn write_physical(&self, gpa: u64, buffer: &[u8]) -> Result<(), std::io::Error>;
fn get_page_access(&self, gpa: u64) -> Result<u8, std::io::Error>;
fn set_page_access(&self, gpa: u64, access: u8) -> Result<(), std::io::Error>;
fn get_page_access(&self, gpa: u64) -> Result<KVMiPageAccess, std::io::Error>;
fn set_page_access(&self, gpa: u64, access: KVMiPageAccess) -> Result<(), std::io::Error>;
fn pause(&self) -> Result<(), std::io::Error>;
fn get_vcpu_count(&self) -> Result<u32, std::io::Error>;
fn get_registers(&self, vcpu: u16) -> Result<(kvm_regs, kvm_sregs, KvmMsrs), std::io::Error>;
Expand Down
Loading

0 comments on commit c89ed33

Please sign in to comment.