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