@@ -196,6 +196,27 @@ pub enum HyperlightError {
196196 #[ error( "Failure processing PE File {0:?}" ) ]
197197 PEFileProcessingFailure ( #[ from] goblin:: error:: Error ) ,
198198
199+ /// The sandbox becomes **poisoned** when the guest is not run to completion, leaving it in
200+ /// an inconsistent state that could compromise memory safety, data integrity, or security.
201+ ///
202+ /// ### When Does Poisoning Occur?
203+ ///
204+ /// Poisoning happens when guest execution is interrupted before normal completion:
205+ ///
206+ /// - **Guest panics or aborts** - When a guest function panics, crashes, or calls `abort()`,
207+ /// the normal cleanup and unwinding process is interrupted
208+ /// - **Invalid memory access** - Attempts to read/write/execute memory outside allowed regions
209+ /// - **Stack overflow** - Guest exhausts its stack space during execution
210+ /// - **Heap exhaustion** - Guest runs out of heap memory
211+ /// - **Host-initiated cancellation** - Calling [`InterruptHandle::kill()`] to forcefully
212+ /// terminate an in-progress guest function
213+ ///
214+ /// ## Recovery
215+ ///
216+ /// Use [`crate::MultiUseSandbox::restore()`] to recover from a poisoned sandbox.
217+ #[ error( "The sandbox was poisoned" ) ]
218+ PoisonedSandbox ,
219+
199220 /// Raw pointer is less than base address
200221 #[ error( "Raw pointer ({0:?}) was less than the base address ({1})" ) ]
201222 RawPointerLessThanBaseAddress ( RawPtr , u64 ) ,
@@ -301,6 +322,96 @@ impl<T> From<PoisonError<MutexGuard<'_, T>>> for HyperlightError {
301322 }
302323}
303324
325+ impl HyperlightError {
326+ /// Internal helper to determines if the given error has potential to poison the sandbox.
327+ ///
328+ /// Errors that poison the sandbox are those that can leave the sandbox in an inconsistent
329+ /// state where memory, resources, or data structures may be corrupted or leaked. Usually
330+ /// due to the guest not running to completion.
331+ ///
332+ /// If this method returns `true`, the sandbox will be poisoned and all further operations
333+ /// will fail until the sandbox is restored from a non-poisoned snapshot using
334+ /// [`crate::MultiUseSandbox::restore()`].
335+ pub ( crate ) fn is_poison_error ( & self ) -> bool {
336+ // wildcard _ or matches! not used here purposefully to ensure that new error variants
337+ // are explicitly considered for poisoning behavior.
338+ match self {
339+ // These errors poison the sandbox because they can leave it in an inconsistent state due
340+ // to the guest not running to completion.
341+ HyperlightError :: GuestAborted ( _, _)
342+ | HyperlightError :: ExecutionCanceledByHost ( )
343+ | HyperlightError :: PoisonedSandbox
344+ | HyperlightError :: ExecutionAccessViolation ( _)
345+ | HyperlightError :: StackOverflow ( )
346+ | HyperlightError :: MemoryAccessViolation ( _, _, _) => true ,
347+ #[ cfg( all( feature = "seccomp" , target_os = "linux" ) ) ]
348+ HyperlightError :: DisallowedSyscall => true ,
349+
350+ // All other errors do not poison the sandbox.
351+ HyperlightError :: AnyhowError ( _)
352+ | HyperlightError :: BoundsCheckFailed ( _, _)
353+ | HyperlightError :: CheckedAddOverflow ( _, _)
354+ | HyperlightError :: CStringConversionError ( _)
355+ | HyperlightError :: Error ( _)
356+ | HyperlightError :: FailedToGetValueFromParameter ( )
357+ | HyperlightError :: FieldIsMissingInGuestLogData ( _)
358+ | HyperlightError :: GuestError ( _, _)
359+ | HyperlightError :: GuestExecutionHungOnHostFunctionCall ( )
360+ | HyperlightError :: GuestFunctionCallAlreadyInProgress ( )
361+ | HyperlightError :: GuestInterfaceUnsupportedType ( _)
362+ | HyperlightError :: GuestOffsetIsInvalid ( _)
363+ | HyperlightError :: HostFunctionNotFound ( _)
364+ | HyperlightError :: IOError ( _)
365+ | HyperlightError :: IntConversionFailure ( _)
366+ | HyperlightError :: InvalidFlatBuffer ( _)
367+ | HyperlightError :: JsonConversionFailure ( _)
368+ | HyperlightError :: LockAttemptFailed ( _)
369+ | HyperlightError :: MemoryAllocationFailed ( _)
370+ | HyperlightError :: MemoryProtectionFailed ( _)
371+ | HyperlightError :: MemoryRequestTooBig ( _, _)
372+ | HyperlightError :: MetricNotFound ( _)
373+ | HyperlightError :: MmapFailed ( _)
374+ | HyperlightError :: MprotectFailed ( _)
375+ | HyperlightError :: NoHypervisorFound ( )
376+ | HyperlightError :: NoMemorySnapshot
377+ | HyperlightError :: ParameterValueConversionFailure ( _, _)
378+ | HyperlightError :: PEFileProcessingFailure ( _)
379+ | HyperlightError :: RawPointerLessThanBaseAddress ( _, _)
380+ | HyperlightError :: RefCellBorrowFailed ( _)
381+ | HyperlightError :: RefCellMutBorrowFailed ( _)
382+ | HyperlightError :: ReturnValueConversionFailure ( _, _)
383+ | HyperlightError :: SnapshotSandboxMismatch
384+ | HyperlightError :: SystemTimeError ( _)
385+ | HyperlightError :: TryFromSliceError ( _)
386+ | HyperlightError :: UnexpectedNoOfArguments ( _, _)
387+ | HyperlightError :: UnexpectedParameterValueType ( _, _)
388+ | HyperlightError :: UnexpectedReturnValueType ( _, _)
389+ | HyperlightError :: UTF8StringConversionFailure ( _)
390+ | HyperlightError :: VectorCapacityIncorrect ( _, _, _) => false ,
391+
392+ #[ cfg( target_os = "windows" ) ]
393+ HyperlightError :: CrossBeamReceiveError ( _) => false ,
394+ #[ cfg( target_os = "windows" ) ]
395+ HyperlightError :: CrossBeamSendError ( _) => false ,
396+ #[ cfg( target_os = "windows" ) ]
397+ HyperlightError :: WindowsAPIError ( _) => false ,
398+ #[ cfg( target_os = "linux" ) ]
399+ HyperlightError :: VmmSysError ( _) => false ,
400+ #[ cfg( kvm) ]
401+ HyperlightError :: KVMError ( _) => false ,
402+ #[ cfg( mshv) ]
403+ HyperlightError :: MSHVError ( _) => false ,
404+ #[ cfg( gdb) ]
405+ HyperlightError :: TranslateGuestAddress ( _) => false ,
406+ #[ cfg( all( feature = "seccomp" , target_os = "linux" ) ) ]
407+ HyperlightError :: SeccompFilterError ( _) => false ,
408+
409+ #[ cfg( all( feature = "seccomp" , target_os = "linux" ) ) ]
410+ HyperlightError :: SeccompFilterBackendError ( _) => false ,
411+ }
412+ }
413+ }
414+
304415/// Creates a `HyperlightError::Error` from a string literal or format string
305416#[ macro_export]
306417macro_rules! new_error {
0 commit comments