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(
111 "Guest binary was built with hyperlight-guest-bin {guest_bin_version}, \
112 but the host is running hyperlight {host_version}"
113 )]
114 GuestBinVersionMismatch {
115 guest_bin_version: String,
117 host_version: String,
119 },
120
121 #[error("HostFunction {0} was not found")]
123 HostFunctionNotFound(String),
124
125 #[doc(hidden)]
130 #[error("Internal Hyperlight VM error: {0}")]
131 HyperlightVmError(#[from] HyperlightVmError),
132
133 #[error("Reading Writing or Seeking data failed {0:?}")]
135 IOError(#[from] std::io::Error),
136
137 #[error("Failed To Convert Size to usize")]
139 IntConversionFailure(#[from] TryFromIntError),
140
141 #[error("The flatbuffer is invalid")]
143 InvalidFlatBuffer(#[from] InvalidFlatbuffer),
144
145 #[error("Conversion of str data to json failed")]
147 JsonConversionFailure(#[from] serde_json::Error),
148
149 #[error("Unable to lock resource")]
151 LockAttemptFailed(String),
152
153 #[error("Memory Access Violation at address {0:#x} of type {1}, but memory is marked as {2}")]
155 MemoryAccessViolation(u64, MemoryRegionFlags, MemoryRegionFlags),
156
157 #[error("Memory Allocation Failed with OS Error {0:?}.")]
159 MemoryAllocationFailed(Option<i32>),
160
161 #[error("Memory Protection Failed with OS Error {0:?}.")]
163 MemoryProtectionFailed(Option<i32>),
164
165 #[error("Memory region size mismatch: host size {0:?}, guest size {1:?} region {2:?}")]
167 MemoryRegionSizeMismatch(usize, usize, String),
168
169 #[error("Memory requested {0} exceeds maximum size allowed {1}")]
171 MemoryRequestTooBig(usize, usize),
172
173 #[error("Memory requested {0} is less than the minimum size allowed {1}")]
176 MemoryRequestTooSmall(usize, usize),
177
178 #[error("Metric Not Found {0:?}.")]
180 MetricNotFound(&'static str),
181
182 #[error("mmap failed with os error {0:?}")]
184 MmapFailed(Option<i32>),
185
186 #[error("mprotect failed with os error {0:?}")]
188 MprotectFailed(Option<i32>),
189
190 #[error("No Hypervisor was found for Sandbox")]
192 NoHypervisorFound(),
193
194 #[error("Restore_state called with no valid snapshot")]
196 NoMemorySnapshot,
197
198 #[error("Failed To Convert Parameter Value {0:?} to {1:?}")]
200 ParameterValueConversionFailure(ParameterValue, &'static str),
201
202 #[error("Failure processing PE File {0:?}")]
204 PEFileProcessingFailure(#[from] goblin::error::Error),
205
206 #[error("The sandbox was poisoned")]
225 PoisonedSandbox,
226
227 #[error("Raw pointer ({0:?}) was less than the base address ({1})")]
229 RawPointerLessThanBaseAddress(RawPtr, u64),
230
231 #[error("RefCell borrow failed")]
233 RefCellBorrowFailed(#[from] BorrowError),
234
235 #[error("RefCell mut borrow failed")]
237 RefCellMutBorrowFailed(#[from] BorrowMutError),
238
239 #[error("Failed To Convert Return Value {0:?} to {1:?}")]
241 ReturnValueConversionFailure(ReturnValue, &'static str),
242
243 #[error("Snapshot memory layout is not compatible with this sandbox")]
246 SnapshotLayoutMismatch,
247
248 #[error(
251 "Snapshot host function mismatch: missing=[{}], signature mismatches=[{}]",
252 missing.join(", "),
253 signature_mismatches.join("; ")
254 )]
255 SnapshotHostFunctionMismatch {
256 missing: Vec<String>,
258 signature_mismatches: Vec<String>,
261 },
262
263 #[error("SystemTimeError {0:?}")]
265 SystemTimeError(#[from] SystemTimeError),
266
267 #[error("TryFromSliceError {0:?}")]
269 TryFromSliceError(#[from] TryFromSliceError),
270
271 #[error("The number of arguments to the function is wrong: got {0:?} expected {1:?}")]
273 UnexpectedNoOfArguments(usize, usize),
274
275 #[error("The parameter value type is unexpected got {0:?} expected {1:?}")]
277 UnexpectedParameterValueType(ParameterValue, String),
278
279 #[error("The return value type is unexpected got {0:?} expected {1:?}")]
281 UnexpectedReturnValueType(ReturnValue, String),
282
283 #[error("String Conversion of UTF8 data to str failed")]
285 UTF8StringConversionFailure(#[from] FromUtf8Error),
286
287 #[error(
289 "The capacity of the vector is incorrect. Capacity: {0}, Length: {1}, FlatBuffer Size: {2}"
290 )]
291 VectorCapacityIncorrect(usize, usize, i32),
292
293 #[error("vmm sys Error {0:?}")]
295 #[cfg(target_os = "linux")]
296 VmmSysError(vmm_sys_util::errno::Error),
297
298 #[cfg(target_os = "windows")]
300 #[error("Windows API Error Result {0:?}")]
301 WindowsAPIError(#[from] windows_result::Error),
302}
303
304impl From<Infallible> for HyperlightError {
305 fn from(_: Infallible) -> Self {
306 "Impossible as this is an infallible error".into()
307 }
308}
309
310impl From<&str> for HyperlightError {
311 fn from(s: &str) -> Self {
312 HyperlightError::Error(s.to_string())
313 }
314}
315
316impl<T> From<PoisonError<MutexGuard<'_, T>>> for HyperlightError {
317 fn from(e: PoisonError<MutexGuard<'_, T>>) -> Self {
321 let source = match e.source() {
322 Some(s) => s.to_string(),
323 None => String::from(""),
324 };
325 HyperlightError::LockAttemptFailed(source)
326 }
327}
328
329impl HyperlightError {
330 pub(crate) fn is_poison_error(&self) -> bool {
340 match self {
343 HyperlightError::GuestAborted(_, _)
346 | HyperlightError::ExecutionCanceledByHost()
347 | HyperlightError::PoisonedSandbox
348 | HyperlightError::ExecutionAccessViolation(_)
349 | HyperlightError::MemoryAccessViolation(_, _, _)
350 | HyperlightError::MemoryRegionSizeMismatch(_, _, _)
351 | HyperlightError::HyperlightVmError(HyperlightVmError::Restore(_)) => true,
354
355 HyperlightError::HyperlightVmError(HyperlightVmError::UpdateRegion(_))
359 | HyperlightError::HyperlightVmError(HyperlightVmError::AccessPageTable(_)) => true,
360
361 HyperlightError::HyperlightVmError(HyperlightVmError::DispatchGuestCall(e)) => {
363 e.is_poison_error()
364 }
365
366 HyperlightError::AnyhowError(_)
368 | HyperlightError::BoundsCheckFailed(_, _)
369 | HyperlightError::CheckedAddOverflow(_, _)
370 | HyperlightError::CStringConversionError(_)
371 | HyperlightError::Error(_)
372 | HyperlightError::FailedToGetValueFromParameter()
373 | HyperlightError::FieldIsMissingInGuestLogData(_)
374 | HyperlightError::GuestBinVersionMismatch { .. }
375 | HyperlightError::GuestError(_, _)
376 | HyperlightError::GuestExecutionHungOnHostFunctionCall()
377 | HyperlightError::GuestFunctionCallAlreadyInProgress()
378 | HyperlightError::GuestInterfaceUnsupportedType(_)
379 | HyperlightError::HostFunctionNotFound(_)
380 | HyperlightError::HyperlightVmError(HyperlightVmError::Create(_))
381 | HyperlightError::HyperlightVmError(HyperlightVmError::Initialize(_))
382 | HyperlightError::HyperlightVmError(HyperlightVmError::MapRegion(_))
383 | HyperlightError::HyperlightVmError(HyperlightVmError::UnmapRegion(_))
384 | HyperlightError::IOError(_)
385 | HyperlightError::IntConversionFailure(_)
386 | HyperlightError::InvalidFlatBuffer(_)
387 | HyperlightError::JsonConversionFailure(_)
388 | HyperlightError::LockAttemptFailed(_)
389 | HyperlightError::MemoryAllocationFailed(_)
390 | HyperlightError::MemoryProtectionFailed(_)
391 | HyperlightError::MemoryRequestTooBig(_, _)
392 | HyperlightError::MemoryRequestTooSmall(_, _)
393 | HyperlightError::MetricNotFound(_)
394 | HyperlightError::MmapFailed(_)
395 | HyperlightError::MprotectFailed(_)
396 | HyperlightError::NoHypervisorFound()
397 | HyperlightError::NoMemorySnapshot
398 | HyperlightError::ParameterValueConversionFailure(_, _)
399 | HyperlightError::PEFileProcessingFailure(_)
400 | HyperlightError::RawPointerLessThanBaseAddress(_, _)
401 | HyperlightError::RefCellBorrowFailed(_)
402 | HyperlightError::RefCellMutBorrowFailed(_)
403 | HyperlightError::ReturnValueConversionFailure(_, _)
404 | HyperlightError::SnapshotLayoutMismatch
405 | HyperlightError::SnapshotHostFunctionMismatch { .. }
406 | HyperlightError::SystemTimeError(_)
407 | HyperlightError::TryFromSliceError(_)
408 | HyperlightError::UnexpectedNoOfArguments(_, _)
409 | HyperlightError::UnexpectedParameterValueType(_, _)
410 | HyperlightError::UnexpectedReturnValueType(_, _)
411 | HyperlightError::UTF8StringConversionFailure(_)
412 | HyperlightError::VectorCapacityIncorrect(_, _, _) => false,
413
414 #[cfg(target_os = "windows")]
415 HyperlightError::CrossBeamReceiveError(_) => false,
416 #[cfg(target_os = "windows")]
417 HyperlightError::CrossBeamSendError(_) => false,
418 #[cfg(target_os = "windows")]
419 HyperlightError::WindowsAPIError(_) => false,
420 #[cfg(target_os = "linux")]
421 HyperlightError::VmmSysError(_) => false,
422 }
423 }
424}
425
426#[macro_export]
428macro_rules! new_error {
429 ($msg:literal $(,)?) => {{
430 let __args = std::format_args!($msg);
431 let __err_msg = match __args.as_str() {
432 Some(msg) => String::from(msg),
433 None => std::format!($msg),
434 };
435 $crate::HyperlightError::Error(__err_msg)
436 }};
437 ($fmtstr:expr, $($arg:tt)*) => {{
438 let __err_msg = std::format!($fmtstr, $($arg)*);
439 $crate::error::HyperlightError::Error(__err_msg)
440 }};
441}
442
443#[cfg(test)]
444mod tests {
445 use super::*;
446 use crate::hypervisor::hyperlight_vm::{
447 DispatchGuestCallError, HandleIoError, HyperlightVmError, RunVmError,
448 };
449 use crate::sandbox::outb::HandleOutbError;
450
451 #[test]
453 fn test_promote_execution_cancelled_by_host() {
454 let err = DispatchGuestCallError::Run(RunVmError::ExecutionCancelledByHost);
455 let (promoted, should_poison) = err.promote();
456
457 assert!(
458 should_poison,
459 "ExecutionCancelledByHost should poison the sandbox"
460 );
461 assert!(
462 matches!(promoted, HyperlightError::ExecutionCanceledByHost()),
463 "Expected HyperlightError::ExecutionCanceledByHost, got {:?}",
464 promoted
465 );
466 }
467
468 #[test]
470 fn test_promote_guest_aborted() {
471 let err = DispatchGuestCallError::Run(RunVmError::HandleIo(HandleIoError::Outb(
472 HandleOutbError::GuestAborted {
473 code: 42,
474 message: "test abort".to_string(),
475 },
476 )));
477 let (promoted, should_poison) = err.promote();
478
479 assert!(should_poison, "GuestAborted should poison the sandbox");
480 match promoted {
481 HyperlightError::GuestAborted(code, msg) => {
482 assert_eq!(code, 42);
483 assert_eq!(msg, "test abort");
484 }
485 _ => panic!("Expected HyperlightError::GuestAborted, got {:?}", promoted),
486 }
487 }
488
489 #[test]
491 fn test_promote_memory_access_violation() {
492 let err = DispatchGuestCallError::Run(RunVmError::MemoryAccessViolation {
493 addr: 0xDEADBEEF,
494 access_type: MemoryRegionFlags::WRITE,
495 region_flags: MemoryRegionFlags::READ,
496 });
497 let (promoted, should_poison) = err.promote();
498
499 assert!(
500 should_poison,
501 "MemoryAccessViolation should poison the sandbox"
502 );
503 match promoted {
504 HyperlightError::MemoryAccessViolation(addr, access_type, region_flags) => {
505 assert_eq!(addr, 0xDEADBEEF);
506 assert_eq!(access_type, MemoryRegionFlags::WRITE);
507 assert_eq!(region_flags, MemoryRegionFlags::READ);
508 }
509 _ => panic!(
510 "Expected HyperlightError::MemoryAccessViolation, got {:?}",
511 promoted
512 ),
513 }
514 }
515
516 #[test]
518 fn test_promote_other_run_errors_wrapped() {
519 let err = DispatchGuestCallError::Run(RunVmError::MmioReadUnmapped(0x1000));
520 let (promoted, should_poison) = err.promote();
521
522 assert!(should_poison, "Run errors should poison the sandbox");
523 assert!(
524 matches!(
525 promoted,
526 HyperlightError::HyperlightVmError(HyperlightVmError::DispatchGuestCall(_))
527 ),
528 "Expected HyperlightError::HyperlightVmError, got {:?}",
529 promoted
530 );
531 }
532}