@@ -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,161 @@ 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+ fn test_violate_seccomp_filters ( ) -> Result < ( ) > {
397+ if cfg ! ( target_os = "windows" ) {
398+ // This test is not applicable on Windows as seccomp is a Linux-specific feature.
399+ return Ok ( ( ) ) ;
400+ }
401+
402+ if !is_hypervisor_present ( ) {
403+ panic ! ( "Panic on create_multi_use_sandbox because no hypervisor is present" ) ;
404+ }
405+
406+ fn make_get_pid_syscall ( ) -> Result < u64 > {
407+ let pid = unsafe { libc:: syscall ( libc:: SYS_getpid ) } ;
408+ Ok ( pid as u64 )
409+ }
410+
411+ // First, run to make sure it fails.
412+ {
413+ let mut usbox = UninitializedSandbox :: new (
414+ GuestBinary :: FilePath ( simple_guest_as_string ( ) . expect ( "Guest Binary Missing" ) ) ,
415+ None ,
416+ )
417+ . unwrap ( ) ;
418+
419+ usbox. register ( "MakeGetpidSyscall" , make_get_pid_syscall) ?;
420+
421+ let mut sbox: MultiUseSandbox = usbox. evolve ( Noop :: default ( ) ) ?;
422+
423+ let res =
424+ sbox. call_guest_function_by_name ( "ViolateSeccompFilters" , ReturnType :: ULong , None ) ;
425+
426+ #[ cfg( feature = "seccomp" ) ]
427+ match res {
428+ Ok ( _) => panic ! ( "Expected to fail due to seccomp violation" ) ,
429+ Err ( e) => match e {
430+ HyperlightError :: DisallowedSyscall => { }
431+ _ => panic ! ( "Expected DisallowedSyscall error: {}" , e) ,
432+ } ,
433+ }
434+
435+ #[ cfg( not( feature = "seccomp" ) ) ]
436+ match res {
437+ Ok ( _) => ( ) ,
438+ Err ( e) => panic ! ( "Expected to succeed without seccomp: {}" , e) ,
439+ }
440+ }
441+
442+ // Second, run with allowing `SYS_getpid`
443+ #[ cfg( feature = "seccomp" ) ]
444+ {
445+ let mut usbox = UninitializedSandbox :: new (
446+ GuestBinary :: FilePath ( simple_guest_as_string ( ) . expect ( "Guest Binary Missing" ) ) ,
447+ None ,
448+ )
449+ . unwrap ( ) ;
450+
451+ usbox. register_with_extra_allowed_syscalls (
452+ "MakeGetpidSyscall" ,
453+ make_get_pid_syscall,
454+ vec ! [ libc:: SYS_getpid ] ,
455+ ) ?;
456+ // ^^^ note, we are allowing SYS_getpid
457+
458+ let mut sbox: MultiUseSandbox = usbox. evolve ( Noop :: default ( ) ) ?;
459+
460+ let res =
461+ sbox. call_guest_function_by_name ( "ViolateSeccompFilters" , ReturnType :: ULong , None ) ;
462+
463+ match res {
464+ Ok ( _) => { }
465+ Err ( e) => panic ! ( "Expected to succeed due to seccomp violation: {}" , e) ,
466+ }
467+ }
468+
469+ Ok ( ( ) )
470+ }
471+
472+ // This test is to capture the case where the guest execution is running a host function when cancelled and that host function
473+ // is never going to return.
474+ // The host function that is called will end after 5 seconds, but by this time the cancellation will have given up
475+ // (using default timeout settings) , so this tests looks for the error "Failed to cancel guest execution".
476+ #[ test]
477+ #[ ignore = "We cannot cancel host functions. TODO reenable this test when it's enabled" ]
478+ fn test_terminate_vcpu_calling_host_spinning_cpu ( ) {
479+ // This test relies upon a Hypervisor being present so for now
480+ // we will skip it if there isn't one.
481+ if !is_hypervisor_present ( ) {
482+ println ! ( "Skipping test_call_guest_function_by_name because no hypervisor is present" ) ;
483+ return ;
484+ }
485+ let mut usbox = UninitializedSandbox :: new (
486+ GuestBinary :: FilePath ( callback_guest_as_string ( ) . expect ( "Guest Binary Missing" ) ) ,
487+ None ,
488+ )
489+ . unwrap ( ) ;
490+
491+ // Make this host call run for 5 seconds
492+
493+ fn spin ( ) -> Result < ( ) > {
494+ thread:: sleep ( std:: time:: Duration :: from_secs ( 5 ) ) ;
495+ Ok ( ( ) )
496+ }
497+
498+ #[ cfg( any( target_os = "windows" , not( feature = "seccomp" ) ) ) ]
499+ usbox. register ( "Spin" , spin) . unwrap ( ) ;
500+
501+ #[ cfg( all( target_os = "linux" , feature = "seccomp" ) ) ]
502+ usbox
503+ . register_with_extra_allowed_syscalls ( "Spin" , spin, vec ! [ libc:: SYS_clock_nanosleep ] )
504+ . unwrap ( ) ;
505+
506+ let sandbox: MultiUseSandbox = usbox. evolve ( Noop :: default ( ) ) . unwrap ( ) ;
507+ let mut ctx = sandbox. new_call_context ( ) ;
508+ let result = ctx. call ( "CallHostSpin" , ReturnType :: Void , None ) ;
509+
510+ assert ! ( result. is_err( ) ) ;
511+ match result. unwrap_err ( ) {
512+ HyperlightError :: GuestExecutionHungOnHostFunctionCall ( ) => { }
513+ e => panic ! (
514+ "Expected HyperlightError::GuestExecutionHungOnHostFunctionCall but got {:?}" ,
515+ e
516+ ) ,
517+ }
518+ }
519+
520+ #[ test]
521+ fn test_trigger_exception_on_guest ( ) {
522+ let usbox = UninitializedSandbox :: new (
523+ GuestBinary :: FilePath ( simple_guest_as_string ( ) . expect ( "Guest Binary Missing" ) ) ,
524+ None ,
525+ )
526+ . unwrap ( ) ;
527+
528+ let mut multi_use_sandbox: MultiUseSandbox = usbox. evolve ( Noop :: default ( ) ) . unwrap ( ) ;
529+
530+ let res = multi_use_sandbox. call_guest_function_by_name (
531+ "TriggerException" ,
532+ ReturnType :: Void ,
533+ None ,
534+ ) ;
535+
536+ assert ! ( res. is_err( ) ) ;
537+
538+ match res. unwrap_err ( ) {
539+ HyperlightError :: GuestAborted ( _, msg) => {
540+ // msg should indicate we got an invalid opcode exception
541+ assert ! ( msg. contains( "InvalidOpcode" ) ) ;
542+ }
543+ e => panic ! (
544+ "Expected HyperlightError::GuestExecutionError but got {:?}" ,
545+ e
546+ ) ,
547+ }
548+ }
387549}
0 commit comments