1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
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)] pub enum DriverType { Dummy, #[cfg(feature = "hyper-v")] HyperV, #[cfg(feature = "kvm")] KVM, #[cfg(feature = "virtualbox")] VirtualBox, #[cfg(feature = "xen")] Xen, } /// Supports passing initialization parameters to the driver /// /// Some drivers can support optional extra initialization parameters. /// /// This is required to initialize the KVM driver, which needs a `domain_name` and /// a `kvm_socket` parameters. /// /// This is equivalent to LibVMI's `vmi_init_data_type_t` #[repr(C)] #[derive(Debug)] pub enum DriverInitParam { KVMiSocket(String), } impl TryInto<DriverInitParam> for DriverInitParamFFI { type Error = IntoStringError; fn try_into(self) -> Result<DriverInitParam, Self::Error> { Ok(match self { DriverInitParamFFI::KVMiSocket(cstr_socket) => DriverInitParam::KVMiSocket( unsafe { CStr::from_ptr(cstr_socket) } .to_owned() .into_string()?, ), }) } } ///an x86 segment register #[repr(C)] #[derive(Debug, Default)] pub struct SegmentReg { ///Stores the base address of a code segment pub base: u64, ///Used as a threshold for offset. If offset added to base is more than limit, GP fault is generated. Otherwise a linear physical address is created. pub limit: u32, ///Represents 16 bit segment selector consisting of a 2-bit Requested Privilege Level (RPL), a 1-bit Table Indicator (TI), and a 13-bit index. 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, Default)] pub struct X86Registers { /// 8 byte general purpose register. pub rax: u64, /// 8 byte general purpose register. pub rbx: u64, /// 8 byte general purpose register. pub rcx: u64, /// 8 byte general purpose register. pub rdx: u64, /// 8 byte general purpose register. pub rsi: u64, /// 8 byte general purpose register. pub rdi: u64, /// 8 byte general purpose register. pub rsp: u64, /// 8 byte general purpose register. pub rbp: u64, /// 8 byte general purpose register. pub r8: u64, /// 8 byte general purpose register. pub r9: u64, /// 8 byte general purpose register. pub r10: u64, /// 8 byte general purpose register. pub r11: u64, /// 8 byte general purpose register. pub r12: u64, /// 8 byte general purpose register. pub r13: u64, /// 8 byte general purpose register. pub r14: u64, /// 8 byte general purpose register. pub r15: u64, /// 8 byte general purpose register. pub rip: u64, /// 8 byte general purpose register. pub rflags: u64, ///Has various control flags that modify the basic operation of the processor. pub cr0: u64, ///Contains a value called Page Fault Linear Address (PFLA). When a page fault occurs, the address the program attempted to access is stored in the CR2 register. CR2 register cannot be intercepted by the guest operating system. pub cr2: u64, ///CR3 enables the processor to translate linear addresses into physical addresses by locating the page directory and page tables for the current task. Typically, the upper 20 bits of CR3 become the page directory base register (PDBR), which stores the physical address of the first page directory entry. pub cr3: u64, ///Used in protected mode to control operations such as virtual-8086 support, enabling I/O breakpoints, page size extension and machine-check exceptions. pub cr4: u64, ///Contains the 32-bit segment selector for the privilege level 0 code segment. Its index value is 0x174. pub sysenter_cs: u64, ///Contains the 32-bit offset into the privilege level 0 code segment to the first instruction of the selected operating procedure or routine. Its index value is 0x175. pub sysenter_esp: u64, ///Contains the 32-bit stack pointer for the privilege level 0 stack. Its index value is 0x176. pub sysenter_eip: u64, ///Extended Feature Enable Register (EFER) allows enabling the SYSCALL/SYSRET instruction, and later for entering and exiting long mode. Its index value is 0xc0000080. pub msr_efer: u64, ///Used to set the handler for SYSCALL and /or SYSRET instructions used for system calls. Its index value is 0xc0000081. pub msr_star: u64, ///Used to set the handler for SYSCALL and /or SYSRET instructions used for system calls. Its index value is 0xc0000082. pub msr_lstar: u64, ///Extened Feature Enable Register pub efer: u64, ///Advanced Programmable Interrupt Control Register pub apic_base: u64, ///Code segment register pub cs: SegmentReg, ///Data segment register pub ds: SegmentReg, ///Extra segment register, customizable by the programmer. pub es: SegmentReg, ///Points to TIB(Thread Information block) of a process. pub fs: SegmentReg, ///Points to TLS(Thread Local Storage) of a process. pub gs: SegmentReg, ///Stack Segment Register pub ss: SegmentReg, /// Task Register pub tr: SegmentReg, /// Local descriptor table register pub ldt: SegmentReg, pub idt: SystemTableReg, pub gdt: SystemTableReg, } #[repr(C)] #[derive(Debug)] pub enum Registers { X86(X86Registers), } pub const PAGE_SHIFT: u32 = 12; pub const PAGE_SIZE: u32 = 4096; pub trait Introspectable { /// Retrieve the number of VCPUs. /// fn get_vcpu_count(&self) -> Result<u16, Box<dyn Error>> { unimplemented!(); } /// read the physical memory, starting from paddr, into buf /// /// # Arguments /// /// * 'paddr' - the physical address to read from /// * 'buf' - the data read from memory /// fn read_physical(&self, _paddr: u64, _buf: &mut [u8]) -> Result<(), Box<dyn Error>> { unimplemented!(); } /// Modify contents of physical memory, starting at paddr, from buf /// /// # Arguments /// /// * 'paddr' - the physical address to write into /// * 'buf' - the data to be written into memory /// fn write_physical(&self, _paddr: u64, _buf: &mut [u8]) -> Result<(), Box<dyn Error>> { unimplemented!(); } /// Get the maximum physical address /// /// Returns maximum physical address in 64 bit unsigned integer format. /// fn get_max_physical_addr(&self) -> Result<u64, Box<dyn Error>> { unimplemented!(); } /// Read register values /// /// # Arguments /// * 'vcpu' - vcpu id for which the value of registers are to be dumped as the argument /// fn read_registers(&self, _vcpu: u16) -> Result<Registers, Box<dyn Error>> { unimplemented!(); } ///get page access /// /// # Arguments /// * 'paddr' - physical address of the page whose access we want to know. /// fn get_page_access(&self, _paddr: u64) -> Result<Access, Box<dyn Error>> { unimplemented!(); } ///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!(); } /// 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!(); } /// Used to pause the VM /// fn pause(&mut self) -> Result<(), Box<dyn Error>> { unimplemented!(); } /// Used to resume the VM /// fn resume(&mut self) -> Result<(), Box<dyn Error>> { unimplemented!(); } /// Used to enable/disable an event interception /// /// # Arguments /// * 'vcpu' - vcpu id for which we are to enable/disable intercept monitoring /// * 'intercept_type' - to specify event type for which to raise flag /// * 'enabled' - flag to specify whether to enable/disable event monitoring /// fn toggle_intercept( &mut self, _vcpu: u16, _intercept_type: InterceptType, _enabled: bool, ) -> Result<(), Box<dyn Error>> { unimplemented!(); } /// Listen and return the next event, or None /// /// # Arguments /// * 'timeout' - Time for which it will wait for a new event /// fn listen(&mut self, _timeout: u32) -> Result<Option<Event>, Box<dyn Error>> { unimplemented!(); } /// Send reply corresponding to the current event being popped /// /// # Arguments /// * 'event' /// * 'reply_type' /// fn reply_event( &mut self, _event: Event, _reply_type: EventReplyType, ) -> Result<(), Box<dyn Error>> { unimplemented!(); } } /// Various types of intercepts handled by libmicrovmi #[repr(C)] #[derive(Debug, Copy, Clone)] pub enum InterceptType { /// Intercept when value of cr register is changed by the guest Cr(CrType), /// Intercept when value of msr register is changed by the guest 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 #[repr(C)] #[derive(Debug)] pub enum EventType { ///Cr register interception Cr { ///Type of control register cr_type: CrType, /// new value after cr register has been intercepted by the guest. new: u64, /// old value before cr register has been intercepted by the guest. old: u64, }, ///Msr register interception Msr { ///Type of model specific register msr_type: u32, /// new value after msr register has been intercepted by the guest. value: u64, }, ///int3 interception Breakpoint { /// Physical memory address of the guest gpa: u64, /// instruction length. Generally it should be one. Anything other than one implies malicious guest. insn_len: u8, }, Pagefault { /// Virtual memory address of the guest gva: u64, /// Physical memory address of the guest gpa: u64, /// Acsess responsible for thr pagefault access: Access, }, } ///Types of x86 control registers are listed here #[repr(C)] #[derive(Debug, Copy, Clone)] pub enum CrType { ///Has various control flags that modify the basic operation of the processor. Cr0, ///Contains a value called Page Fault Linear Address (PFLA). When a page fault occurs, the address the program attempted to access is stored in the CR2 register. CR2 register cannot be intercepted by the guest operating system. Cr3, ///Used in protected mode to control operations such as virtual-8086 support, enabling I/O breakpoints, page size extension and machine-check exceptions. Cr4, } ///This provides an abstraction of event which the hypervisor reports and using which we introspect the guest #[repr(C)] pub struct Event { ///vcpu on which the event is detected pub vcpu: u16, /// Type of event detected pub kind: EventType, } ///Reply provided to the hypervisor after detecting an event #[repr(C)] #[derive(Debug)] pub enum EventReplyType { Continue, }