From b7b2c2efab55cb2f05206a6465ceef4418ed84e6 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Tue, 14 Apr 2026 13:53:25 -0700 Subject: [PATCH 1/2] fix: zero-fill NOBITS sections in ELF loader Some linkers emit PT_LOAD segments where filesz == memsz but contain .bss sections whose VMA range overlaps with file bytes from unrelated sections. The loader copies the full segment verbatim, leaving .bss with stale data instead of zeros. Collect NOBITS section ranges (excluding .tbss) during ELF parsing and zero-fill them after loading PT_LOAD segments. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Co-authored-by: danbugs --- src/hyperlight_host/src/mem/elf.rs | 37 ++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/hyperlight_host/src/mem/elf.rs b/src/hyperlight_host/src/mem/elf.rs index 16e506eac..7d3d0fb96 100644 --- a/src/hyperlight_host/src/mem/elf.rs +++ b/src/hyperlight_host/src/mem/elf.rs @@ -21,10 +21,7 @@ use std::sync::Arc; use goblin::elf::reloc::{R_AARCH64_NONE, R_AARCH64_RELATIVE}; #[cfg(target_arch = "x86_64")] use goblin::elf::reloc::{R_X86_64_NONE, R_X86_64_RELATIVE}; -use goblin::elf::{Elf, ProgramHeaders, Reloc}; -#[cfg(feature = "nanvix-unstable")] -use goblin::elf32::program_header::PT_LOAD; -#[cfg(not(feature = "nanvix-unstable"))] +use goblin::elf::{Elf, ProgramHeaders, Reloc, section_header}; use goblin::elf64::program_header::PT_LOAD; use super::exe::LoadInfo; @@ -45,6 +42,8 @@ pub(crate) struct ElfInfo { shdrs: Vec, entry: u64, relocs: Vec, + /// (addr, size) of NOBITS sections that need zero-filling (excludes .tbss). + nobits_ranges: Vec<(u64, u64)>, /// The hyperlight version string embedded by `hyperlight-guest-bin`, if /// present. Used to detect version/ABI mismatches between guest and host. guest_bin_version: Option, @@ -128,6 +127,20 @@ impl ElfInfo { // hyperlight-guest-bin. let guest_bin_version = Self::read_version_note(&elf, bytes); + // Collect NOBITS sections (e.g. .bss) that need zero-filling. + // Skip .tbss (SHF_TLS) since thread-local BSS is allocated per-thread. + let nobits_ranges: Vec<(u64, u64)> = { + elf.section_headers + .iter() + .filter(|sh| { + sh.sh_type == section_header::SHT_NOBITS + && sh.sh_size > 0 + && (sh.sh_flags & u64::from(section_header::SHF_TLS)) == 0 + }) + .map(|sh| (sh.sh_addr, sh.sh_size)) + .collect() + }; + Ok(ElfInfo { payload: bytes.to_vec(), phdrs: elf.program_headers, @@ -146,6 +159,7 @@ impl ElfInfo { .collect(), entry: elf.entry, relocs, + nobits_ranges, guest_bin_version, }) } @@ -206,6 +220,21 @@ impl ElfInfo { .copy_from_slice(&self.payload[payload_offset..payload_offset + payload_len]); target[start_va + payload_len..start_va + phdr.p_memsz as usize].fill(0); } + // Zero-fill NOBITS sections (e.g. .bss) that were not already + // covered by the filesz < memsz zeroing above. + for &(addr, size) in &self.nobits_ranges { + let sh_start = (addr - base_va) as usize; + let sh_end = sh_start + size as usize; + if sh_end <= target.len() { + target[sh_start..sh_end].fill(0); + } else { + tracing::warn!( + "NOBITS section at VA {:#x} (size {:#x}) extends past loaded image, skipping zero-fill", + addr, + size + ); + } + } let get_addend = |name, r: &Reloc| { r.r_addend .ok_or_else(|| new_error!("{} missing addend", name)) From ed50d48fe4dfdb8c669e3681eb023c85c3d8252f Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Tue, 14 Apr 2026 14:18:39 -0700 Subject: [PATCH 2/2] refactor: remove PEB file_mappings and related code Remove the nanvix-unstable-gated file_mappings field from HyperlightPEB and all host-side code that wrote to it: - write_file_mapping_entry in mgr.rs - PEB layout calculations (array sizing, heap offset, getter methods) - PEB file_mapping writes in write_peb and map_file_cow - 3 PEB test functions (multiuse, deferred, multiple_entries) - evolve-time write_file_mapping_entry call Embedders that need file mapping metadata can pass it through init_data instead of the PEB struct. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Co-authored-by: danbugs --- src/hyperlight_common/src/mem.rs | 7 - src/hyperlight_host/src/mem/layout.rs | 89 +----- src/hyperlight_host/src/mem/mgr.rs | 63 ---- .../src/sandbox/file_mapping.rs | 2 +- .../src/sandbox/initialized_multi_use.rs | 287 +----------------- .../src/sandbox/uninitialized_evolve.rs | 9 - 6 files changed, 4 insertions(+), 453 deletions(-) diff --git a/src/hyperlight_common/src/mem.rs b/src/hyperlight_common/src/mem.rs index fb850acc8..d577c7954 100644 --- a/src/hyperlight_common/src/mem.rs +++ b/src/hyperlight_common/src/mem.rs @@ -72,11 +72,4 @@ pub struct HyperlightPEB { pub output_stack: GuestMemoryRegion, pub init_data: GuestMemoryRegion, pub guest_heap: GuestMemoryRegion, - /// File mappings array descriptor. - /// **Note:** `size` holds the **entry count** (number of valid - /// [`FileMappingInfo`] entries), NOT a byte size. `ptr` holds the - /// guest address of the preallocated array (immediately after the - /// PEB struct). - #[cfg(feature = "nanvix-unstable")] - pub file_mappings: GuestMemoryRegion, } diff --git a/src/hyperlight_host/src/mem/layout.rs b/src/hyperlight_host/src/mem/layout.rs index b55189969..2177848c8 100644 --- a/src/hyperlight_host/src/mem/layout.rs +++ b/src/hyperlight_host/src/mem/layout.rs @@ -227,8 +227,6 @@ pub(crate) struct SandboxMemoryLayout { peb_output_data_offset: usize, peb_init_data_offset: usize, peb_heap_data_offset: usize, - #[cfg(feature = "nanvix-unstable")] - peb_file_mappings_offset: usize, guest_heap_buffer_offset: usize, init_data_offset: usize, @@ -281,11 +279,6 @@ impl Debug for SandboxMemoryLayout { "Guest Heap Offset", &format_args!("{:#x}", self.peb_heap_data_offset), ); - #[cfg(feature = "nanvix-unstable")] - ff.field( - "File Mappings Offset", - &format_args!("{:#x}", self.peb_file_mappings_offset), - ); ff.field( "Guest Heap Buffer Offset", &format_args!("{:#x}", self.guest_heap_buffer_offset), @@ -353,29 +346,11 @@ impl SandboxMemoryLayout { let peb_output_data_offset = peb_offset + offset_of!(HyperlightPEB, output_stack); let peb_init_data_offset = peb_offset + offset_of!(HyperlightPEB, init_data); let peb_heap_data_offset = peb_offset + offset_of!(HyperlightPEB, guest_heap); - #[cfg(feature = "nanvix-unstable")] - let peb_file_mappings_offset = peb_offset + offset_of!(HyperlightPEB, file_mappings); // The following offsets are the actual values that relate to memory layout, // which are written to PEB struct let peb_address = Self::BASE_ADDRESS + peb_offset; // make sure heap buffer starts at 4K boundary. - // The FileMappingInfo array is stored immediately after the PEB struct. - // We statically reserve space for MAX_FILE_MAPPINGS entries so that - // the heap never overlaps the array, even when all slots are used. - // The host writes file mapping metadata here via write_file_mapping_entry; - // the guest only reads the entries. We don't know at layout time how - // many file mappings the host will register, so we reserve space for - // the maximum number. - // The heap starts at the next page boundary after this reserved area. - #[cfg(feature = "nanvix-unstable")] - let file_mappings_array_end = peb_offset - + size_of::() - + hyperlight_common::mem::MAX_FILE_MAPPINGS - * size_of::(); - #[cfg(feature = "nanvix-unstable")] - let guest_heap_buffer_offset = file_mappings_array_end.next_multiple_of(PAGE_SIZE_USIZE); - #[cfg(not(feature = "nanvix-unstable"))] let guest_heap_buffer_offset = (peb_offset + size_of::()).next_multiple_of(PAGE_SIZE_USIZE); @@ -389,8 +364,6 @@ impl SandboxMemoryLayout { peb_output_data_offset, peb_init_data_offset, peb_heap_data_offset, - #[cfg(feature = "nanvix-unstable")] - peb_file_mappings_offset, sandbox_memory_config: cfg, code_size, guest_heap_buffer_offset, @@ -514,32 +487,6 @@ impl SandboxMemoryLayout { self.peb_heap_data_offset } - /// Get the offset in guest memory to the file_mappings count field - /// (the `size` field of the `GuestMemoryRegion` in the PEB). - #[cfg(feature = "nanvix-unstable")] - pub(crate) fn get_file_mappings_size_offset(&self) -> usize { - self.peb_file_mappings_offset - } - - /// Get the offset in guest memory to the file_mappings pointer field. - #[cfg(feature = "nanvix-unstable")] - fn get_file_mappings_pointer_offset(&self) -> usize { - self.get_file_mappings_size_offset() + size_of::() - } - - /// Get the offset in snapshot memory where the FileMappingInfo array starts - /// (immediately after the PEB struct, within the same page). - #[cfg(feature = "nanvix-unstable")] - pub(crate) fn get_file_mappings_array_offset(&self) -> usize { - self.peb_offset + size_of::() - } - - /// Get the guest address of the FileMappingInfo array. - #[cfg(feature = "nanvix-unstable")] - fn get_file_mappings_array_gva(&self) -> u64 { - (Self::BASE_ADDRESS + self.get_file_mappings_array_offset()) as u64 - } - /// Get the offset of the heap pointer in guest memory, #[instrument(skip_all, parent = Span::current(), level= "Trace")] fn get_heap_pointer_offset(&self) -> usize { @@ -643,19 +590,7 @@ impl SandboxMemoryLayout { )); } - // PEB + preallocated FileMappingInfo array - #[cfg(feature = "nanvix-unstable")] - let heap_offset = { - let peb_and_array_size = size_of::() - + hyperlight_common::mem::MAX_FILE_MAPPINGS - * size_of::(); - builder.push_page_aligned( - peb_and_array_size, - MemoryRegionFlags::READ | MemoryRegionFlags::WRITE, - Peb, - ) - }; - #[cfg(not(feature = "nanvix-unstable"))] + // PEB let heap_offset = builder.push_page_aligned(size_of::(), MemoryRegionFlags::READ, Peb); @@ -796,21 +731,6 @@ impl SandboxMemoryLayout { write_u64(mem, self.get_heap_size_offset(), self.heap_size.try_into()?)?; write_u64(mem, self.get_heap_pointer_offset(), addr)?; - // Set up the file_mappings descriptor in the PEB. - // - The `size` field holds the number of valid FileMappingInfo - // entries currently written (initially 0 — entries are added - // later by map_file_cow / evolve). - // - The `ptr` field holds the guest address of the preallocated - // FileMappingInfo array - #[cfg(feature = "nanvix-unstable")] - write_u64(mem, self.get_file_mappings_size_offset(), 0)?; - #[cfg(feature = "nanvix-unstable")] - write_u64( - mem, - self.get_file_mappings_pointer_offset(), - self.get_file_mappings_array_gva(), - )?; - // End of setting up the PEB // The input and output data regions do not have their layout @@ -865,12 +785,7 @@ mod tests { // in order of layout expected_size += layout.code_size; - // PEB + preallocated FileMappingInfo array - #[cfg(feature = "nanvix-unstable")] - let peb_and_array = size_of::() - + hyperlight_common::mem::MAX_FILE_MAPPINGS - * size_of::(); - #[cfg(not(feature = "nanvix-unstable"))] + // PEB let peb_and_array = size_of::(); expected_size += peb_and_array.next_multiple_of(PAGE_SIZE_USIZE); diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 98c70734b..dddab493a 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -13,8 +13,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -#[cfg(feature = "nanvix-unstable")] -use std::mem::offset_of; use flatbuffers::FlatBufferBuilder; use hyperlight_common::flatbuffer_wrappers::function_call::{ @@ -339,67 +337,6 @@ impl SandboxMemoryManager { } impl SandboxMemoryManager { - /// Write a [`FileMappingInfo`] entry into the PEB's preallocated array. - /// - /// Reads the current entry count from the PEB, validates that the - /// array isn't full ([`MAX_FILE_MAPPINGS`]), writes the entry at the - /// next available slot, and increments the count. - /// - /// This is the **only** place that writes to the PEB file mappings - /// array — both `MultiUseSandbox::map_file_cow` and the evolve loop - /// call through here so the logic is not duplicated. - /// - /// # Errors - /// - /// Returns an error if [`MAX_FILE_MAPPINGS`] has been reached. - /// - /// [`FileMappingInfo`]: hyperlight_common::mem::FileMappingInfo - /// [`MAX_FILE_MAPPINGS`]: hyperlight_common::mem::MAX_FILE_MAPPINGS - #[cfg(feature = "nanvix-unstable")] - pub(crate) fn write_file_mapping_entry( - &mut self, - guest_addr: u64, - size: u64, - label: &[u8; hyperlight_common::mem::FILE_MAPPING_LABEL_MAX_LEN + 1], - ) -> Result<()> { - use hyperlight_common::mem::{FileMappingInfo, MAX_FILE_MAPPINGS}; - - // Read the current entry count from the PEB. This is the source - // of truth — it survives snapshot/restore because the PEB is - // part of shared memory that gets snapshotted. - let current_count = - self.shared_mem - .read::(self.layout.get_file_mappings_size_offset())? as usize; - - if current_count >= MAX_FILE_MAPPINGS { - return Err(crate::new_error!( - "file mapping limit reached ({} of {})", - current_count, - MAX_FILE_MAPPINGS, - )); - } - - // Write the entry into the next available slot. - let entry_offset = self.layout.get_file_mappings_array_offset() - + current_count * std::mem::size_of::(); - let guest_addr_offset = offset_of!(FileMappingInfo, guest_addr); - let size_offset = offset_of!(FileMappingInfo, size); - let label_offset = offset_of!(FileMappingInfo, label); - self.shared_mem - .write::(entry_offset + guest_addr_offset, guest_addr)?; - self.shared_mem - .write::(entry_offset + size_offset, size)?; - self.shared_mem - .copy_from_slice(label, entry_offset + label_offset)?; - - // Increment the entry count. - let new_count = (current_count + 1) as u64; - self.shared_mem - .write::(self.layout.get_file_mappings_size_offset(), new_count)?; - - Ok(()) - } - /// Reads a host function call from memory #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] pub(crate) fn get_host_function_call(&mut self) -> Result { diff --git a/src/hyperlight_host/src/sandbox/file_mapping.rs b/src/hyperlight_host/src/sandbox/file_mapping.rs index 1ebe1f262..9b26ae879 100644 --- a/src/hyperlight_host/src/sandbox/file_mapping.rs +++ b/src/hyperlight_host/src/sandbox/file_mapping.rs @@ -58,7 +58,7 @@ pub(crate) struct PreparedFileMapping { /// The page-aligned size of the mapping in bytes. pub(crate) size: usize, /// Null-terminated C-style label for this mapping (max 63 chars + null). - #[cfg_attr(not(feature = "nanvix-unstable"), allow(unused))] + #[allow(unused)] pub(crate) label: [u8; hyperlight_common::mem::FILE_MAPPING_LABEL_MAX_LEN + 1], /// Host-side OS resources. `None` after successful consumption /// by the apply step (ownership transferred to the VM layer). diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 72de96035..bbc4806f0 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -560,23 +560,6 @@ impl MultiUseSandbox { return Err(crate::HyperlightError::PoisonedSandbox); } - // Pre-check the file mapping limit before doing any expensive - // OS or VM work. The PEB count is the source of truth. - #[cfg(feature = "nanvix-unstable")] - let current_count = self - .mem_mgr - .shared_mem - .read::(self.mem_mgr.layout.get_file_mappings_size_offset())? - as usize; - #[cfg(feature = "nanvix-unstable")] - if current_count >= hyperlight_common::mem::MAX_FILE_MAPPINGS { - return Err(crate::HyperlightError::Error(format!( - "map_file_cow: file mapping limit reached ({} of {})", - current_count, - hyperlight_common::mem::MAX_FILE_MAPPINGS, - ))); - } - // Phase 1: host-side OS work (open file, create mapping) let mut prepared = prepare_file_cow(file_path, guest_base, label)?; @@ -636,14 +619,6 @@ impl MultiUseSandbox { prepared.mark_consumed(); self.mem_mgr.mapped_rgns += 1; - // Record the mapping metadata in the PEB. If this fails the VM - // still holds a valid mapping but the PEB won't list it — the - // limit was already pre-checked above so this should not fail - // in practice. - #[cfg(feature = "nanvix-unstable")] - self.mem_mgr - .write_file_mapping_entry(prepared.guest_base, size, &prepared.label)?; - Ok(size) } @@ -2134,267 +2109,7 @@ mod tests { let _ = std::fs::remove_file(&path); } - /// Tests that `map_file_cow` on a MultiUseSandbox correctly writes - /// the FileMappingInfo entry (count, guest_addr, size, label) into - /// the PEB. - #[test] - #[cfg(feature = "nanvix-unstable")] - fn test_map_file_cow_peb_entry_multiuse() { - use std::mem::offset_of; - - use hyperlight_common::mem::{FILE_MAPPING_LABEL_MAX_LEN, FileMappingInfo}; - - let (path, _) = create_test_file("hyperlight_test_peb_entry_multiuse.bin", &[0xDD; 4096]); - - let guest_base: u64 = 0x1_0000_0000; - let label = "my_ramfs"; - - let mut sbox = UninitializedSandbox::new( - GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")), - None, - ) - .unwrap() - .evolve() - .unwrap(); - - // Map with an explicit label. - let mapped_size = sbox.map_file_cow(&path, guest_base, Some(label)).unwrap(); - - // Read back the PEB file_mappings count. - let count = sbox - .mem_mgr - .shared_mem - .read::(sbox.mem_mgr.layout.get_file_mappings_size_offset()) - .unwrap(); - assert_eq!( - count, 1, - "PEB file_mappings count should be 1 after one mapping" - ); - - // Read back the first FileMappingInfo entry. - let entry_offset = sbox.mem_mgr.layout.get_file_mappings_array_offset(); - - let stored_addr = sbox - .mem_mgr - .shared_mem - .read::(entry_offset + offset_of!(FileMappingInfo, guest_addr)) - .unwrap(); - assert_eq!(stored_addr, guest_base, "PEB entry guest_addr should match"); - - let stored_size = sbox - .mem_mgr - .shared_mem - .read::(entry_offset + offset_of!(FileMappingInfo, size)) - .unwrap(); - assert_eq!( - stored_size, mapped_size, - "PEB entry size should match mapped_size" - ); - - // Read back the label bytes and verify. - let label_offset = entry_offset + offset_of!(FileMappingInfo, label); - let mut label_buf = [0u8; FILE_MAPPING_LABEL_MAX_LEN + 1]; - for (i, byte) in label_buf.iter_mut().enumerate() { - *byte = sbox - .mem_mgr - .shared_mem - .read::(label_offset + i) - .unwrap(); - } - let label_len = label_buf - .iter() - .position(|&b| b == 0) - .unwrap_or(label_buf.len()); - let stored_label = std::str::from_utf8(&label_buf[..label_len]).unwrap(); - assert_eq!(stored_label, label, "PEB entry label should match"); - - let _ = std::fs::remove_file(&path); - } - - /// Tests that deferred `map_file_cow` (before evolve) correctly - /// writes FileMappingInfo entries into the PEB during evolve. - #[test] - #[cfg(feature = "nanvix-unstable")] - fn test_map_file_cow_peb_entry_deferred() { - use std::mem::offset_of; - - use hyperlight_common::mem::{FILE_MAPPING_LABEL_MAX_LEN, FileMappingInfo}; - - let (path, _) = create_test_file("hyperlight_test_peb_entry_deferred.bin", &[0xEE; 4096]); - - let guest_base: u64 = 0x1_0000_0000; - let label = "deferred_fs"; - - let mut u_sbox = UninitializedSandbox::new( - GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")), - None, - ) - .unwrap(); - - let mapped_size = u_sbox.map_file_cow(&path, guest_base, Some(label)).unwrap(); - - // Evolve — PEB entries should be written during this step. - let sbox: MultiUseSandbox = u_sbox.evolve().unwrap(); - - // Read back count. - let count = sbox - .mem_mgr - .shared_mem - .read::(sbox.mem_mgr.layout.get_file_mappings_size_offset()) - .unwrap(); - assert_eq!(count, 1, "PEB file_mappings count should be 1 after evolve"); - - // Read back the entry. - let entry_offset = sbox.mem_mgr.layout.get_file_mappings_array_offset(); - - let stored_addr = sbox - .mem_mgr - .shared_mem - .read::(entry_offset + offset_of!(FileMappingInfo, guest_addr)) - .unwrap(); - assert_eq!(stored_addr, guest_base); - - let stored_size = sbox - .mem_mgr - .shared_mem - .read::(entry_offset + offset_of!(FileMappingInfo, size)) - .unwrap(); - assert_eq!(stored_size, mapped_size); - - // Verify the label. - let label_offset = entry_offset + offset_of!(FileMappingInfo, label); - let mut label_buf = [0u8; FILE_MAPPING_LABEL_MAX_LEN + 1]; - for (i, byte) in label_buf.iter_mut().enumerate() { - *byte = sbox - .mem_mgr - .shared_mem - .read::(label_offset + i) - .unwrap(); - } - let label_len = label_buf - .iter() - .position(|&b| b == 0) - .unwrap_or(label_buf.len()); - let stored_label = std::str::from_utf8(&label_buf[..label_len]).unwrap(); - assert_eq!( - stored_label, label, - "PEB entry label should match after evolve" - ); - - let _ = std::fs::remove_file(&path); - } - - /// Tests that mapping 5 files (3 deferred + 2 post-evolve) correctly - /// populates all PEB FileMappingInfo slots with the right guest_addr, - /// size, and label for each entry. - #[test] - #[cfg(feature = "nanvix-unstable")] - fn test_map_file_cow_peb_multiple_entries() { - use std::mem::{offset_of, size_of}; - - use hyperlight_common::mem::{FILE_MAPPING_LABEL_MAX_LEN, FileMappingInfo}; - - const NUM_FILES: usize = 5; - const DEFERRED_COUNT: usize = 3; - - // Create 5 test files with distinct content. - let mut paths = Vec::new(); - let mut labels: Vec = Vec::new(); - for i in 0..NUM_FILES { - let name = format!("hyperlight_test_peb_multi_{}.bin", i); - let content = vec![i as u8 + 0xA0; 4096]; - let (path, _) = create_test_file(&name, &content); - paths.push(path); - labels.push(format!("file_{}", i)); - } - - // Each file gets a unique guest base, spaced 1 page apart - // (well outside the shared memory region). - let page_size = page_size::get() as u64; - let base: u64 = 0x1_0000_0000; - let guest_bases: Vec = (0..NUM_FILES as u64) - .map(|i| base + i * page_size) - .collect(); - - let mut u_sbox = UninitializedSandbox::new( - GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")), - None, - ) - .unwrap(); - - // Map 3 files before evolve (deferred path). - let mut mapped_sizes = Vec::new(); - for i in 0..DEFERRED_COUNT { - let size = u_sbox - .map_file_cow(&paths[i], guest_bases[i], Some(&labels[i])) - .unwrap(); - mapped_sizes.push(size); - } - - // Evolve — deferred mappings applied + PEB entries written. - let mut sbox: MultiUseSandbox = u_sbox.evolve().unwrap(); - - // Map 2 more files post-evolve (MultiUseSandbox path). - for i in DEFERRED_COUNT..NUM_FILES { - let size = sbox - .map_file_cow(&paths[i], guest_bases[i], Some(&labels[i])) - .unwrap(); - mapped_sizes.push(size); - } - - // Verify PEB count equals 5. - let count = sbox - .mem_mgr - .shared_mem - .read::(sbox.mem_mgr.layout.get_file_mappings_size_offset()) - .unwrap(); - assert_eq!( - count, NUM_FILES as u64, - "PEB should have {NUM_FILES} entries" - ); - - // Verify each entry's guest_addr, size, and label. - let array_base = sbox.mem_mgr.layout.get_file_mappings_array_offset(); - for i in 0..NUM_FILES { - let entry_offset = array_base + i * size_of::(); - - let stored_addr = sbox - .mem_mgr - .shared_mem - .read::(entry_offset + offset_of!(FileMappingInfo, guest_addr)) - .unwrap(); - assert_eq!( - stored_addr, guest_bases[i], - "Entry {i}: guest_addr mismatch" - ); - - let stored_size = sbox - .mem_mgr - .shared_mem - .read::(entry_offset + offset_of!(FileMappingInfo, size)) - .unwrap(); - assert_eq!(stored_size, mapped_sizes[i], "Entry {i}: size mismatch"); - - // Read and verify the label. - let label_base = entry_offset + offset_of!(FileMappingInfo, label); - let mut label_buf = [0u8; FILE_MAPPING_LABEL_MAX_LEN + 1]; - for (j, byte) in label_buf.iter_mut().enumerate() { - *byte = sbox.mem_mgr.shared_mem.read::(label_base + j).unwrap(); - } - let label_len = label_buf - .iter() - .position(|&b| b == 0) - .unwrap_or(label_buf.len()); - let stored_label = std::str::from_utf8(&label_buf[..label_len]).unwrap(); - assert_eq!(stored_label, labels[i], "Entry {i}: label mismatch"); - } - - // Clean up. - for path in &paths { - let _ = std::fs::remove_file(path); - } - } - + /// Tests that an explicitly provided label exceeding 63 bytes is rejected. /// Tests that an explicitly provided label exceeding 63 bytes is rejected. #[test] fn test_map_file_cow_label_too_long() { diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index 428594d37..37eb933e2 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -107,15 +107,6 @@ pub(super) fn evolve_impl_multi_use(u_sbox: UninitializedSandbox) -> Result