hypervisor kernel integrity enforcement via EPT/NPT write interception for Xen/HVM guests
14

Configure Feed

Select the types of activity you want to include in your feed.

turnstile / turnstile-ctl / src / hypercall.rs
4.1 kB 150 lines
1use std::fs::{File, OpenOptions}; 2use std::os::unix::io::AsRawFd; 3 4use crate::error::{Result, TurnstileError}; 5use crate::xen::*; 6 7pub struct XenHandle { 8 privcmd: File, 9} 10 11impl XenHandle { 12 pub fn open() -> Result<Self> { 13 let privcmd = OpenOptions::new() 14 .read(true) 15 .write(true) 16 .open("/dev/xen/privcmd")?; 17 Ok(Self { privcmd }) 18 } 19 20 fn hypercall(&self, op: u32, domid: u16, arg: u64) -> Result<i64> { 21 let mut hc = PrivcmdHypercall { 22 op: HYPERVISOR_TURNSTILE, 23 arg: [op as _, domid as _, arg, 0, 0], 24 }; 25 26 let ret = unsafe { privcmd_hypercall(self.privcmd.as_raw_fd(), &mut hc) }; 27 28 match ret { 29 Ok(v) => Ok(v as i64), 30 Err(nix::errno::Errno::ESRCH) => Err(TurnstileError::DomainNotFound(domid)), 31 Err(e) => Err(TurnstileError::Hypercall(e as i32)), 32 } 33 } 34 35 pub fn set_policy(&self, domid: u16, policy: u32) -> Result<()> { 36 let op = TurnstileOpSetPolicy { policy, _pad: 0 }; 37 self.hypercall( 38 TURNSTILE_OP_SET_POLICY, 39 domid, 40 &op as *const _ as u64, 41 )?; 42 Ok(()) 43 } 44 45 pub fn protect_range(&self, domid: u16, gpa_start: u64, length: u64) -> Result<()> { 46 let op = TurnstileOpProtectRange { gpa_start, length }; 47 self.hypercall( 48 TURNSTILE_OP_PROTECT_RANGE, 49 domid, 50 &op as *const _ as u64, 51 )?; 52 Ok(()) 53 } 54 55 pub fn unprotect_range(&self, domid: u16, gpa_start: u64, length: u64) -> Result<()> { 56 let op = TurnstileOpProtectRange { gpa_start, length }; 57 self.hypercall( 58 TURNSTILE_OP_UNPROTECT_RANGE, 59 domid, 60 &op as *const _ as u64, 61 )?; 62 Ok(()) 63 } 64 65 pub fn get_stats(&self, domid: u16) -> Result<TurnstileStats> { 66 let mut stats = TurnstileStats::default(); 67 self.hypercall( 68 TURNSTILE_OP_GET_STATS, 69 domid, 70 &mut stats as *mut _ as u64, 71 )?; 72 Ok(stats) 73 } 74 75 pub fn get_violations( 76 &self, 77 domid: u16, 78 buffer: &mut [TurnstileViolation], 79 ) -> Result<(u32, u32)> { 80 let mut op = TurnstileOpGetViolations { 81 buffer_ptr: buffer.as_ptr() as u64, 82 max_entries: buffer.len() as u32, 83 entries_returned: 0, 84 overflow_count: 0, 85 _pad: 0, 86 }; 87 88 self.hypercall( 89 TURNSTILE_OP_GET_VIOLATIONS, 90 domid, 91 &mut op as *mut _ as u64, 92 )?; 93 94 Ok((op.entries_returned, op.overflow_count)) 95 } 96 97 pub fn upload_func_entries(&self, domid: u16, entries: &[u64]) -> Result<()> { 98 if entries.is_empty() { 99 return Ok(()); 100 } 101 102 if entries.len() > TURNSTILE_MAX_FUNC_ENTRIES { 103 return Err(TurnstileError::MetadataLimitExceeded( 104 entries.len(), 105 TURNSTILE_MAX_FUNC_ENTRIES, 106 )); 107 } 108 109 let op = TurnstileOpUploadMetadata { 110 buffer_ptr: entries.as_ptr() as u64, 111 metadata_type: TURNSTILE_META_FUNC_ENTRIES, 112 count: entries.len() as u32, 113 }; 114 115 self.hypercall( 116 TURNSTILE_OP_UPLOAD_METADATA, 117 domid, 118 &op as *const _ as u64, 119 )?; 120 121 Ok(()) 122 } 123 124 pub fn upload_jump_entries(&self, domid: u16, entries: &[JumpEntryUpload]) -> Result<()> { 125 if entries.is_empty() { 126 return Ok(()); 127 } 128 129 if entries.len() > TURNSTILE_MAX_JUMP_ENTRIES { 130 return Err(TurnstileError::MetadataLimitExceeded( 131 entries.len(), 132 TURNSTILE_MAX_JUMP_ENTRIES, 133 )); 134 } 135 136 let op = TurnstileOpUploadMetadata { 137 buffer_ptr: entries.as_ptr() as u64, 138 metadata_type: TURNSTILE_META_JUMP_ENTRIES, 139 count: entries.len() as u32, 140 }; 141 142 self.hypercall( 143 TURNSTILE_OP_UPLOAD_METADATA, 144 domid, 145 &op as *const _ as u64, 146 )?; 147 148 Ok(()) 149 } 150}