1use std::array::TryFromSliceError;
18use std::cell::{BorrowError, BorrowMutError};
19use std::convert::Infallible;
20use std::error::Error;
21use std::num::TryFromIntError;
22use std::string::FromUtf8Error;
23use std::sync::{MutexGuard, PoisonError};
24use std::time::SystemTimeError;
25
26#[cfg(target_os = "windows")]
27use crossbeam_channel::{RecvError, SendError};
28use flatbuffers::InvalidFlatbuffer;
29use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnValue};
30use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
31use thiserror::Error;
32
33use crate::hypervisor::hyperlight_vm::HyperlightVmError;
34#[cfg(target_os = "windows")]
35use crate::hypervisor::wrappers::HandleWrapper;
36use crate::mem::memory_region::MemoryRegionFlags;
37use crate::mem::ptr::RawPtr;
38
39#[derive(Error, Debug)]
41pub enum HyperlightError {
42 #[error("Anyhow Error was returned: {0}")]
44 AnyhowError(#[from] anyhow::Error),
45 #[error("Offset: {0} out of bounds, Max is: {1}")]
47 BoundsCheckFailed(u64, usize),
48
49 #[error("Couldn't add offset to base address. Offset: {0}, Base Address: {1}")]
51 CheckedAddOverflow(u64, u64),
52
53 #[error("{0:?}")]
55 #[cfg(target_os = "windows")]
56 CrossBeamReceiveError(#[from] RecvError),
57
58 #[error("{0:?}")]
60 #[cfg(target_os = "windows")]
61 CrossBeamSendError(#[from] SendError<HandleWrapper>),
62
63 #[error("Error converting CString {0:?}")]
65 CStringConversionError(#[from] std::ffi::NulError),
66
67 #[error("{0}")]
69 Error(String),
70
71 #[error("Non-executable address {0:#x} tried to be executed")]
73 ExecutionAccessViolation(u64),
74
75 #[error("Execution was cancelled by the host.")]
77 ExecutionCanceledByHost(),
78
79 #[error("Failed to get a value from flat buffer parameter")]
81 FailedToGetValueFromParameter(),
82
83 #[error("Field Name {0} not found in decoded GuestLogData")]
85 FieldIsMissingInGuestLogData(String),
86
87 #[error("Guest aborted: {0} {1}")]
89 GuestAborted(u8, String),
90
91 #[error("Guest error occurred {0:?}: {1}")]
93 GuestError(ErrorCode, String),
94
95 #[error("Guest execution hung on the execution of a host function call")]
97 GuestExecutionHungOnHostFunctionCall(),
98
99 #[error("Guest call is already in progress")]
101 GuestFunctionCallAlreadyInProgress(),
102
103 #[error("Unsupported type: {0}")]
105 GuestInterfaceUnsupportedType(String),
106
107 #[error("The guest offset {0} is invalid.")]
109 GuestOffsetIsInvalid(usize),
110
111 #[error("HostFunction {0} was not found")]
113 HostFunctionNotFound(String),
114
115 #[doc(hidden)]
120 #[error("Internal Hyperlight VM error: {0}")]
121 HyperlightVmError(#[from] HyperlightVmError),
122
123 #[error("Reading Writing or Seeking data failed {0:?}")]
125 IOError(#[from] std::io::Error),
126
127 #[error("Failed To Convert Size to usize")]
129 IntConversionFailure(#[from] TryFromIntError),
130
131 #[error("The flatbuffer is invalid")]
133 InvalidFlatBuffer(#[from] InvalidFlatbuffer),
134
135 #[error("Conversion of str data to json failed")]
137 JsonConversionFailure(#[from] serde_json::Error),
138
139 #[error("Unable to lock resource")]
141 LockAttemptFailed(String),
142
143 #[error("Memory Access Violation at address {0:#x} of type {1}, but memory is marked as {2}")]
145 MemoryAccessViolation(u64, MemoryRegionFlags, MemoryRegionFlags),
146
147 #[error("Memory Allocation Failed with OS Error {0:?}.")]
149 MemoryAllocationFailed(Option<i32>),
150
151 #[error("Memory Protection Failed with OS Error {0:?}.")]
153 MemoryProtectionFailed(Option<i32>),
154
155 #[error("Memory region size mismatch: host size {0:?}, guest size {1:?} region {2:?}")]
157 MemoryRegionSizeMismatch(usize, usize, String),
158
159 #[error("Memory requested {0} exceeds maximum size allowed {1}")]
161 MemoryRequestTooBig(usize, usize),
162
163 #[error("Memory requested {0} is less than the minimum size allowed {1}")]
166 MemoryRequestTooSmall(usize, usize),
167
168 #[error("Metric Not Found {0:?}.")]
170 MetricNotFound(&'static str),
171
172 #[error("mmap failed with os error {0:?}")]
174 MmapFailed(Option<i32>),
175
176 #[error("mprotect failed with os error {0:?}")]
178 MprotectFailed(Option<i32>),
179
180 #[error("No Hypervisor was found for Sandbox")]
182 NoHypervisorFound(),
183
184 #[error("Restore_state called with no valid snapshot")]
186 NoMemorySnapshot,
187
188 #[error("Failed To Convert Parameter Value {0:?} to {1:?}")]
190 ParameterValueConversionFailure(ParameterValue, &'static str),
191
192 #[error("Failure processing PE File {0:?}")]
194 PEFileProcessingFailure(#[from] goblin::error::Error),
195
196 #[error("The sandbox was poisoned")]
215 PoisonedSandbox,
216
217 #[error("Raw pointer ({0:?}) was less than the base address ({1})")]
219 RawPointerLessThanBaseAddress(RawPtr, u64),
220
221 #[error("RefCell borrow failed")]
223 RefCellBorrowFailed(#[from] BorrowError),
224
225 #[error("RefCell mut borrow failed")]
227 RefCellMutBorrowFailed(#[from] BorrowMutError),
228
229 #[error("Failed To Convert Return Value {0:?} to {1:?}")]
231 ReturnValueConversionFailure(ReturnValue, &'static str),
232
233 #[error("Snapshot Size Mismatch: Memory Size {0:?} Snapshot Size {1:?}")]
235 SnapshotSizeMismatch(usize, usize),
236
237 #[error("Snapshot was taken from a different sandbox")]
239 SnapshotSandboxMismatch,
240
241 #[error("SystemTimeError {0:?}")]
243 SystemTimeError(#[from] SystemTimeError),
244
245 #[error("TryFromSliceError {0:?}")]
247 TryFromSliceError(#[from] TryFromSliceError),
248
249 #[error("The number of arguments to the function is wrong: got {0:?} expected {1:?}")]
251 UnexpectedNoOfArguments(usize, usize),
252
253 #[error("The parameter value type is unexpected got {0:?} expected {1:?}")]
255 UnexpectedParameterValueType(ParameterValue, String),
256
257 #[error("The return value type is unexpected got {0:?} expected {1:?}")]
259 UnexpectedReturnValueType(ReturnValue, String),
260
261 #[error("String Conversion of UTF8 data to str failed")]
263 UTF8StringConversionFailure(#[from] FromUtf8Error),
264
265 #[error(
267 "The capacity of the vector is incorrect. Capacity: {0}, Length: {1}, FlatBuffer Size: {2}"
268 )]
269 VectorCapacityIncorrect(usize, usize, i32),
270
271 #[error("vmm sys Error {0:?}")]
273 #[cfg(target_os = "linux")]
274 VmmSysError(vmm_sys_util::errno::Error),
275
276 #[cfg(target_os = "windows")]
278 #[error("Windows API Error Result {0:?}")]
279 WindowsAPIError(#[from] windows_result::Error),
280}
281
282impl From<Infallible> for HyperlightError {
283 fn from(_: Infallible) -> Self {
284 "Impossible as this is an infallible error".into()
285 }
286}
287
288impl From<&str> for HyperlightError {
289 fn from(s: &str) -> Self {
290 HyperlightError::Error(s.to_string())
291 }
292}
293
294impl<T> From<PoisonError<MutexGuard<'_, T>>> for HyperlightError {
295 fn from(e: PoisonError<MutexGuard<'_, T>>) -> Self {
299 let source = match e.source() {
300 Some(s) => s.to_string(),
301 None => String::from(""),
302 };
303 HyperlightError::LockAttemptFailed(source)
304 }
305}
306
307impl HyperlightError {
308 pub(crate) fn is_poison_error(&self) -> bool {
318 match self {
321 HyperlightError::GuestAborted(_, _)
324 | HyperlightError::ExecutionCanceledByHost()
325 | HyperlightError::PoisonedSandbox
326 | HyperlightError::ExecutionAccessViolation(_)
327 | HyperlightError::MemoryAccessViolation(_, _, _)
328 | HyperlightError::SnapshotSizeMismatch(_, _)
329 | HyperlightError::MemoryRegionSizeMismatch(_, _, _)
330 | HyperlightError::HyperlightVmError(HyperlightVmError::Restore(_)) => true,
333
334 HyperlightError::HyperlightVmError(HyperlightVmError::UpdateRegion(_))
338 | HyperlightError::HyperlightVmError(HyperlightVmError::AccessPageTable(_)) => true,
339
340 HyperlightError::HyperlightVmError(HyperlightVmError::DispatchGuestCall(e)) => {
342 e.is_poison_error()
343 }
344
345 HyperlightError::AnyhowError(_)
347 | HyperlightError::BoundsCheckFailed(_, _)
348 | HyperlightError::CheckedAddOverflow(_, _)
349 | HyperlightError::CStringConversionError(_)
350 | HyperlightError::Error(_)
351 | HyperlightError::FailedToGetValueFromParameter()
352 | HyperlightError::FieldIsMissingInGuestLogData(_)
353 | HyperlightError::GuestError(_, _)
354 | HyperlightError::GuestExecutionHungOnHostFunctionCall()
355 | HyperlightError::GuestFunctionCallAlreadyInProgress()
356 | HyperlightError::GuestInterfaceUnsupportedType(_)
357 | HyperlightError::GuestOffsetIsInvalid(_)
358 | HyperlightError::HostFunctionNotFound(_)
359 | HyperlightError::HyperlightVmError(HyperlightVmError::Create(_))
360 | HyperlightError::HyperlightVmError(HyperlightVmError::Initialize(_))
361 | HyperlightError::HyperlightVmError(HyperlightVmError::MapRegion(_))
362 | HyperlightError::HyperlightVmError(HyperlightVmError::UnmapRegion(_))
363 | HyperlightError::IOError(_)
364 | HyperlightError::IntConversionFailure(_)
365 | HyperlightError::InvalidFlatBuffer(_)
366 | HyperlightError::JsonConversionFailure(_)
367 | HyperlightError::LockAttemptFailed(_)
368 | HyperlightError::MemoryAllocationFailed(_)
369 | HyperlightError::MemoryProtectionFailed(_)
370 | HyperlightError::MemoryRequestTooBig(_, _)
371 | HyperlightError::MemoryRequestTooSmall(_, _)
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 }
401 }
402}
403
404#[macro_export]
406macro_rules! new_error {
407 ($msg:literal $(,)?) => {{
408 let __args = std::format_args!($msg);
409 let __err_msg = match __args.as_str() {
410 Some(msg) => String::from(msg),
411 None => std::format!($msg),
412 };
413 $crate::HyperlightError::Error(__err_msg)
414 }};
415 ($fmtstr:expr, $($arg:tt)*) => {{
416 let __err_msg = std::format!($fmtstr, $($arg)*);
417 $crate::error::HyperlightError::Error(__err_msg)
418 }};
419}
420
421#[cfg(test)]
422mod tests {
423 use super::*;
424 use crate::hypervisor::hyperlight_vm::{
425 DispatchGuestCallError, HandleIoError, HyperlightVmError, RunVmError,
426 };
427 use crate::sandbox::outb::HandleOutbError;
428
429 #[test]
431 fn test_promote_execution_cancelled_by_host() {
432 let err = DispatchGuestCallError::Run(RunVmError::ExecutionCancelledByHost);
433 let (promoted, should_poison) = err.promote();
434
435 assert!(
436 should_poison,
437 "ExecutionCancelledByHost should poison the sandbox"
438 );
439 assert!(
440 matches!(promoted, HyperlightError::ExecutionCanceledByHost()),
441 "Expected HyperlightError::ExecutionCanceledByHost, got {:?}",
442 promoted
443 );
444 }
445
446 #[test]
448 fn test_promote_guest_aborted() {
449 let err = DispatchGuestCallError::Run(RunVmError::HandleIo(HandleIoError::Outb(
450 HandleOutbError::GuestAborted {
451 code: 42,
452 message: "test abort".to_string(),
453 },
454 )));
455 let (promoted, should_poison) = err.promote();
456
457 assert!(should_poison, "GuestAborted should poison the sandbox");
458 match promoted {
459 HyperlightError::GuestAborted(code, msg) => {
460 assert_eq!(code, 42);
461 assert_eq!(msg, "test abort");
462 }
463 _ => panic!("Expected HyperlightError::GuestAborted, got {:?}", promoted),
464 }
465 }
466
467 #[test]
469 fn test_promote_memory_access_violation() {
470 let err = DispatchGuestCallError::Run(RunVmError::MemoryAccessViolation {
471 addr: 0xDEADBEEF,
472 access_type: MemoryRegionFlags::WRITE,
473 region_flags: MemoryRegionFlags::READ,
474 });
475 let (promoted, should_poison) = err.promote();
476
477 assert!(
478 should_poison,
479 "MemoryAccessViolation should poison the sandbox"
480 );
481 match promoted {
482 HyperlightError::MemoryAccessViolation(addr, access_type, region_flags) => {
483 assert_eq!(addr, 0xDEADBEEF);
484 assert_eq!(access_type, MemoryRegionFlags::WRITE);
485 assert_eq!(region_flags, MemoryRegionFlags::READ);
486 }
487 _ => panic!(
488 "Expected HyperlightError::MemoryAccessViolation, got {:?}",
489 promoted
490 ),
491 }
492 }
493
494 #[test]
496 fn test_promote_other_run_errors_wrapped() {
497 let err = DispatchGuestCallError::Run(RunVmError::MmioReadUnmapped(0x1000));
498 let (promoted, should_poison) = err.promote();
499
500 assert!(should_poison, "Run errors should poison the sandbox");
501 assert!(
502 matches!(
503 promoted,
504 HyperlightError::HyperlightVmError(HyperlightVmError::DispatchGuestCall(_))
505 ),
506 "Expected HyperlightError::HyperlightVmError, got {:?}",
507 promoted
508 );
509 }
510}