@@ -93,36 +93,55 @@ macro_rules! generate_writer {
9393/// Send or Sync, since it doesn't ensure any particular synchronization.
9494#[ derive( Debug ) ]
9595pub struct HostMapping {
96- ptr : * mut u8 ,
97- size : usize ,
96+ # [ cfg ( not ( target_os = "windows" ) ) ]
97+ mmap : Mmap ,
9898 #[ cfg( target_os = "windows" ) ]
99- handle : HANDLE ,
99+ mapping : WindowsMapping ,
100100}
101101
102- impl Drop for HostMapping {
103- #[ cfg( target_os = "linux" ) ]
104- fn drop ( & mut self ) {
105- use libc:: munmap;
102+ /// Windows-side flavors of a [`HostMapping`].
103+ #[ cfg( target_os = "windows" ) ]
104+ #[ derive( Debug ) ]
105+ enum WindowsMapping {
106+ /// `[guard][blob][guard]` carved from a single anonymous file
107+ /// mapping created via `CreateFileMappingA(INVALID_HANDLE_VALUE)`
108+ /// and mapped with `MapViewOfFile`.
109+ Anonymous {
110+ view : MappedView ,
111+ file_mapping : FileMapping ,
112+ } ,
113+ }
106114
107- unsafe {
108- munmap ( self . ptr as * mut c_void , self . size ) ;
115+ impl HostMapping {
116+ /// Base address of the host mapping, including the surrounding guard pages.
117+ pub ( crate ) fn ptr ( & self ) -> * mut u8 {
118+ #[ cfg( not( target_os = "windows" ) ) ]
119+ {
120+ self . mmap . base as * mut u8
121+ }
122+ #[ cfg( target_os = "windows" ) ]
123+ match & self . mapping {
124+ WindowsMapping :: Anonymous { view, .. } => view. addr as * mut u8 ,
109125 }
110126 }
111- # [ cfg ( target_os = "windows" ) ]
112- fn drop ( & mut self ) {
113- let mem_mapped_address = MEMORY_MAPPED_VIEW_ADDRESS {
114- Value : self . ptr as * mut c_void ,
115- } ;
116- if let Err ( e ) = unsafe { UnmapViewOfFile ( mem_mapped_address ) } {
117- tracing :: error! (
118- "Failed to drop HostMapping (UnmapViewOfFile failed): {:?}" ,
119- e
120- ) ;
127+
128+ /// Total size of the host mapping, including the surrounding guard pages.
129+ pub ( crate ) fn size ( & self ) -> usize {
130+ # [ cfg ( not ( target_os = "windows" ) ) ]
131+ {
132+ self . mmap . len
133+ }
134+ # [ cfg ( target_os = "windows" ) ]
135+ match & self . mapping {
136+ WindowsMapping :: Anonymous { view , .. } => view . len ,
121137 }
138+ }
122139
123- let file_handle: HANDLE = self . handle ;
124- if let Err ( e) = unsafe { CloseHandle ( file_handle) } {
125- tracing:: error!( "Failed to drop HostMapping (CloseHandle failed): {:?}" , e) ;
140+ /// Win32 file-mapping handle backing this mapping.
141+ #[ cfg( target_os = "windows" ) ]
142+ pub ( crate ) fn file_mapping_handle ( & self ) -> HANDLE {
143+ match & self . mapping {
144+ WindowsMapping :: Anonymous { file_mapping, .. } => file_mapping. 0 ,
126145 }
127146 }
128147}
@@ -384,19 +403,23 @@ impl ExclusiveSharedMemory {
384403 Error :: last_os_error( ) . raw_os_error( )
385404 ) ) ;
386405 }
406+ let mmap = Mmap {
407+ base : addr,
408+ len : total_size,
409+ } ;
387410
388411 // protect the guard pages
389412 #[ cfg( not( miri) ) ]
390413 {
391- let res = unsafe { mprotect ( addr , PAGE_SIZE_USIZE , PROT_NONE ) } ;
414+ let res = unsafe { mprotect ( mmap . base , PAGE_SIZE_USIZE , PROT_NONE ) } ;
392415 if res != 0 {
393416 return Err ( HyperlightError :: MprotectFailed (
394417 Error :: last_os_error ( ) . raw_os_error ( ) ,
395418 ) ) ;
396419 }
397420 let res = unsafe {
398421 mprotect (
399- ( addr as * const u8 ) . add ( total_size - PAGE_SIZE_USIZE ) as * mut c_void ,
422+ ( mmap . base as * const u8 ) . add ( total_size - PAGE_SIZE_USIZE ) as * mut c_void ,
400423 PAGE_SIZE_USIZE ,
401424 PROT_NONE ,
402425 )
@@ -418,10 +441,7 @@ impl ExclusiveSharedMemory {
418441 // type does have Send and Sync manually impl'd, the Arc
419442 // is not pointless as the lint suggests.
420443 #[ allow( clippy:: arc_with_non_send_sync) ]
421- region : Arc :: new ( HostMapping {
422- ptr : addr as * mut u8 ,
423- size : total_size,
424- } ) ,
444+ region : Arc :: new ( HostMapping { mmap } ) ,
425445 } )
426446 }
427447
@@ -485,23 +505,28 @@ impl ExclusiveSharedMemory {
485505 Error :: last_os_error( ) . raw_os_error( )
486506 ) ) ;
487507 }
508+ let file_mapping = FileMapping ( handle) ;
488509
489510 let file_map = FILE_MAP_ALL_ACCESS ;
490- let addr = unsafe { MapViewOfFile ( handle , file_map, 0 , 0 , 0 ) } ;
511+ let addr = unsafe { MapViewOfFile ( file_mapping . 0 , file_map, 0 , 0 , 0 ) } ;
491512
492513 if addr. Value . is_null ( ) {
493514 log_then_return ! ( HyperlightError :: MemoryAllocationFailed (
494515 Error :: last_os_error( ) . raw_os_error( )
495516 ) ) ;
496517 }
518+ let view = MappedView {
519+ addr : addr. Value ,
520+ len : total_size,
521+ } ;
497522
498523 // Set the first and last pages to be guard pages
499524
500525 let mut unused_out_old_prot_flags = PAGE_PROTECTION_FLAGS ( 0 ) ;
501526
502527 // If the following calls to VirtualProtect are changed make sure to update the calls to VirtualProtectEx in surrogate_process_manager.rs
503528
504- let first_guard_page_start = addr . Value ;
529+ let first_guard_page_start = view . addr ;
505530 if let Err ( e) = unsafe {
506531 VirtualProtect (
507532 first_guard_page_start,
@@ -513,7 +538,7 @@ impl ExclusiveSharedMemory {
513538 log_then_return ! ( WindowsAPIError ( e. clone( ) ) ) ;
514539 }
515540
516- let last_guard_page_start = unsafe { addr . Value . add ( total_size - PAGE_SIZE_USIZE ) } ;
541+ let last_guard_page_start = unsafe { view . addr . add ( total_size - PAGE_SIZE_USIZE ) } ;
517542 if let Err ( e) = unsafe {
518543 VirtualProtect (
519544 last_guard_page_start,
@@ -536,9 +561,7 @@ impl ExclusiveSharedMemory {
536561 // is not pointless as the lint suggests.
537562 #[ allow( clippy:: arc_with_non_send_sync) ]
538563 region : Arc :: new ( HostMapping {
539- ptr : addr. Value as * mut u8 ,
540- size : total_size,
541- handle,
564+ mapping : WindowsMapping :: Anonymous { view, file_mapping } ,
542565 } ) ,
543566 } )
544567 }
@@ -662,7 +685,7 @@ impl ExclusiveSharedMemory {
662685 /// Gets the file handle of the shared memory region for this Sandbox
663686 #[ cfg( target_os = "windows" ) ]
664687 pub fn get_mmap_file_handle ( & self ) -> HANDLE {
665- self . region . handle
688+ self . region . file_mapping_handle ( )
666689 }
667690
668691 /// Create a [`HostSharedMemory`] view of this region without
@@ -742,34 +765,34 @@ pub trait SharedMemory {
742765 /// need to be marked as `unsafe` because doing anything with this
743766 /// pointer itself requires `unsafe`.
744767 fn base_addr ( & self ) -> usize {
745- self . region ( ) . ptr as usize + PAGE_SIZE_USIZE
768+ self . region ( ) . ptr ( ) as usize + PAGE_SIZE_USIZE
746769 }
747770
748771 /// Return the base address of the host mapping of this region as
749772 /// a pointer. Following the general Rust philosophy, this does
750773 /// not need to be marked as `unsafe` because doing anything with
751774 /// this pointer itself requires `unsafe`.
752775 fn base_ptr ( & self ) -> * mut u8 {
753- self . region ( ) . ptr . wrapping_add ( PAGE_SIZE_USIZE )
776+ self . region ( ) . ptr ( ) . wrapping_add ( PAGE_SIZE_USIZE )
754777 }
755778
756779 /// Return the length of usable memory contained in `self`.
757780 /// The returned size does not include the size of the surrounding
758781 /// guard pages.
759782 fn mem_size ( & self ) -> usize {
760- self . region ( ) . size - 2 * PAGE_SIZE_USIZE
783+ self . region ( ) . size ( ) - 2 * PAGE_SIZE_USIZE
761784 }
762785
763786 /// Return the raw base address of the host mapping, including the
764787 /// guard pages.
765788 fn raw_ptr ( & self ) -> * mut u8 {
766- self . region ( ) . ptr
789+ self . region ( ) . ptr ( )
767790 }
768791
769792 /// Return the raw size of the host mapping, including the guard
770793 /// pages.
771794 fn raw_mem_size ( & self ) -> usize {
772- self . region ( ) . size
795+ self . region ( ) . size ( )
773796 }
774797
775798 /// Extract a base address that can be mapped into a VM for this
@@ -786,9 +809,9 @@ pub trait SharedMemory {
786809 #[ cfg( windows) ]
787810 {
788811 super :: memory_region:: HostRegionBase {
789- from_handle : self . region ( ) . handle . into ( ) ,
790- handle_base : self . region ( ) . ptr as usize ,
791- handle_size : self . region ( ) . size ,
812+ from_handle : self . region ( ) . file_mapping_handle ( ) . into ( ) ,
813+ handle_base : self . region ( ) . ptr ( ) as usize ,
814+ handle_size : self . region ( ) . size ( ) ,
792815 offset : PAGE_SIZE_USIZE ,
793816 }
794817 }
@@ -829,8 +852,8 @@ pub trait SharedMemory {
829852 #[ cfg( all( target_os = "linux" , feature = "kvm" , not( any( feature = "mshv3" ) ) ) ) ]
830853 unsafe {
831854 let ret = libc:: madvise (
832- e. region . ptr as * mut libc:: c_void ,
833- e. region . size ,
855+ e. region . ptr ( ) as * mut libc:: c_void ,
856+ e. region . size ( ) ,
834857 libc:: MADV_DONTNEED ,
835858 ) ;
836859 if ret == 0 {
@@ -2026,6 +2049,75 @@ pub struct ReadonlySharedMemory {
20262049unsafe impl Send for ReadonlySharedMemory { }
20272050unsafe impl Sync for ReadonlySharedMemory { }
20282051
2052+ /// RAII guard for an `mmap` reservation. Calls `munmap` on drop.
2053+ #[ cfg( target_os = "linux" ) ]
2054+ #[ derive( Debug ) ]
2055+ struct Mmap {
2056+ base : * mut c_void ,
2057+ len : usize ,
2058+ }
2059+
2060+ #[ cfg( target_os = "linux" ) ]
2061+ impl Drop for Mmap {
2062+ fn drop ( & mut self ) {
2063+ // SAFETY: `self.base` and `self.len` are exactly what was
2064+ // returned by the `mmap` that produced this `Mmap`, and that
2065+ // mapping has not been unmapped (we own it).
2066+ unsafe {
2067+ if libc:: munmap ( self . base , self . len ) != 0 {
2068+ tracing:: error!(
2069+ "Mmap::drop: munmap failed: {:?}" ,
2070+ std:: io:: Error :: last_os_error( )
2071+ ) ;
2072+ }
2073+ }
2074+ }
2075+ }
2076+
2077+ /// RAII guard for a Win32 mapped view. Calls `UnmapViewOfFile` on drop.
2078+ #[ cfg( target_os = "windows" ) ]
2079+ #[ derive( Debug ) ]
2080+ struct MappedView {
2081+ addr : * mut c_void ,
2082+ len : usize ,
2083+ }
2084+
2085+ #[ cfg( target_os = "windows" ) ]
2086+ impl Drop for MappedView {
2087+ fn drop ( & mut self ) {
2088+ let view = MEMORY_MAPPED_VIEW_ADDRESS { Value : self . addr } ;
2089+ // SAFETY: `self.addr` is the base address returned by the
2090+ // `MapViewOfFile` call that produced this `MappedView`, and
2091+ // the view has not been unmapped (we own it).
2092+ if let Err ( e) = unsafe { UnmapViewOfFile ( view) } {
2093+ tracing:: error!(
2094+ "MappedView::drop(addr={:?}, len={}) UnmapViewOfFile failed: {:?}" ,
2095+ self . addr,
2096+ self . len,
2097+ e
2098+ ) ;
2099+ }
2100+ }
2101+ }
2102+
2103+ /// Owns a Win32 file-mapping `HANDLE`. Calls `CloseHandle` on drop.
2104+ #[ cfg( target_os = "windows" ) ]
2105+ #[ derive( Debug ) ]
2106+ struct FileMapping ( HANDLE ) ;
2107+
2108+ #[ cfg( target_os = "windows" ) ]
2109+ impl Drop for FileMapping {
2110+ fn drop ( & mut self ) {
2111+ // SAFETY: `self.0` is a valid HANDLE returned by
2112+ // `CreateFileMappingA` that has not been closed (we own it).
2113+ unsafe {
2114+ if let Err ( e) = CloseHandle ( self . 0 ) {
2115+ tracing:: error!( "FileMapping::drop: CloseHandle failed: {:?}" , e) ;
2116+ }
2117+ }
2118+ }
2119+ }
2120+
20292121impl ReadonlySharedMemory {
20302122 pub ( crate ) fn from_bytes ( contents : & [ u8 ] ) -> Result < Self > {
20312123 let mut anon = ExclusiveSharedMemory :: new ( contents. len ( ) ) ?;
0 commit comments