@@ -30,6 +30,7 @@ use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, Ret
3030use hyperlight_common:: flatbuffer_wrappers:: guest_error:: ErrorCode ;
3131use thiserror:: Error ;
3232
33+ use crate :: hypervisor:: hyperlight_vm:: HyperlightVmError ;
3334#[ cfg( target_os = "windows" ) ]
3435use crate :: hypervisor:: wrappers:: HandleWrapper ;
3536use crate :: mem:: memory_region:: MemoryRegionFlags ;
@@ -111,6 +112,14 @@ pub enum HyperlightError {
111112 #[ error( "HostFunction {0} was not found" ) ]
112113 HostFunctionNotFound ( String ) ,
113114
115+ /// Hyperlight VM error.
116+ ///
117+ /// **Note:** This error variant is considered internal and its structure is not stable.
118+ /// It may change between versions without notice. Users should not rely on this.
119+ #[ doc( hidden) ]
120+ #[ error( "Internal Hyperlight VM error: {0}" ) ]
121+ HyperlightVmError ( #[ from] HyperlightVmError ) ,
122+
114123 /// Reading Writing or Seeking data failed.
115124 #[ error( "Reading Writing or Seeking data failed {0:?}" ) ]
116125 IOError ( #[ from] std:: io:: Error ) ,
@@ -127,11 +136,6 @@ pub enum HyperlightError {
127136 #[ error( "Conversion of str data to json failed" ) ]
128137 JsonConversionFailure ( #[ from] serde_json:: Error ) ,
129138
130- /// KVM Error Occurred
131- #[ error( "KVM Error {0:?}" ) ]
132- #[ cfg( kvm) ]
133- KVMError ( #[ from] kvm_ioctls:: Error ) ,
134-
135139 /// An attempt to get a lock from a Mutex failed.
136140 #[ error( "Unable to lock resource" ) ]
137141 LockAttemptFailed ( String ) ,
@@ -168,11 +172,6 @@ pub enum HyperlightError {
168172 #[ error( "mprotect failed with os error {0:?}" ) ]
169173 MprotectFailed ( Option < i32 > ) ,
170174
171- /// mshv Error Occurred
172- #[ error( "mshv Error {0:?}" ) ]
173- #[ cfg( mshv3) ]
174- MSHVError ( #[ from] mshv_ioctls:: MshvError ) ,
175-
176175 /// No Hypervisor was found for Sandbox.
177176 #[ error( "No Hypervisor was found for Sandbox" ) ]
178177 NoHypervisorFound ( ) ,
@@ -242,11 +241,6 @@ pub enum HyperlightError {
242241 #[ error( "SystemTimeError {0:?}" ) ]
243242 SystemTimeError ( #[ from] SystemTimeError ) ,
244243
245- /// Error occurred when translating guest address
246- #[ error( "An error occurred when translating guest address: {0:?}" ) ]
247- #[ cfg( gdb) ]
248- TranslateGuestAddress ( u64 ) ,
249-
250244 /// Error occurred converting a slice to an array
251245 #[ error( "TryFromSliceError {0:?}" ) ]
252246 TryFromSliceError ( #[ from] TryFromSliceError ) ,
@@ -334,6 +328,11 @@ impl HyperlightError {
334328 | HyperlightError :: SnapshotSizeMismatch ( _, _)
335329 | HyperlightError :: MemoryRegionSizeMismatch ( _, _, _) => true ,
336330
331+ // HyperlightVmError::DispatchGuestCall may poison the sandbox
332+ HyperlightError :: HyperlightVmError ( HyperlightVmError :: DispatchGuestCall ( e) ) => {
333+ e. is_poison_error ( )
334+ }
335+
337336 // All other errors do not poison the sandbox.
338337 HyperlightError :: AnyhowError ( _)
339338 | HyperlightError :: BoundsCheckFailed ( _, _)
@@ -348,6 +347,10 @@ impl HyperlightError {
348347 | HyperlightError :: GuestInterfaceUnsupportedType ( _)
349348 | HyperlightError :: GuestOffsetIsInvalid ( _)
350349 | HyperlightError :: HostFunctionNotFound ( _)
350+ | HyperlightError :: HyperlightVmError ( HyperlightVmError :: Create ( _) )
351+ | HyperlightError :: HyperlightVmError ( HyperlightVmError :: Initialize ( _) )
352+ | HyperlightError :: HyperlightVmError ( HyperlightVmError :: MapRegion ( _) )
353+ | HyperlightError :: HyperlightVmError ( HyperlightVmError :: UnmapRegion ( _) )
351354 | HyperlightError :: IOError ( _)
352355 | HyperlightError :: IntConversionFailure ( _)
353356 | HyperlightError :: InvalidFlatBuffer ( _)
@@ -384,12 +387,6 @@ impl HyperlightError {
384387 HyperlightError :: WindowsAPIError ( _) => false ,
385388 #[ cfg( target_os = "linux" ) ]
386389 HyperlightError :: VmmSysError ( _) => false ,
387- #[ cfg( kvm) ]
388- HyperlightError :: KVMError ( _) => false ,
389- #[ cfg( mshv3) ]
390- HyperlightError :: MSHVError ( _) => false ,
391- #[ cfg( gdb) ]
392- HyperlightError :: TranslateGuestAddress ( _) => false ,
393390 }
394391 }
395392}
@@ -410,3 +407,144 @@ macro_rules! new_error {
410407 $crate:: error:: HyperlightError :: Error ( __err_msg)
411408 } } ;
412409}
410+
411+ #[ cfg( test) ]
412+ mod tests {
413+ use super :: * ;
414+ use crate :: hypervisor:: hyperlight_vm:: {
415+ DispatchGuestCallError , HandleIoError , HyperlightVmError , RunVmError ,
416+ } ;
417+ use crate :: sandbox:: outb:: HandleOutbError ;
418+
419+ /// Test that StackOverflow from RunVmError promotes to HyperlightError::StackOverflow
420+ #[ test]
421+ fn test_promote_stack_overflow_from_run_vm ( ) {
422+ let err = DispatchGuestCallError :: Run ( RunVmError :: StackOverflow ) ;
423+ let ( promoted, should_poison) = err. promote ( ) ;
424+
425+ assert ! ( should_poison, "StackOverflow should poison the sandbox" ) ;
426+ assert ! (
427+ matches!( promoted, HyperlightError :: StackOverflow ( ) ) ,
428+ "Expected HyperlightError::StackOverflow, got {:?}" ,
429+ promoted
430+ ) ;
431+ }
432+
433+ /// Test that StackOverflow from HandleOutbError promotes to HyperlightError::StackOverflow
434+ #[ test]
435+ fn test_promote_stack_overflow_from_outb ( ) {
436+ let err = DispatchGuestCallError :: Run ( RunVmError :: HandleIo ( HandleIoError :: Outb (
437+ HandleOutbError :: StackOverflow ,
438+ ) ) ) ;
439+ let ( promoted, should_poison) = err. promote ( ) ;
440+
441+ assert ! ( should_poison, "StackOverflow should poison the sandbox" ) ;
442+ assert ! (
443+ matches!( promoted, HyperlightError :: StackOverflow ( ) ) ,
444+ "Expected HyperlightError::StackOverflow, got {:?}" ,
445+ promoted
446+ ) ;
447+ }
448+
449+ /// Test that ExecutionCancelledByHost promotes to HyperlightError::ExecutionCanceledByHost
450+ #[ test]
451+ fn test_promote_execution_cancelled_by_host ( ) {
452+ let err = DispatchGuestCallError :: Run ( RunVmError :: ExecutionCancelledByHost ) ;
453+ let ( promoted, should_poison) = err. promote ( ) ;
454+
455+ assert ! (
456+ should_poison,
457+ "ExecutionCancelledByHost should poison the sandbox"
458+ ) ;
459+ assert ! (
460+ matches!( promoted, HyperlightError :: ExecutionCanceledByHost ( ) ) ,
461+ "Expected HyperlightError::ExecutionCanceledByHost, got {:?}" ,
462+ promoted
463+ ) ;
464+ }
465+
466+ /// Test that GuestAborted promotes to HyperlightError::GuestAborted with correct values
467+ #[ test]
468+ fn test_promote_guest_aborted ( ) {
469+ let err = DispatchGuestCallError :: Run ( RunVmError :: HandleIo ( HandleIoError :: Outb (
470+ HandleOutbError :: GuestAborted {
471+ code : 42 ,
472+ message : "test abort" . to_string ( ) ,
473+ } ,
474+ ) ) ) ;
475+ let ( promoted, should_poison) = err. promote ( ) ;
476+
477+ assert ! ( should_poison, "GuestAborted should poison the sandbox" ) ;
478+ match promoted {
479+ HyperlightError :: GuestAborted ( code, msg) => {
480+ assert_eq ! ( code, 42 ) ;
481+ assert_eq ! ( msg, "test abort" ) ;
482+ }
483+ _ => panic ! ( "Expected HyperlightError::GuestAborted, got {:?}" , promoted) ,
484+ }
485+ }
486+
487+ /// Test that MemoryAccessViolation promotes to HyperlightError::MemoryAccessViolation
488+ #[ test]
489+ fn test_promote_memory_access_violation ( ) {
490+ let err = DispatchGuestCallError :: Run ( RunVmError :: MemoryAccessViolation {
491+ addr : 0xDEADBEEF ,
492+ access_type : MemoryRegionFlags :: WRITE ,
493+ region_flags : MemoryRegionFlags :: READ ,
494+ } ) ;
495+ let ( promoted, should_poison) = err. promote ( ) ;
496+
497+ assert ! (
498+ should_poison,
499+ "MemoryAccessViolation should poison the sandbox"
500+ ) ;
501+ match promoted {
502+ HyperlightError :: MemoryAccessViolation ( addr, access_type, region_flags) => {
503+ assert_eq ! ( addr, 0xDEADBEEF ) ;
504+ assert_eq ! ( access_type, MemoryRegionFlags :: WRITE ) ;
505+ assert_eq ! ( region_flags, MemoryRegionFlags :: READ ) ;
506+ }
507+ _ => panic ! (
508+ "Expected HyperlightError::MemoryAccessViolation, got {:?}" ,
509+ promoted
510+ ) ,
511+ }
512+ }
513+
514+ /// Test that ConvertRspPointer does not poison the sandbox
515+ #[ test]
516+ fn test_promote_convert_rsp_pointer_no_poison ( ) {
517+ let err = DispatchGuestCallError :: ConvertRspPointer ( "test error" . to_string ( ) ) ;
518+ let ( promoted, should_poison) = err. promote ( ) ;
519+
520+ assert ! (
521+ !should_poison,
522+ "ConvertRspPointer should not poison the sandbox"
523+ ) ;
524+ assert ! (
525+ matches!(
526+ promoted,
527+ HyperlightError :: HyperlightVmError ( HyperlightVmError :: DispatchGuestCall ( _) )
528+ ) ,
529+ "Expected HyperlightError::HyperlightVmError, got {:?}" ,
530+ promoted
531+ ) ;
532+ }
533+
534+ /// Test that non-promoted Run errors are wrapped in HyperlightVmError
535+ #[ test]
536+ fn test_promote_other_run_errors_wrapped ( ) {
537+ let err = DispatchGuestCallError :: Run ( RunVmError :: MmioReadUnmapped ( 0x1000 ) ) ;
538+ let ( promoted, should_poison) = err. promote ( ) ;
539+
540+ assert ! ( should_poison, "Run errors should poison the sandbox" ) ;
541+ assert ! (
542+ matches!(
543+ promoted,
544+ HyperlightError :: HyperlightVmError ( HyperlightVmError :: DispatchGuestCall ( _) )
545+ ) ,
546+ "Expected HyperlightError::HyperlightVmError, got {:?}" ,
547+ promoted
548+ ) ;
549+ }
550+ }
0 commit comments