@@ -295,16 +295,21 @@ where
295
295
296
296
#[ cfg( test) ]
297
297
mod tests {
298
+ use std:: thread;
299
+
298
300
use hyperlight_common:: flatbuffer_wrappers:: function_types:: {
299
301
ParameterValue , ReturnType , ReturnValue ,
300
302
} ;
301
- use hyperlight_testing:: simple_guest_as_string;
303
+ use hyperlight_testing:: { callback_guest_as_string , simple_guest_as_string} ;
302
304
303
305
use crate :: func:: call_ctx:: MultiUseGuestCallContext ;
304
306
use crate :: sandbox:: SandboxConfiguration ;
305
307
use crate :: sandbox_state:: sandbox:: { DevolvableSandbox , EvolvableSandbox } ;
306
308
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
+ } ;
308
313
309
314
// Tests to ensure that many (1000) function calls can be made in a call context with a small stack (1K) and heap(14K).
310
315
// 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 {
384
389
. unwrap ( ) ;
385
390
assert_eq ! ( res, ReturnValue :: Int ( 0 ) ) ;
386
391
}
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
+ }
387
545
}
0 commit comments