diff --git a/Justfile b/Justfile index c8df52da5..c17563f00 100644 --- a/Justfile +++ b/Justfile @@ -212,9 +212,9 @@ test-doc target=default-target features="": miri-tests: rustup +nightly component list | grep -q "miri.*installed" || rustup component add miri --toolchain nightly - # For now only run miri tests on hyperlight-common with trace_guest feature # We can add more as needed cargo +nightly miri test -p hyperlight-common -F trace_guest + cargo +nightly miri test -p hyperlight-host --lib -- mem::shared_mem::tests ################ ### LINTING #### diff --git a/src/hyperlight_host/src/mem/mod.rs b/src/hyperlight_host/src/mem/mod.rs index afc3577dd..64f5db2fe 100644 --- a/src/hyperlight_host/src/mem/mod.rs +++ b/src/hyperlight_host/src/mem/mod.rs @@ -36,5 +36,5 @@ pub mod ptr_offset; /// a memory region for a guest running in a sandbox. pub mod shared_mem; /// Utilities for writing shared memory tests -#[cfg(test)] +#[cfg(all(test, not(miri)))] // uses proptest which isn't miri-compatible pub(crate) mod shared_mem_tests; diff --git a/src/hyperlight_host/src/mem/shared_mem.rs b/src/hyperlight_host/src/mem/shared_mem.rs index 824cfde04..66e10fb72 100644 --- a/src/hyperlight_host/src/mem/shared_mem.rs +++ b/src/hyperlight_host/src/mem/shared_mem.rs @@ -35,13 +35,11 @@ use windows::Win32::System::Memory::{ #[cfg(target_os = "windows")] use windows::core::PCSTR; -#[cfg(target_os = "windows")] -use crate::HyperlightError::MemoryAllocationFailed; use crate::HyperlightError::SnapshotSizeMismatch; #[cfg(target_os = "windows")] -use crate::HyperlightError::{MemoryRequestTooBig, WindowsAPIError}; +use crate::HyperlightError::WindowsAPIError; use crate::sandbox::snapshot::Snapshot; -use crate::{Result, log_then_return, new_error}; +use crate::{HyperlightError, Result, log_then_return, new_error}; /// Makes sure that the given `offset` and `size` are within the bounds of the memory with size `mem_size`. macro_rules! bounds_check { @@ -312,12 +310,11 @@ impl ExclusiveSharedMemory { #[cfg(target_os = "linux")] #[instrument(skip_all, parent = Span::current(), level= "Trace")] pub fn new(min_size_bytes: usize) -> Result { - use libc::{ - MAP_ANONYMOUS, MAP_FAILED, MAP_NORESERVE, MAP_SHARED, PROT_NONE, PROT_READ, PROT_WRITE, - c_int, mmap, mprotect, off_t, size_t, - }; - - use crate::error::HyperlightError::{MemoryRequestTooBig, MmapFailed, MprotectFailed}; + #[cfg(miri)] + use libc::MAP_PRIVATE; + use libc::{MAP_ANONYMOUS, MAP_FAILED, PROT_READ, PROT_WRITE, c_int, mmap, off_t, size_t}; + #[cfg(not(miri))] + use libc::{MAP_NORESERVE, MAP_SHARED, PROT_NONE, mprotect}; if min_size_bytes == 0 { return Err(new_error!("Cannot create shared memory with size 0")); @@ -337,39 +334,55 @@ impl ExclusiveSharedMemory { // usize and isize are guaranteed to be the same size, and // isize::MAX should be positive, so this cast should be safe. if total_size > isize::MAX as usize { - return Err(MemoryRequestTooBig(total_size, isize::MAX as usize)); + return Err(HyperlightError::MemoryRequestTooBig( + total_size, + isize::MAX as usize, + )); } // allocate the memory + #[cfg(not(miri))] + let flags = MAP_ANONYMOUS | MAP_SHARED | MAP_NORESERVE; + #[cfg(miri)] + let flags = MAP_ANONYMOUS | MAP_PRIVATE; + let addr = unsafe { mmap( null_mut(), total_size as size_t, PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_SHARED | MAP_NORESERVE, + flags, -1 as c_int, 0 as off_t, ) }; if addr == MAP_FAILED { - log_then_return!(MmapFailed(Error::last_os_error().raw_os_error())); + log_then_return!(HyperlightError::MmapFailed( + Error::last_os_error().raw_os_error() + )); } // protect the guard pages - - let res = unsafe { mprotect(addr, PAGE_SIZE_USIZE, PROT_NONE) }; - if res != 0 { - return Err(MprotectFailed(Error::last_os_error().raw_os_error())); - } - let res = unsafe { - mprotect( - (addr as *const u8).add(total_size - PAGE_SIZE_USIZE) as *mut c_void, - PAGE_SIZE_USIZE, - PROT_NONE, - ) - }; - if res != 0 { - return Err(MprotectFailed(Error::last_os_error().raw_os_error())); + #[cfg(not(miri))] + { + let res = unsafe { mprotect(addr, PAGE_SIZE_USIZE, PROT_NONE) }; + if res != 0 { + return Err(HyperlightError::MprotectFailed( + Error::last_os_error().raw_os_error(), + )); + } + let res = unsafe { + mprotect( + (addr as *const u8).add(total_size - PAGE_SIZE_USIZE) as *mut c_void, + PAGE_SIZE_USIZE, + PROT_NONE, + ) + }; + if res != 0 { + return Err(HyperlightError::MprotectFailed( + Error::last_os_error().raw_os_error(), + )); + } } Ok(Self { @@ -414,7 +427,10 @@ impl ExclusiveSharedMemory { // usize and isize are guaranteed to be the same size, and // isize::MAX should be positive, so this cast should be safe. if total_size > isize::MAX as usize { - return Err(MemoryRequestTooBig(total_size, isize::MAX as usize)); + return Err(HyperlightError::MemoryRequestTooBig( + total_size, + isize::MAX as usize, + )); } let mut dwmaximumsizehigh = 0; @@ -442,7 +458,7 @@ impl ExclusiveSharedMemory { }; if handle.is_invalid() { - log_then_return!(MemoryAllocationFailed( + log_then_return!(HyperlightError::MemoryAllocationFailed( Error::last_os_error().raw_os_error() )); } @@ -451,7 +467,7 @@ impl ExclusiveSharedMemory { let addr = unsafe { MapViewOfFile(handle, file_map, 0, 0, 0) }; if addr.Value.is_null() { - log_then_return!(MemoryAllocationFailed( + log_then_return!(HyperlightError::MemoryAllocationFailed( Error::last_os_error().raw_os_error() )); } @@ -646,7 +662,7 @@ pub trait SharedMemory { /// not need to be marked as `unsafe` because doing anything with /// this pointer itself requires `unsafe`. fn base_ptr(&self) -> *mut u8 { - self.base_addr() as *mut u8 + self.region().ptr.wrapping_add(PAGE_SIZE_USIZE) } /// Return the length of usable memory contained in `self`. @@ -965,10 +981,14 @@ impl SharedMemory for HostSharedMemory { #[cfg(test)] mod tests { use hyperlight_common::mem::PAGE_SIZE_USIZE; + #[cfg(not(miri))] use proptest::prelude::*; - use super::{ExclusiveSharedMemory, HostSharedMemory, SharedMemory}; + #[cfg(not(miri))] + use super::HostSharedMemory; + use super::{ExclusiveSharedMemory, SharedMemory}; use crate::Result; + #[cfg(not(miri))] use crate::mem::shared_mem_tests::read_write_test_suite; #[test] @@ -1059,6 +1079,8 @@ mod tests { Ok(()) } + // proptest uses file I/O (getcwd, open) which miri doesn't support + #[cfg(not(miri))] proptest! { #[test] fn read_write_i32(val in -0x1000_i32..0x1000_i32) { @@ -1238,6 +1260,7 @@ mod tests { // provides a way for running the above tests in a separate process since they expect to crash #[test] + #[cfg_attr(miri, ignore)] // miri can't spawn subprocesses fn guard_page_testing_shim() { let tests = vec!["read", "write", "exec"]; for test in tests { diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 0872c0780..00cc2a942 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -22,11 +22,11 @@ checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" [[package]] name = "buddy_system_allocator" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0108968a3a2dab95b089c0fc3f1afa7759aa5ebe6f1d86d206d6f7ba726eb" +checksum = "b672b945a3e4f4f40bfd4cd5ee07df9e796a42254ce7cd6d2599ad969244c44a" dependencies = [ - "spin 0.9.8", + "spin", ] [[package]] @@ -79,7 +79,7 @@ dependencies = [ "anyhow", "flatbuffers", "log", - "spin 0.10.0", + "spin", "thiserror", ] @@ -110,7 +110,7 @@ dependencies = [ "hyperlight-guest-tracing", "linkme", "log", - "spin 0.10.0", + "spin", "tracing", ] @@ -129,7 +129,7 @@ name = "hyperlight-guest-tracing" version = "0.12.0" dependencies = [ "hyperlight-common", - "spin 0.10.0", + "spin", "tracing", "tracing-core", ] @@ -311,15 +311,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - [[package]] name = "spin" version = "0.10.0"