@@ -295,16 +295,21 @@ where
295295
296296#[ cfg( test) ]
297297mod tests {
298+ use std:: thread;
299+
298300 use hyperlight_common:: flatbuffer_wrappers:: function_types:: {
299301 ParameterValue , ReturnType , ReturnValue ,
300302 } ;
301- use hyperlight_testing:: simple_guest_as_string;
303+ use hyperlight_testing:: { callback_guest_as_string , simple_guest_as_string} ;
302304
303305 use crate :: func:: call_ctx:: MultiUseGuestCallContext ;
304306 use crate :: sandbox:: SandboxConfiguration ;
305307 use crate :: sandbox_state:: sandbox:: { DevolvableSandbox , EvolvableSandbox } ;
306308 use crate :: sandbox_state:: transition:: { MultiUseContextCallback , Noop } ;
307- use crate :: { GuestBinary , MultiUseSandbox , UninitializedSandbox } ;
309+ use crate :: {
310+ is_hypervisor_present, GuestBinary , HyperlightError , MultiUseSandbox , Result ,
311+ UninitializedSandbox ,
312+ } ;
308313
309314 // Tests to ensure that many (1000) function calls can be made in a call context with a small stack (1K) and heap(14K).
310315 // This test effectively ensures that the stack is being properly reset after each call and we are not leaking memory in the Guest.
@@ -384,4 +389,157 @@ mod tests {
384389 . unwrap ( ) ;
385390 assert_eq ! ( res, ReturnValue :: Int ( 0 ) ) ;
386391 }
392+
393+ #[ test]
394+ // TODO: Investigate why this test fails with an incorrect error when run alongside other tests
395+ #[ ignore]
396+ #[ cfg( target_os = "linux" ) ]
397+ fn test_violate_seccomp_filters ( ) -> Result < ( ) > {
398+ if !is_hypervisor_present ( ) {
399+ panic ! ( "Panic on create_multi_use_sandbox because no hypervisor is present" ) ;
400+ }
401+
402+ fn make_get_pid_syscall ( ) -> Result < u64 > {
403+ let pid = unsafe { libc:: syscall ( libc:: SYS_getpid ) } ;
404+ Ok ( pid as u64 )
405+ }
406+
407+ // First, run to make sure it fails.
408+ {
409+ let mut usbox = UninitializedSandbox :: new (
410+ GuestBinary :: FilePath ( simple_guest_as_string ( ) . expect ( "Guest Binary Missing" ) ) ,
411+ None ,
412+ )
413+ . unwrap ( ) ;
414+
415+ usbox. register ( "MakeGetpidSyscall" , make_get_pid_syscall) ?;
416+
417+ let mut sbox: MultiUseSandbox = usbox. evolve ( Noop :: default ( ) ) ?;
418+
419+ let res =
420+ sbox. call_guest_function_by_name ( "ViolateSeccompFilters" , ReturnType :: ULong , None ) ;
421+
422+ #[ cfg( feature = "seccomp" ) ]
423+ match res {
424+ Ok ( _) => panic ! ( "Expected to fail due to seccomp violation" ) ,
425+ Err ( e) => match e {
426+ HyperlightError :: DisallowedSyscall => { }
427+ _ => panic ! ( "Expected DisallowedSyscall error: {}" , e) ,
428+ } ,
429+ }
430+
431+ #[ cfg( not( feature = "seccomp" ) ) ]
432+ match res {
433+ Ok ( _) => ( ) ,
434+ Err ( e) => panic ! ( "Expected to succeed without seccomp: {}" , e) ,
435+ }
436+ }
437+
438+ // Second, run with allowing `SYS_getpid`
439+ #[ cfg( feature = "seccomp" ) ]
440+ {
441+ let mut usbox = UninitializedSandbox :: new (
442+ GuestBinary :: FilePath ( simple_guest_as_string ( ) . expect ( "Guest Binary Missing" ) ) ,
443+ None ,
444+ )
445+ . unwrap ( ) ;
446+
447+ usbox. register_with_extra_allowed_syscalls (
448+ "MakeGetpidSyscall" ,
449+ make_get_pid_syscall,
450+ vec ! [ libc:: SYS_getpid ] ,
451+ ) ?;
452+ // ^^^ note, we are allowing SYS_getpid
453+
454+ let mut sbox: MultiUseSandbox = usbox. evolve ( Noop :: default ( ) ) ?;
455+
456+ let res =
457+ sbox. call_guest_function_by_name ( "ViolateSeccompFilters" , ReturnType :: ULong , None ) ;
458+
459+ match res {
460+ Ok ( _) => { }
461+ Err ( e) => panic ! ( "Expected to succeed due to seccomp violation: {}" , e) ,
462+ }
463+ }
464+
465+ Ok ( ( ) )
466+ }
467+
468+ // This test is to capture the case where the guest execution is running a host function when cancelled and that host function
469+ // is never going to return.
470+ // The host function that is called will end after 5 seconds, but by this time the cancellation will have given up
471+ // (using default timeout settings) , so this tests looks for the error "Failed to cancel guest execution".
472+ #[ test]
473+ #[ ignore = "We cannot cancel host functions. TODO reenable this test when it's enabled" ]
474+ fn test_terminate_vcpu_calling_host_spinning_cpu ( ) {
475+ // This test relies upon a Hypervisor being present so for now
476+ // we will skip it if there isn't one.
477+ if !is_hypervisor_present ( ) {
478+ println ! ( "Skipping test_call_guest_function_by_name because no hypervisor is present" ) ;
479+ return ;
480+ }
481+ let mut usbox = UninitializedSandbox :: new (
482+ GuestBinary :: FilePath ( callback_guest_as_string ( ) . expect ( "Guest Binary Missing" ) ) ,
483+ None ,
484+ )
485+ . unwrap ( ) ;
486+
487+ // Make this host call run for 5 seconds
488+
489+ fn spin ( ) -> Result < ( ) > {
490+ thread:: sleep ( std:: time:: Duration :: from_secs ( 5 ) ) ;
491+ Ok ( ( ) )
492+ }
493+
494+ #[ cfg( any( target_os = "windows" , not( feature = "seccomp" ) ) ) ]
495+ usbox. register ( "Spin" , spin) . unwrap ( ) ;
496+
497+ #[ cfg( all( target_os = "linux" , feature = "seccomp" ) ) ]
498+ usbox
499+ . register_with_extra_allowed_syscalls ( "Spin" , spin, vec ! [ libc:: SYS_clock_nanosleep ] )
500+ . unwrap ( ) ;
501+
502+ let sandbox: MultiUseSandbox = usbox. evolve ( Noop :: default ( ) ) . unwrap ( ) ;
503+ let mut ctx = sandbox. new_call_context ( ) ;
504+ let result = ctx. call ( "CallHostSpin" , ReturnType :: Void , None ) ;
505+
506+ assert ! ( result. is_err( ) ) ;
507+ match result. unwrap_err ( ) {
508+ HyperlightError :: GuestExecutionHungOnHostFunctionCall ( ) => { }
509+ e => panic ! (
510+ "Expected HyperlightError::GuestExecutionHungOnHostFunctionCall but got {:?}" ,
511+ e
512+ ) ,
513+ }
514+ }
515+
516+ #[ test]
517+ fn test_trigger_exception_on_guest ( ) {
518+ let usbox = UninitializedSandbox :: new (
519+ GuestBinary :: FilePath ( simple_guest_as_string ( ) . expect ( "Guest Binary Missing" ) ) ,
520+ None ,
521+ )
522+ . unwrap ( ) ;
523+
524+ let mut multi_use_sandbox: MultiUseSandbox = usbox. evolve ( Noop :: default ( ) ) . unwrap ( ) ;
525+
526+ let res = multi_use_sandbox. call_guest_function_by_name (
527+ "TriggerException" ,
528+ ReturnType :: Void ,
529+ None ,
530+ ) ;
531+
532+ assert ! ( res. is_err( ) ) ;
533+
534+ match res. unwrap_err ( ) {
535+ HyperlightError :: GuestAborted ( _, msg) => {
536+ // msg should indicate we got an invalid opcode exception
537+ assert ! ( msg. contains( "InvalidOpcode" ) ) ;
538+ }
539+ e => panic ! (
540+ "Expected HyperlightError::GuestExecutionError but got {:?}" ,
541+ e
542+ ) ,
543+ }
544+ }
387545}
0 commit comments