diff --git a/CHANGELOG.md b/CHANGELOG.md index f73ce1620..fa70855d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). tables become unreachable at the snapshot instead of at the next restore. * `vmem::walk_va_spaces` merges adjacent mappings of the same kind into one mapping. +* A new sandbox writes only the guest code, PEB and init data into its memory. + The host populates other pages on first guest touch, which speeds up sandbox + creation. * **Breaking:** The transport arena sits one unmapped guard page below the reserved scratch-top pages, at an address independent of the scratch size, and the page tables at the scratch base. The guest's page allocator stops at the arena GPA the host publishes in the scratch-top metadata, so guests must be rebuilt. `hyperlight_common::layout::scratch_allocator_limit_gpa` is renamed `scratch_reserved_top_gpa`, the start of the reserved pages. An allocator that stops there runs into the arena. The minimum scratch size grows by that guard page. Snapshot ABI 7: existing snapshots must be regenerated. diff --git a/src/hyperlight_host/src/mem/shared_mem.rs b/src/hyperlight_host/src/mem/shared_mem.rs index e5113cef6..69ef78732 100644 --- a/src/hyperlight_host/src/mem/shared_mem.rs +++ b/src/hyperlight_host/src/mem/shared_mem.rs @@ -1559,6 +1559,7 @@ unsafe impl Send for ReadonlySharedMemory {} unsafe impl Sync for ReadonlySharedMemory {} impl ReadonlySharedMemory { + #[cfg(any(test, hvf))] pub(crate) fn from_bytes(contents: &[u8], guest_mapped_size: usize) -> Result { if guest_mapped_size > contents.len() || !guest_mapped_size.is_multiple_of(page_size::get()) { diff --git a/src/hyperlight_host/src/sandbox/snapshot/mod.rs b/src/hyperlight_host/src/sandbox/snapshot/mod.rs index 8dfff24ba..aaed10e2d 100644 --- a/src/hyperlight_host/src/sandbox/snapshot/mod.rs +++ b/src/hyperlight_host/src/sandbox/snapshot/mod.rs @@ -33,7 +33,7 @@ use crate::mem::exe::{ExeInfo, LoadInfo}; use crate::mem::layout::SandboxMemoryLayout; use crate::mem::memory_region::MemoryRegionFlags; use crate::mem::mgr::{BackingSource, GuestBacking, GuestPageTableBuffer, GuestPhysicalMemoryView}; -use crate::mem::shared_mem::{ExclusiveSharedMemory, ReadonlySharedMemory}; +use crate::mem::shared_mem::ExclusiveSharedMemory; use crate::mem::virtq::VirtqSnapshot; use crate::sandbox::SandboxConfiguration; use crate::sandbox::uninitialized::{GuestBinary, GuestEnvironment}; @@ -610,18 +610,6 @@ impl Snapshot { layout.set_code_gva(code_gva)?; let regions = layout.get_memory_regions()?; - let mut memory = vec![0; layout.get_memory_size()?]; - - let load_info = exe_info.load( - layout.get_guest_code_gva() as u64, - &mut memory[layout.guest_code_offset()..], - )?; - - layout.write_peb(&mut memory)?; - - blob.map(|x| layout.write_init_data(&mut memory, x.data)) - .transpose()?; - // Set up page table entries for the snapshot let pt_buf = GuestPageTableBuffer::new(layout.get_pt_base_gpa() as usize); @@ -675,13 +663,25 @@ impl Snapshot { .ok_or_else(|| crate::new_error!("ELF entrypoint GVA overflows"))?; // The page tables follow the data, which is padded to a host page. - let data_len = memory - .len() - .next_multiple_of(self::memory::host_page_size()); - memory.resize(data_len, 0); - memory.extend_from_slice(&pt_bytes); + let host_page_size = self::memory::host_page_size(); + let data_len = layout.get_memory_size()?.next_multiple_of(host_page_size); + let mut memory = ExclusiveSharedMemory::new( + (data_len + pt_bytes.len()).next_multiple_of(host_page_size), + )?; + let data = &mut memory.as_mut_slice()[..data_len]; + + let load_info = exe_info.load( + layout.get_guest_code_gva() as u64, + &mut data[layout.guest_code_offset()..], + )?; + + layout.write_peb(data)?; + + blob.map(|x| layout.write_init_data(data, x.data)) + .transpose()?; + memory.copy_from_slice(&pt_bytes, data_len)?; let memory = Arc::new(SnapshotMemory::from_flat( - ReadonlySharedMemory::from_bytes(&memory, data_len)?, + memory.freeze(data_len)?, SandboxMemoryLayout::BASE_ADDRESS as u64, pt_bytes.len(), scratch_base_gpa(layout.get_scratch_size()),