Skip to content

Commit e793129

Browse files
committed
Reset more vcpu state after snapshot::restore
Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent 429446f commit e793129

File tree

13 files changed

+738
-127
lines changed

13 files changed

+738
-127
lines changed

Cargo.lock

Lines changed: 2 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/hyperlight_host/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ windows-version = "0.1"
7575
lazy_static = "1.4.0"
7676

7777
[target.'cfg(unix)'.dependencies]
78-
kvm-bindings = { version = "0.14", features = ["fam-wrappers"], optional = true }
79-
kvm-ioctls = { version = "0.24", optional = true }
78+
kvm-bindings = { git = "https://github.com/rust-vmm/kvm", rev = "25f630aa384dad1306b288ec5eed3312f84e3393", features = ["fam-wrappers"], optional = true }
79+
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm", rev = "25f630aa384dad1306b288ec5eed3312f84e3393", optional = true }
8080
mshv-bindings = { version = "0.6", optional = true }
8181
mshv-ioctls = { version = "0.6", optional = true}
8282

src/hyperlight_host/src/error.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ pub enum HyperlightError {
144144
#[error("Memory Allocation Failed with OS Error {0:?}.")]
145145
MemoryAllocationFailed(Option<i32>),
146146

147+
/// MSR Read Violation - Guest attempted to read from a Model-Specific Register
148+
#[error("Guest attempted to read from MSR {0:#x}")]
149+
MsrReadViolation(u32),
150+
151+
/// MSR Write Violation - Guest attempted to write to a Model-Specific Register
152+
#[error("Guest attempted to write {1:#x} to MSR {0:#x}")]
153+
MsrWriteViolation(u32, u64),
154+
147155
/// Memory Protection Failed
148156
#[error("Memory Protection Failed with OS Error {0:?}.")]
149157
MemoryProtectionFailed(Option<i32>),
@@ -322,7 +330,9 @@ impl HyperlightError {
322330
| HyperlightError::PoisonedSandbox
323331
| HyperlightError::ExecutionAccessViolation(_)
324332
| HyperlightError::StackOverflow()
325-
| HyperlightError::MemoryAccessViolation(_, _, _) => true,
333+
| HyperlightError::MemoryAccessViolation(_, _, _)
334+
| HyperlightError::MsrReadViolation(_)
335+
| HyperlightError::MsrWriteViolation(_, _) => true,
326336

327337
// All other errors do not poison the sandbox.
328338
HyperlightError::AnyhowError(_)

src/hyperlight_host/src/hypervisor/hyperlight_vm.rs

Lines changed: 230 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use crate::hypervisor::hyperv_linux::MshvVm;
4646
use crate::hypervisor::hyperv_windows::WhpVm;
4747
#[cfg(kvm)]
4848
use crate::hypervisor::kvm::KvmVm;
49-
use crate::hypervisor::regs::CommonSpecialRegisters;
49+
use crate::hypervisor::regs::{CommonDebugRegs, CommonSpecialRegisters};
5050
#[cfg(target_os = "windows")]
5151
use crate::hypervisor::wrappers::HandleWrapper;
5252
use crate::hypervisor::{HyperlightExit, InterruptHandle, InterruptHandleImpl, get_max_log_level};
@@ -86,6 +86,9 @@ pub(crate) struct HyperlightVm {
8686
next_slot: u32, // Monotonically increasing slot number
8787
freed_slots: Vec<u32>, // Reusable slots from unmapped regions
8888

89+
// pml4 saved to be able to restore it if needed
90+
#[cfg(feature = "init-paging")]
91+
pml4_addr: u64,
8992
#[cfg(gdb)]
9093
gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
9194
#[cfg(gdb)]
@@ -94,6 +97,11 @@ pub(crate) struct HyperlightVm {
9497
trace_info: MemTraceInfo,
9598
#[cfg(crashdump)]
9699
rt_cfg: SandboxRuntimeConfig,
100+
// Windows does not support just "zeroing" out the xsave area - we need to preserve the XCOMP_BV.
101+
// Since it varies by hardware, we can't just hardcode a value, so we save it here.
102+
// Also note that windows uses compacted format for xsave.
103+
#[cfg(target_os = "windows")]
104+
xcomp_bv: u64,
97105
}
98106

99107
impl HyperlightVm {
@@ -128,6 +136,11 @@ impl HyperlightVm {
128136
None => return Err(NoHypervisorFound()),
129137
};
130138

139+
// Enable MSR intercepts unless explicitly allowed
140+
if !config.get_allow_msr() {
141+
vm.enable_msr_intercept()?;
142+
}
143+
131144
for (i, region) in mem_regions.iter().enumerate() {
132145
// Safety: slots are unique and region points to valid memory since we created the regions
133146
unsafe { vm.map_memory((i as u32, region))? };
@@ -172,6 +185,18 @@ impl HyperlightVm {
172185
dropped: AtomicBool::new(false),
173186
});
174187

188+
// get xsave header for debugging
189+
#[cfg(target_os = "windows")]
190+
{
191+
let xsave = vm.xsave()?;
192+
193+
let xcomp_bv = if xsave.len() >= 528 {
194+
u64::from_le_bytes(xsave[520..528].try_into().unwrap())
195+
} else {
196+
return Err(new_error!("XSAVE buffer too small to contain XCOMP_BV"));
197+
};
198+
}
199+
175200
#[cfg_attr(not(gdb), allow(unused_mut))]
176201
let mut ret = Self {
177202
vm,
@@ -185,6 +210,8 @@ impl HyperlightVm {
185210
mmap_regions: Vec::new(),
186211
freed_slots: Vec::new(),
187212

213+
#[cfg(feature = "init-paging")]
214+
pml4_addr: _pml4_addr,
188215
#[cfg(gdb)]
189216
gdb_conn,
190217
#[cfg(gdb)]
@@ -193,6 +220,8 @@ impl HyperlightVm {
193220
trace_info,
194221
#[cfg(crashdump)]
195222
rt_cfg,
223+
#[cfg(target_os = "windows")]
224+
xcomp_bv,
196225
};
197226

198227
// Send the interrupt handle to the GDB thread if debugging is enabled
@@ -487,6 +516,12 @@ impl HyperlightVm {
487516
}
488517
}
489518
}
519+
Ok(HyperlightExit::MsrRead(msr_index)) => {
520+
break Err(HyperlightError::MsrReadViolation(msr_index));
521+
}
522+
Ok(HyperlightExit::MsrWrite { msr_index, value }) => {
523+
break Err(HyperlightError::MsrWriteViolation(msr_index, value));
524+
}
490525
Ok(HyperlightExit::Cancelled()) => {
491526
// If cancellation was not requested for this specific guest function call,
492527
// the vcpu was interrupted by a stale cancellation. This can occur when:
@@ -581,6 +616,48 @@ impl HyperlightVm {
581616
Ok(())
582617
}
583618

619+
// Resets the following vCPU state:
620+
// - General purpose registers
621+
// - FPU registers
622+
// - Debug registers
623+
// - Special registers
624+
// - XSAVE area
625+
pub(crate) fn reset_vcpu(&self) -> Result<()> {
626+
self.vm.set_regs(&CommonRegisters::default())?;
627+
self.vm.set_fpu(&CommonFpu::default())?;
628+
self.vm.set_debug_regs(&CommonDebugRegs::default())?;
629+
630+
#[cfg(feature = "init-paging")]
631+
self.vm
632+
.set_sregs(&CommonSpecialRegisters::standard_64bit_defaults(
633+
self.pml4_addr,
634+
))?;
635+
#[cfg(not(feature = "init-paging"))]
636+
self.vm
637+
.set_sregs(&CommonSpecialRegisters::standard_real_mode_defaults())?;
638+
639+
// Windows does not support just "zeroing" out the xsave area - we need to preserve the XCOMP_BV.
640+
#[cfg(target_os = "windows")]
641+
{
642+
// The XSAVE header starts at offset 512.
643+
// Bytes 7:0 of the header is XSTATE_BV.
644+
// Bytes 15:8 of the header is XCOMP_BV.
645+
// So XCOMP_BV starts at offset 512 + 8 = 520.
646+
// We are using a u32 array, so the index is 520 / 4 = 130.
647+
const XCOMP_BV_OFFSET_U32: usize = 520 / std::mem::size_of::<u32>();
648+
649+
let mut xsave = [0u32; 1024];
650+
xsave[XCOMP_BV_OFFSET_U32] = self.xcomp_bv as u32;
651+
xsave[XCOMP_BV_OFFSET_U32 + 1] = (self.xcomp_bv >> 32) as u32;
652+
self.vm.set_xsave(&xsave)?;
653+
}
654+
#[cfg(not(target_os = "windows"))]
655+
self.vm.set_xsave(&[0; 1024])?;
656+
657+
// MSRs don't need to be reset as they cannot be modified by guest (unless unsafely-allowed)
658+
Ok(())
659+
}
660+
584661
// Handle a debug exit
585662
#[cfg(gdb)]
586663
fn handle_debug(
@@ -818,6 +895,158 @@ fn get_memory_access_violation<'a>(
818895
None
819896
}
820897

898+
#[cfg(test)]
899+
mod tests {
900+
use super::*;
901+
use crate::is_hypervisor_present;
902+
use crate::mem::layout::SandboxMemoryLayout;
903+
use crate::mem::mgr::SandboxMemoryManager;
904+
use crate::mem::ptr::RawPtr;
905+
use crate::mem::ptr_offset::Offset;
906+
use crate::mem::shared_mem::{ExclusiveSharedMemory, SharedMemory};
907+
use crate::sandbox::SandboxConfiguration;
908+
use crate::sandbox::host_funcs::FunctionRegistry;
909+
#[cfg(feature = "mem_profile")]
910+
use crate::sandbox::trace::DummyUnwindInfo;
911+
#[cfg(feature = "mem_profile")]
912+
use crate::sandbox::trace::MemTraceInfo;
913+
#[cfg(crashdump)]
914+
use crate::sandbox::uninitialized::SandboxRuntimeConfig;
915+
use std::sync::{Arc, Mutex};
916+
917+
#[test]
918+
fn test_reset_vcpu() -> Result<()> {
919+
if !is_hypervisor_present() {
920+
return Ok(());
921+
}
922+
923+
#[cfg(target_os = "windows")]
924+
return Ok(());
925+
926+
#[cfg(not(target_os = "windows"))]
927+
{
928+
let mut code = Vec::new();
929+
// mov rax, 0x1111111111111111
930+
code.extend_from_slice(&[0x48, 0xb8, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11]);
931+
// mov rbx, 0x2222222222222222
932+
code.extend_from_slice(&[0x48, 0xbb, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22]);
933+
// mov rcx, 0x3333333333333333
934+
code.extend_from_slice(&[0x48, 0xb9, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33]);
935+
936+
// hlt
937+
code.extend_from_slice(&[0xf4]);
938+
939+
let config: SandboxConfiguration = Default::default();
940+
#[cfg(crashdump)]
941+
let rt_cfg: SandboxRuntimeConfig = Default::default();
942+
#[cfg(feature = "mem_profile")]
943+
let trace_info = MemTraceInfo::new(Arc::new(DummyUnwindInfo {})).unwrap();
944+
945+
let layout = SandboxMemoryLayout::new(
946+
config.clone(),
947+
code.len(), // code size
948+
0, // stack
949+
0, // heap
950+
0, // init data
951+
None,
952+
)?;
953+
954+
let mem_size = layout.get_memory_size()?;
955+
let eshm = ExclusiveSharedMemory::new(mem_size)?;
956+
957+
let stack_cookie = [0u8; 16];
958+
let mem_mgr = SandboxMemoryManager::new(
959+
layout.clone(),
960+
eshm,
961+
RawPtr::from(0),
962+
Offset::from(0),
963+
stack_cookie,
964+
);
965+
966+
let (mut mem_mgr_hshm, mut mem_mgr_gshm) = mem_mgr.build();
967+
968+
// Set up shared memory (page tables)
969+
#[cfg(feature = "init-paging")]
970+
let rsp = {
971+
let mut regions = layout.get_memory_regions(&mem_mgr_gshm.shared_mem)?;
972+
let mem_size = mem_mgr_gshm.shared_mem.mem_size() as u64;
973+
mem_mgr_gshm.set_up_shared_memory(mem_size, &mut regions)?
974+
};
975+
#[cfg(not(feature = "init-paging"))]
976+
let rsp = 0;
977+
978+
// Write code
979+
let code_offset = layout.get_guest_code_offset();
980+
mem_mgr_hshm
981+
.shared_mem
982+
.copy_from_slice(&code, code_offset)?;
983+
984+
// Get regions for VM
985+
let regions = layout
986+
.get_memory_regions(&mem_mgr_gshm.shared_mem)?
987+
.into_iter()
988+
.filter(|r| r.guest_region.len() > 0)
989+
.collect();
990+
991+
// Calculate pml4_addr
992+
#[cfg(feature = "init-paging")]
993+
let pml4_addr = SandboxMemoryLayout::PML4_OFFSET as u64;
994+
#[cfg(not(feature = "init-paging"))]
995+
let pml4_addr = 0;
996+
997+
// Entrypoint
998+
let entrypoint = layout.get_guest_code_address() as u64;
999+
1000+
let mut vm = HyperlightVm::new(
1001+
regions,
1002+
pml4_addr,
1003+
entrypoint,
1004+
rsp,
1005+
&config,
1006+
#[cfg(gdb)]
1007+
None,
1008+
#[cfg(crashdump)]
1009+
rt_cfg,
1010+
#[cfg(feature = "mem_profile")]
1011+
trace_info,
1012+
)?;
1013+
1014+
let host_funcs = Arc::new(Mutex::new(FunctionRegistry::default()));
1015+
#[cfg(gdb)]
1016+
let dbg_mem_access_fn = Arc::new(Mutex::new(mem_mgr_hshm.clone()));
1017+
1018+
// Run the VM
1019+
vm.initialise(
1020+
RawPtr::from(0), // peb_addr
1021+
0, // seed
1022+
4096, // page_size
1023+
&mut mem_mgr_hshm,
1024+
&host_funcs,
1025+
None,
1026+
#[cfg(gdb)]
1027+
dbg_mem_access_fn.clone(),
1028+
)?;
1029+
1030+
// After run, check registers
1031+
let regs = vm.vm.regs()?;
1032+
assert_eq!(regs.rax, 0x1111111111111111);
1033+
assert_eq!(regs.rbx, 0x2222222222222222);
1034+
assert_eq!(regs.rcx, 0x3333333333333333);
1035+
1036+
// Reset vcpu
1037+
vm.reset_vcpu()?;
1038+
1039+
// Check registers again
1040+
let regs = vm.vm.regs()?;
1041+
assert_eq!(regs.rax, 0);
1042+
assert_eq!(regs.rbx, 0);
1043+
assert_eq!(regs.rcx, 0);
1044+
}
1045+
1046+
Ok(())
1047+
}
1048+
}
1049+
8211050
#[cfg(gdb)]
8221051
mod debug {
8231052
use hyperlight_common::mem::PAGE_SIZE;

0 commit comments

Comments
 (0)