@@ -17,6 +17,7 @@ limitations under the License.
1717use std:: collections:: { BTreeMap , HashMap } ;
1818use std:: sync:: atomic:: { AtomicU64 , Ordering } ;
1919
20+ use hyperlight_common:: flatbuffer_wrappers:: host_function_details:: HostFunctionDetails ;
2021use hyperlight_common:: layout:: { scratch_base_gpa, scratch_base_gva} ;
2122use hyperlight_common:: vmem;
2223use hyperlight_common:: vmem:: {
@@ -115,6 +116,16 @@ pub struct Snapshot {
115116 /// restored sandbox's guest-visible counter so the guest can tell
116117 /// which snapshot it is currently a clone of.
117118 snapshot_generation : u64 ,
119+
120+ /// Names and signatures of host functions registered on the
121+ /// sandbox at the time this snapshot was taken. Persisted to disk
122+ /// so that [`crate::MultiUseSandbox::from_snapshot`] can reject
123+ /// a `HostFunctions` set that is missing required functions or
124+ /// has mismatched signatures.
125+ ///
126+ /// Empty for snapshots created via test-only constructors that
127+ /// bypass the normal sandbox path.
128+ host_functions : HostFunctionDetails ,
118129}
119130impl core:: convert:: AsRef < Snapshot > for Snapshot {
120131 fn as_ref ( & self ) -> & Self {
@@ -423,6 +434,9 @@ impl Snapshot {
423434 sregs : None ,
424435 entrypoint : NextAction :: Initialise ( load_addr + entrypoint_va - base_va) ,
425436 snapshot_generation : 0 ,
437+ host_functions : HostFunctionDetails {
438+ host_functions : None ,
439+ } ,
426440 } )
427441 }
428442
@@ -447,6 +461,7 @@ impl Snapshot {
447461 sregs : CommonSpecialRegisters ,
448462 entrypoint : NextAction ,
449463 snapshot_generation : u64 ,
464+ host_functions : HostFunctionDetails ,
450465 ) -> Result < Self > {
451466 let mut phys_seen = HashMap :: < u64 , usize > :: new ( ) ;
452467 let scratch_gva = scratch_base_gva ( layout. get_scratch_size ( ) ) ;
@@ -610,6 +625,7 @@ impl Snapshot {
610625 sregs : Some ( sregs) ,
611626 entrypoint,
612627 snapshot_generation,
628+ host_functions,
613629 } )
614630 }
615631
@@ -663,6 +679,65 @@ impl Snapshot {
663679 pub ( crate ) fn entrypoint ( & self ) -> NextAction {
664680 self . entrypoint
665681 }
682+
683+ /// Validate that `provided` is a superset of the host functions
684+ /// recorded in this snapshot: every function that was registered
685+ /// at snapshot time must also be present in `provided` with a
686+ /// matching signature. Extras in `provided` are allowed.
687+ ///
688+ /// Snapshots created in-memory before this field was wired in
689+ /// (or by test-only constructors) carry an empty function set,
690+ /// in which case any `provided` set is accepted.
691+ pub ( crate ) fn validate_host_functions ( & self , provided : & crate :: HostFunctions ) -> Result < ( ) > {
692+ let required = match & self . host_functions . host_functions {
693+ Some ( v) => v,
694+ None => return Ok ( ( ) ) ,
695+ } ;
696+ if required. is_empty ( ) {
697+ return Ok ( ( ) ) ;
698+ }
699+
700+ // Build a HostFunctionDetails view of the provided registry
701+ // using the existing `From<&FunctionRegistry>` impl.
702+ let provided_details: HostFunctionDetails = provided. inner ( ) . into ( ) ;
703+ let provided_funcs = provided_details. host_functions . unwrap_or_default ( ) ;
704+
705+ let mut missing: Vec < String > = Vec :: new ( ) ;
706+ let mut signature_mismatches: Vec < String > = Vec :: new ( ) ;
707+
708+ for req in required {
709+ match provided_funcs
710+ . iter ( )
711+ . find ( |f| f. function_name == req. function_name )
712+ {
713+ None => missing. push ( req. function_name . clone ( ) ) ,
714+ Some ( found)
715+ if found. parameter_types != req. parameter_types
716+ || found. return_type != req. return_type =>
717+ {
718+ signature_mismatches. push ( format ! (
719+ "{}: snapshot has {:?} -> {:?}, registered {:?} -> {:?}" ,
720+ req. function_name,
721+ req. parameter_types,
722+ req. return_type,
723+ found. parameter_types,
724+ found. return_type,
725+ ) ) ;
726+ }
727+ Some ( _) => { }
728+ }
729+ }
730+
731+ if missing. is_empty ( ) && signature_mismatches. is_empty ( ) {
732+ return Ok ( ( ) ) ;
733+ }
734+
735+ Err ( crate :: new_error!(
736+ "snapshot host function mismatch: missing={:?}, signature_mismatches={:?}" ,
737+ missing,
738+ signature_mismatches
739+ ) )
740+ }
666741}
667742
668743impl PartialEq for Snapshot {
@@ -674,6 +749,7 @@ impl PartialEq for Snapshot {
674749#[ cfg( test) ]
675750#[ cfg( not( feature = "i686-guest" ) ) ]
676751mod tests {
752+ use hyperlight_common:: flatbuffer_wrappers:: host_function_details:: HostFunctionDetails ;
677753 use hyperlight_common:: vmem:: { self , BasicMapping , Mapping , MappingKind , PAGE_SIZE } ;
678754
679755 use crate :: hypervisor:: regs:: CommonSpecialRegisters ;
@@ -747,6 +823,7 @@ mod tests {
747823 default_sregs ( ) ,
748824 super :: NextAction :: None ,
749825 1 ,
826+ HostFunctionDetails :: default ( ) ,
750827 )
751828 . unwrap ( ) ;
752829
@@ -764,6 +841,7 @@ mod tests {
764841 default_sregs ( ) ,
765842 super :: NextAction :: None ,
766843 2 ,
844+ HostFunctionDetails :: default ( ) ,
767845 )
768846 . unwrap ( ) ;
769847
0 commit comments