@@ -14,6 +14,9 @@ See the License for the specific language governing permissions and
1414limitations under the License. 
1515*/ 
1616
17+ use  std:: mem:: MaybeUninit ; 
18+ use  std:: os:: unix:: ffi:: OsStrExt ; 
19+ use  std:: path:: Path ; 
1720use  std:: sync:: { Arc ,  Mutex } ; 
1821
1922use  hyperlight_common:: flatbuffer_wrappers:: function_call:: { FunctionCall ,  FunctionCallType } ; 
@@ -31,12 +34,13 @@ use crate::func::{ParameterTuple, SupportedReturnType};
3134use  crate :: hypervisor:: handlers:: DbgMemAccessHandlerWrapper ; 
3235use  crate :: hypervisor:: handlers:: { MemAccessHandlerCaller ,  OutBHandlerCaller } ; 
3336use  crate :: hypervisor:: { Hypervisor ,  InterruptHandle } ; 
37+ use  crate :: mem:: memory_region:: { MemoryRegion ,  MemoryRegionFlags ,  MemoryRegionType } ; 
3438use  crate :: mem:: ptr:: RawPtr ; 
3539use  crate :: mem:: shared_mem:: HostSharedMemory ; 
3640use  crate :: metrics:: maybe_time_and_emit_guest_call; 
3741use  crate :: sandbox_state:: sandbox:: { DevolvableSandbox ,  EvolvableSandbox ,  Sandbox } ; 
3842use  crate :: sandbox_state:: transition:: { MultiUseContextCallback ,  Noop } ; 
39- use  crate :: { HyperlightError ,  Result } ; 
43+ use  crate :: { HyperlightError ,  Result ,  log_then_return } ; 
4044
4145/// A sandbox that supports being used Multiple times. 
4246/// The implication of being used multiple times is two-fold: 
@@ -173,6 +177,80 @@ impl MultiUseSandbox {
173177        } ) 
174178    } 
175179
180+     /// Map a region of host memory into the sandbox. 
181+      /// 
182+      /// Depending on the host platform, there are likely alignment 
183+      /// requirements of at least one page for base and len. 
184+      /// 
185+      /// `rgn.region_type` is ignored, since guest PTEs are not created 
186+      /// for the new memory. 
187+      /// 
188+      /// It is the caller's responsibility to ensure that the host side 
189+      /// of the region remains intact and is not written to until this 
190+      /// mapping is removed, either due to the destruction of the 
191+      /// sandbox or due to a state rollback 
192+      #[ instrument( err( Debug ) ,  skip( self ,  rgn) ,  parent = Span :: current( ) ) ]  
193+     pub  unsafe  fn  map_region ( & mut  self ,  rgn :  & MemoryRegion )  -> Result < ( ) >  { 
194+         if  rgn. flags . contains ( MemoryRegionFlags :: STACK_GUARD )  { 
195+             // Stack guard pages are an internal implementation detail 
196+             // (which really should be moved into the guest) 
197+             log_then_return ! ( "Cannot map host memory as a stack guard page" ) ; 
198+         } 
199+         if  rgn. flags . contains ( MemoryRegionFlags :: WRITE )  { 
200+             // TODO: Implement support for writable mappings, which 
201+             // need to be registered with the memory manager so that 
202+             // writes can be rolled back when necessary. 
203+             log_then_return ! ( "TODO: Writable mappings not yet supported" ) ; 
204+         } 
205+         unsafe  {  self . vm . map_region ( rgn)  } ?; 
206+         self . mem_mgr . unwrap_mgr_mut ( ) . mapped_rgns  += 1 ; 
207+         Ok ( ( ) ) 
208+     } 
209+ 
210+     /// Map the contents of a file into the guest at a particular address 
211+      /// 
212+      /// Returns the length of the mapping 
213+      #[ instrument( err( Debug ) ,  skip( self ,  fp,  guest_base) ,  parent = Span :: current( ) ) ]  
214+     pub ( crate )  fn  map_file_cow ( & mut  self ,  fp :  & Path ,  guest_base :  u64 )  -> Result < u64 >  { 
215+         #[ cfg( windows) ]  
216+         log_then_return ! ( "mmap'ing a file into the guest is not yet supported on Windows" ) ; 
217+         unsafe  { 
218+             let  fd = libc:: open ( 
219+                 std:: ffi:: CString :: new ( fp. as_os_str ( ) . as_bytes ( ) ) ?. as_ptr ( ) , 
220+                 libc:: O_RDWR , 
221+             ) ; 
222+             if  fd < 0  { 
223+                 log_then_return ! ( "open error: {:?}" ,  std:: io:: Error :: last_os_error( ) ) ; 
224+             } 
225+             let  mut  st = MaybeUninit :: < libc:: stat > :: uninit ( ) ; 
226+             libc:: fstat ( fd,  st. as_mut_ptr ( ) ) ; 
227+             let  st = st. assume_init ( ) ; 
228+             let  page_size = page_size:: get ( ) ; 
229+             let  size = ( st. st_size  as  usize ) . div_ceil ( page_size)  *  page_size; 
230+             let  base = libc:: mmap ( 
231+                 std:: ptr:: null_mut ( ) , 
232+                 size, 
233+                 libc:: PROT_READ  | libc:: PROT_WRITE  | libc:: PROT_EXEC , 
234+                 libc:: MAP_PRIVATE , 
235+                 fd, 
236+                 0 , 
237+             ) ; 
238+             if  base == libc:: MAP_FAILED  { 
239+                 log_then_return ! ( "mmap error: {:?}" ,  std:: io:: Error :: last_os_error( ) ) ; 
240+             } 
241+             libc:: close ( fd) ; 
242+ 
243+             self . map_region ( & MemoryRegion  { 
244+                 host_region :  base as  usize ..base. wrapping_add ( size)  as  usize , 
245+                 guest_region :  guest_base as  usize ..guest_base as  usize  + size, 
246+                 flags :  MemoryRegionFlags :: READ  | MemoryRegionFlags :: EXECUTE , 
247+                 region_type :  MemoryRegionType :: Heap , 
248+             } ) ?; 
249+ 
250+             Ok ( size as  u64 ) 
251+         } 
252+     } 
253+ 
176254    /// This function is kept here for fuzz testing the parameter and return types 
177255     #[ cfg( feature = "fuzzing" ) ]  
178256    #[ instrument( err( Debug ) ,  skip( self ,  args) ,  parent = Span :: current( ) ) ]  
@@ -193,7 +271,9 @@ impl MultiUseSandbox {
193271     #[ instrument( err( Debug ) ,  skip_all,  parent = Span :: current( ) ,  level = "Trace" ) ]  
194272    pub ( crate )  fn  restore_state ( & mut  self )  -> Result < ( ) >  { 
195273        let  mem_mgr = self . mem_mgr . unwrap_mgr_mut ( ) ; 
196-         mem_mgr. restore_state_from_last_snapshot ( ) 
274+         let  rgns_to_unmap = mem_mgr. restore_state_from_last_snapshot ( ) ?; 
275+         unsafe  {  self . vm . unmap_regions ( rgns_to_unmap) ? } ; 
276+         Ok ( ( ) ) 
197277    } 
198278
199279    pub ( crate )  fn  call_guest_function_by_name_no_reset ( 
@@ -275,9 +355,11 @@ impl DevolvableSandbox<MultiUseSandbox, MultiUseSandbox, Noop<MultiUseSandbox, M
275355     /// The devolve can be used to return the MultiUseSandbox to the state before the code was loaded. Thus avoiding initialisation overhead 
276356     #[ instrument( err( Debug ) ,  skip_all,  parent = Span :: current( ) ,  level = "Trace" ) ]  
277357    fn  devolve ( mut  self ,  _tsn :  Noop < MultiUseSandbox ,  MultiUseSandbox > )  -> Result < MultiUseSandbox >  { 
278-         self . mem_mgr 
358+         let  rgns_to_unmap = self 
359+             . mem_mgr 
279360            . unwrap_mgr_mut ( ) 
280361            . pop_and_restore_state_from_snapshot ( ) ?; 
362+         unsafe  {  self . vm . unmap_regions ( rgns_to_unmap) ? } ; 
281363        Ok ( self ) 
282364    } 
283365} 
0 commit comments