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 hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnValue};
29use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
30use thiserror::Error;
31
32use crate::hypervisor::hyperlight_vm::HyperlightVmError;
33#[cfg(target_os = "windows")]
34use crate::hypervisor::wrappers::HandleWrapper;
35use crate::mem::memory_region::MemoryRegionFlags;
36use crate::mem::ptr::RawPtr;
37
38#[derive(Error, Debug)]
40pub enum HyperlightError {
41 #[error("Anyhow Error was returned: {0}")]
43 AnyhowError(#[from] anyhow::Error),
44 #[error("Offset: {0} out of bounds, Max is: {1}")]
46 BoundsCheckFailed(u64, usize),
47
48 #[error("Couldn't add offset to base address. Offset: {0}, Base Address: {1}")]
50 CheckedAddOverflow(u64, u64),
51
52 #[error("{0:?}")]
54 #[cfg(target_os = "windows")]
55 CrossBeamReceiveError(#[from] RecvError),
56
57 #[error("{0:?}")]
59 #[cfg(target_os = "windows")]
60 CrossBeamSendError(#[from] SendError<HandleWrapper>),
61
62 #[error("Error converting CString {0:?}")]
64 CStringConversionError(#[from] std::ffi::NulError),
65
66 #[error("{0}")]
68 Error(String),
69
70 #[error("Non-executable address {0:#x} tried to be executed")]
72 ExecutionAccessViolation(u64),
73
74 #[error("Execution was cancelled by the host.")]
76 ExecutionCanceledByHost(),
77
78 #[error("Failed to get a value from flat buffer parameter")]
80 FailedToGetValueFromParameter(),
81
82 #[error("Field Name {0} not found in decoded GuestLogData")]
84 FieldIsMissingInGuestLogData(String),
85
86 #[error("Guest aborted: {0} {1}")]
88 GuestAborted(u8, String),
89
90 #[error("Guest error occurred {0:?}: {1}")]
92 GuestError(ErrorCode, String),
93
94 #[error("Guest execution hung on the execution of a host function call")]
96 GuestExecutionHungOnHostFunctionCall(),
97
98 #[error("Guest call is already in progress")]
100 GuestFunctionCallAlreadyInProgress(),
101
102 #[error("Unsupported type: {0}")]
104 GuestInterfaceUnsupportedType(String),
105
106 #[error(
110 "Guest binary was built with hyperlight-guest-bin {guest_bin_version}, \
111 but the host is running hyperlight {host_version}"
112 )]
113 GuestBinVersionMismatch {
114 guest_bin_version: String,
116 host_version: String,
118 },
119
120 #[error("HostFunction {0} was not found")]
122 HostFunctionNotFound(String),
123
124 #[doc(hidden)]
129 #[error("Internal Hyperlight VM error: {0}")]
130 HyperlightVmError(#[from] HyperlightVmError),
131
132 #[error("Reading Writing or Seeking data failed {0:?}")]
134 IOError(#[from] std::io::Error),
135
136 #[error("Failed To Convert Size to usize")]
138 IntConversionFailure(#[from] TryFromIntError),
139
140 #[error("Conversion of str data to json failed")]
142 JsonConversionFailure(#[from] serde_json::Error),
143
144 #[error("Unable to lock resource")]
146 LockAttemptFailed(String),
147
148 #[error("Memory Access Violation at address {0:#x} of type {1}, but memory is marked as {2}")]
150 MemoryAccessViolation(u64, MemoryRegionFlags, MemoryRegionFlags),
151
152 #[error("Memory Allocation Failed with OS Error {0:?}.")]
154 MemoryAllocationFailed(Option<i32>),
155
156 #[error("Memory Protection Failed with OS Error {0:?}.")]
158 MemoryProtectionFailed(Option<i32>),
159
160 #[error("Memory region size mismatch: host size {0:?}, guest size {1:?} region {2:?}")]
162 MemoryRegionSizeMismatch(usize, usize, String),
163
164 #[error("Memory requested {0} exceeds maximum size allowed {1}")]
166 MemoryRequestTooBig(usize, usize),
167
168 #[error("Memory requested {0} is less than the minimum size allowed {1}")]
171 MemoryRequestTooSmall(usize, usize),
172
173 #[error("Metric Not Found {0:?}.")]
175 MetricNotFound(&'static str),
176
177 #[error("mmap failed with os error {0:?}")]
179 MmapFailed(Option<i32>),
180
181 #[error("mprotect failed with os error {0:?}")]
183 MprotectFailed(Option<i32>),
184
185 #[error("No Hypervisor was found for Sandbox")]
187 NoHypervisorFound(),
188
189 #[error("Restore_state called with no valid snapshot")]
191 NoMemorySnapshot,
192
193 #[error("Failed To Convert Parameter Value {0:?} to {1:?}")]
195 ParameterValueConversionFailure(ParameterValue, &'static str),
196
197 #[error("Failure processing PE File {0:?}")]
199 PEFileProcessingFailure(#[from] goblin::error::Error),
200
201 #[error("The sandbox was poisoned")]
220 PoisonedSandbox,
221
222 #[error("Raw pointer ({0:?}) was less than the base address ({1})")]
224 RawPointerLessThanBaseAddress(RawPtr, u64),
225
226 #[error("RefCell borrow failed")]
228 RefCellBorrowFailed(#[from] BorrowError),
229
230 #[error("RefCell mut borrow failed")]
232 RefCellMutBorrowFailed(#[from] BorrowMutError),
233
234 #[error("Failed To Convert Return Value {0:?} to {1:?}")]
236 ReturnValueConversionFailure(ReturnValue, &'static str),
237
238 #[error("Snapshot was taken from a different sandbox")]
240 SnapshotSandboxMismatch,
241
242 #[error("SystemTimeError {0:?}")]
244 SystemTimeError(#[from] SystemTimeError),
245
246 #[error("TryFromSliceError {0:?}")]
248 TryFromSliceError(#[from] TryFromSliceError),
249
250 #[error("The number of arguments to the function is wrong: got {0:?} expected {1:?}")]
252 UnexpectedNoOfArguments(usize, usize),
253
254 #[error("The parameter value type is unexpected got {0:?} expected {1:?}")]
256 UnexpectedParameterValueType(ParameterValue, String),
257
258 #[error("The return value type is unexpected got {0:?} expected {1:?}")]
260 UnexpectedReturnValueType(ReturnValue, String),
261
262 #[error("String Conversion of UTF8 data to str failed")]
264 UTF8StringConversionFailure(#[from] FromUtf8Error),
265
266 #[error(
268 "The capacity of the vector is incorrect. Capacity: {0}, Length: {1}, FlatBuffer Size: {2}"
269 )]
270 VectorCapacityIncorrect(usize, usize, i32),
271
272 #[error("vmm sys Error {0:?}")]
274 #[cfg(target_os = "linux")]
275 VmmSysError(vmm_sys_util::errno::Error),
276
277 #[cfg(target_os = "windows")]
279 #[error("Windows API Error Result {0:?}")]
280 WindowsAPIError(#[from] windows_result::Error),
281}
282
283impl From<Infallible> for HyperlightError {
284 fn from(_: Infallible) -> Self {
285 "Impossible as this is an infallible error".into()
286 }
287}
288
289impl From<&str> for HyperlightError {
290 fn from(s: &str) -> Self {
291 HyperlightError::Error(s.to_string())
292 }
293}
294
295impl<T> From<PoisonError<MutexGuard<'_, T>>> for HyperlightError {
296 fn from(e: PoisonError<MutexGuard<'_, T>>) -> Self {
300 let source = match e.source() {
301 Some(s) => s.to_string(),
302 None => String::from(""),
303 };
304 HyperlightError::LockAttemptFailed(source)
305 }
306}
307
308impl HyperlightError {
309 #[allow(dead_code)]
321 pub(crate) fn is_poison_error(&self) -> bool {
322 match self {
325 HyperlightError::GuestAborted(_, _)
328 | HyperlightError::ExecutionCanceledByHost()
329 | HyperlightError::PoisonedSandbox
330 | HyperlightError::ExecutionAccessViolation(_)
331 | HyperlightError::MemoryAccessViolation(_, _, _)
332 | HyperlightError::MemoryRegionSizeMismatch(_, _, _)
333 | HyperlightError::HyperlightVmError(HyperlightVmError::Restore(_)) => true,
336
337 HyperlightError::HyperlightVmError(HyperlightVmError::UpdateRegion(_))
341 | HyperlightError::HyperlightVmError(HyperlightVmError::AccessPageTable(_)) => true,
342
343 HyperlightError::HyperlightVmError(HyperlightVmError::DispatchGuestCall(e)) => {
345 e.is_poison_error()
346 }
347
348 HyperlightError::AnyhowError(_)
350 | HyperlightError::BoundsCheckFailed(_, _)
351 | HyperlightError::CheckedAddOverflow(_, _)
352 | HyperlightError::CStringConversionError(_)
353 | HyperlightError::Error(_)
354 | HyperlightError::FailedToGetValueFromParameter()
355 | HyperlightError::FieldIsMissingInGuestLogData(_)
356 | HyperlightError::GuestBinVersionMismatch { .. }
357 | HyperlightError::GuestError(_, _)
358 | HyperlightError::GuestExecutionHungOnHostFunctionCall()
359 | HyperlightError::GuestFunctionCallAlreadyInProgress()
360 | HyperlightError::GuestInterfaceUnsupportedType(_)
361 | HyperlightError::HostFunctionNotFound(_)
362 | HyperlightError::HyperlightVmError(HyperlightVmError::Create(_))
363 | HyperlightError::HyperlightVmError(HyperlightVmError::Initialize(_))
364 | HyperlightError::HyperlightVmError(HyperlightVmError::MapRegion(_))
365 | HyperlightError::HyperlightVmError(HyperlightVmError::UnmapRegion(_))
366 | HyperlightError::IOError(_)
367 | HyperlightError::IntConversionFailure(_)
368 | HyperlightError::JsonConversionFailure(_)
369 | HyperlightError::LockAttemptFailed(_)
370 | HyperlightError::MemoryAllocationFailed(_)
371 | HyperlightError::MemoryProtectionFailed(_)
372 | HyperlightError::MemoryRequestTooBig(_, _)
373 | HyperlightError::MemoryRequestTooSmall(_, _)
374 | HyperlightError::MetricNotFound(_)
375 | HyperlightError::MmapFailed(_)
376 | HyperlightError::MprotectFailed(_)
377 | HyperlightError::NoHypervisorFound()
378 | HyperlightError::NoMemorySnapshot
379 | HyperlightError::ParameterValueConversionFailure(_, _)
380 | HyperlightError::PEFileProcessingFailure(_)
381 | HyperlightError::RawPointerLessThanBaseAddress(_, _)
382 | HyperlightError::RefCellBorrowFailed(_)
383 | HyperlightError::RefCellMutBorrowFailed(_)
384 | HyperlightError::ReturnValueConversionFailure(_, _)
385 | HyperlightError::SnapshotSandboxMismatch
386 | HyperlightError::SystemTimeError(_)
387 | HyperlightError::TryFromSliceError(_)
388 | HyperlightError::UnexpectedNoOfArguments(_, _)
389 | HyperlightError::UnexpectedParameterValueType(_, _)
390 | HyperlightError::UnexpectedReturnValueType(_, _)
391 | HyperlightError::UTF8StringConversionFailure(_)
392 | HyperlightError::VectorCapacityIncorrect(_, _, _) => false,
393
394 #[cfg(target_os = "windows")]
395 HyperlightError::CrossBeamReceiveError(_) => false,
396 #[cfg(target_os = "windows")]
397 HyperlightError::CrossBeamSendError(_) => false,
398 #[cfg(target_os = "windows")]
399 HyperlightError::WindowsAPIError(_) => false,
400 #[cfg(target_os = "linux")]
401 HyperlightError::VmmSysError(_) => false,
402 }
403 }
404}
405
406#[macro_export]
408macro_rules! new_error {
409 ($msg:literal $(,)?) => {{
410 let __args = std::format_args!($msg);
411 let __err_msg = match __args.as_str() {
412 Some(msg) => String::from(msg),
413 None => std::format!($msg),
414 };
415 $crate::HyperlightError::Error(__err_msg)
416 }};
417 ($fmtstr:expr, $($arg:tt)*) => {{
418 let __err_msg = std::format!($fmtstr, $($arg)*);
419 $crate::error::HyperlightError::Error(__err_msg)
420 }};
421}
422
423#[cfg(test)]
424mod tests {
425 use super::*;
426 use crate::hypervisor::hyperlight_vm::{
427 DispatchGuestCallError, HandleIoError, HyperlightVmError, RunVmError,
428 };
429 use crate::sandbox::outb::HandleOutbError;
430
431 #[test]
433 fn test_promote_execution_cancelled_by_host() {
434 let err = DispatchGuestCallError::Run(RunVmError::ExecutionCancelledByHost);
435 let (promoted, should_poison) = err.promote();
436
437 assert!(
438 should_poison,
439 "ExecutionCancelledByHost should poison the sandbox"
440 );
441 assert!(
442 matches!(promoted, HyperlightError::ExecutionCanceledByHost()),
443 "Expected HyperlightError::ExecutionCanceledByHost, got {:?}",
444 promoted
445 );
446 }
447
448 #[test]
450 fn test_promote_guest_aborted() {
451 let err = DispatchGuestCallError::Run(RunVmError::HandleIo(HandleIoError::Outb(
452 HandleOutbError::GuestAborted {
453 code: 42,
454 message: "test abort".to_string(),
455 },
456 )));
457 let (promoted, should_poison) = err.promote();
458
459 assert!(should_poison, "GuestAborted should poison the sandbox");
460 match promoted {
461 HyperlightError::GuestAborted(code, msg) => {
462 assert_eq!(code, 42);
463 assert_eq!(msg, "test abort");
464 }
465 _ => panic!("Expected HyperlightError::GuestAborted, got {:?}", promoted),
466 }
467 }
468
469 #[test]
471 fn test_promote_memory_access_violation() {
472 let err = DispatchGuestCallError::Run(RunVmError::MemoryAccessViolation {
473 addr: 0xDEADBEEF,
474 access_type: MemoryRegionFlags::WRITE,
475 region_flags: MemoryRegionFlags::READ,
476 });
477 let (promoted, should_poison) = err.promote();
478
479 assert!(
480 should_poison,
481 "MemoryAccessViolation should poison the sandbox"
482 );
483 match promoted {
484 HyperlightError::MemoryAccessViolation(addr, access_type, region_flags) => {
485 assert_eq!(addr, 0xDEADBEEF);
486 assert_eq!(access_type, MemoryRegionFlags::WRITE);
487 assert_eq!(region_flags, MemoryRegionFlags::READ);
488 }
489 _ => panic!(
490 "Expected HyperlightError::MemoryAccessViolation, got {:?}",
491 promoted
492 ),
493 }
494 }
495
496 #[test]
498 fn test_promote_other_run_errors_wrapped() {
499 let err = DispatchGuestCallError::Run(RunVmError::MmioReadUnmapped(0x1000));
500 let (promoted, should_poison) = err.promote();
501
502 assert!(should_poison, "Run errors should poison the sandbox");
503 assert!(
504 matches!(
505 promoted,
506 HyperlightError::HyperlightVmError(HyperlightVmError::DispatchGuestCall(_))
507 ),
508 "Expected HyperlightError::HyperlightVmError, got {:?}",
509 promoted
510 );
511 }
512}