@@ -568,6 +568,32 @@ impl MultiUseSandbox {
568568 // writes can be rolled back when necessary.
569569 log_then_return ! ( "TODO: Writable mappings not yet supported" ) ;
570570 }
571+
572+ // Validate no overlap with sandbox shared memory
573+ let shared_size = self . mem_mgr . shared_mem . mem_size ( ) ;
574+ let base_addr = crate :: mem:: layout:: SandboxMemoryLayout :: BASE_ADDRESS ;
575+ let shared_end = base_addr + shared_size;
576+ let rgn_start = rgn. guest_region . start ;
577+ let rgn_end = rgn. guest_region . end ;
578+ if rgn_start < shared_end && rgn_end > base_addr {
579+ return Err ( crate :: HyperlightError :: Error ( format ! (
580+ "Overlapping: region [{:#x}..{:#x}) overlaps sandbox memory [{:#x}..{:#x})" ,
581+ rgn_start, rgn_end, base_addr, shared_end,
582+ ) ) ) ;
583+ }
584+
585+ // Validate no overlap with existing mapped regions
586+ for existing in self . vm . get_mapped_regions ( ) {
587+ let ex_start = existing. guest_region . start ;
588+ let ex_end = existing. guest_region . end ;
589+ if rgn_start < ex_end && rgn_end > ex_start {
590+ return Err ( crate :: HyperlightError :: Error ( format ! (
591+ "Overlapping: region [{:#x}..{:#x}) overlaps existing [{:#x}..{:#x})" ,
592+ rgn_start, rgn_end, ex_start, ex_end,
593+ ) ) ) ;
594+ }
595+ }
596+
571597 // Reset snapshot since we are mutating the sandbox state
572598 self . snapshot = None ;
573599 unsafe { self . vm . map_region ( rgn) } . map_err ( HyperlightVmError :: MapRegion ) ?;
@@ -2588,4 +2614,99 @@ mod tests {
25882614 }
25892615 let _ = std:: fs:: remove_file ( & path) ;
25902616 }
2617+
2618+ #[ test]
2619+ fn map_region_rejects_overlapping_regions ( ) {
2620+ let mut sbox: MultiUseSandbox = {
2621+ let path = simple_guest_as_string ( ) . unwrap ( ) ;
2622+ let u_sbox = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None ) . unwrap ( ) ;
2623+ u_sbox. evolve ( ) . unwrap ( )
2624+ } ;
2625+
2626+ let mem1 = allocate_guest_memory ( ) ;
2627+ let mem2 = allocate_guest_memory ( ) ;
2628+ let guest_base: usize = 0x200000000 ;
2629+ let region1 = region_for_memory ( & mem1, guest_base, MemoryRegionFlags :: READ ) ;
2630+
2631+ // First mapping should succeed
2632+ unsafe { sbox. map_region ( & region1) . unwrap ( ) } ;
2633+
2634+ // Exact same range should fail
2635+ let region2 = region_for_memory ( & mem2, guest_base, MemoryRegionFlags :: READ ) ;
2636+ let err = unsafe { sbox. map_region ( & region2) } . unwrap_err ( ) ;
2637+ assert ! (
2638+ format!( "{err:?}" ) . contains( "Overlapping" ) ,
2639+ "Expected Overlapping error, got: {err:?}"
2640+ ) ;
2641+ }
2642+
2643+ #[ test]
2644+ fn map_region_rejects_partial_overlap ( ) {
2645+ let mut sbox: MultiUseSandbox = {
2646+ let path = simple_guest_as_string ( ) . unwrap ( ) ;
2647+ let u_sbox = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None ) . unwrap ( ) ;
2648+ u_sbox. evolve ( ) . unwrap ( )
2649+ } ;
2650+
2651+ // Use multi-page regions so partial overlap is geometrically possible
2652+ let mem1 = page_aligned_memory ( & [ 0xAA ; 8192 ] ) ; // 2 pages
2653+ let mem2 = page_aligned_memory ( & [ 0xBB ; 8192 ] ) ; // 2 pages
2654+ let guest_base: usize = 0x200000000 ;
2655+ let region1 = region_for_memory ( & mem1, guest_base, MemoryRegionFlags :: READ ) ;
2656+
2657+ unsafe { sbox. map_region ( & region1) . unwrap ( ) } ;
2658+
2659+ // region2 starts one page before region1, overlapping by one page
2660+ let overlap_base = guest_base - 0x1000 ;
2661+ let region2 = region_for_memory ( & mem2, overlap_base, MemoryRegionFlags :: READ ) ;
2662+ let err = unsafe { sbox. map_region ( & region2) } . unwrap_err ( ) ;
2663+ assert ! (
2664+ format!( "{err:?}" ) . contains( "verlap" ) ,
2665+ "Expected overlap error for partial overlap, got: {err:?}"
2666+ ) ;
2667+ }
2668+
2669+ #[ test]
2670+ fn map_region_allows_adjacent_non_overlapping ( ) {
2671+ let mut sbox: MultiUseSandbox = {
2672+ let path = simple_guest_as_string ( ) . unwrap ( ) ;
2673+ let u_sbox = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None ) . unwrap ( ) ;
2674+ u_sbox. evolve ( ) . unwrap ( )
2675+ } ;
2676+
2677+ let mem1 = allocate_guest_memory ( ) ;
2678+ let mem2 = allocate_guest_memory ( ) ;
2679+ let guest_base: usize = 0x200000000 ;
2680+ let region1 = region_for_memory ( & mem1, guest_base, MemoryRegionFlags :: READ ) ;
2681+ let region_size = mem1. mem_size ( ) ;
2682+
2683+ unsafe { sbox. map_region ( & region1) . unwrap ( ) } ;
2684+
2685+ // Adjacent region (starts right after the first one ends) should succeed
2686+ let adjacent_base = guest_base + region_size;
2687+ let region2 = region_for_memory ( & mem2, adjacent_base, MemoryRegionFlags :: READ ) ;
2688+ unsafe { sbox. map_region ( & region2) . unwrap ( ) } ;
2689+ }
2690+
2691+ #[ test]
2692+ fn map_region_rejects_overlap_with_snapshot ( ) {
2693+ let mut sbox: MultiUseSandbox = {
2694+ let path = simple_guest_as_string ( ) . unwrap ( ) ;
2695+ let u_sbox = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None ) . unwrap ( ) ;
2696+ u_sbox. evolve ( ) . unwrap ( )
2697+ } ;
2698+
2699+ // Try to map at BASE_ADDRESS (0x1000) which overlaps the snapshot region
2700+ let mem = allocate_guest_memory ( ) ;
2701+ let region = region_for_memory (
2702+ & mem,
2703+ crate :: mem:: layout:: SandboxMemoryLayout :: BASE_ADDRESS ,
2704+ MemoryRegionFlags :: READ ,
2705+ ) ;
2706+ let err = unsafe { sbox. map_region ( & region) } . unwrap_err ( ) ;
2707+ assert ! (
2708+ format!( "{err:?}" ) . contains( "Overlapping" ) ,
2709+ "Expected Overlapping error for snapshot overlap, got: {err:?}"
2710+ ) ;
2711+ }
25912712}
0 commit comments