1use std::array::TryFromSliceError;
5use std::cell::{BorrowError, BorrowMutError};
6use std::convert::Infallible;
7use std::error::Error;
8use std::num::TryFromIntError;
9use std::string::FromUtf8Error;
10use std::sync::{MutexGuard, PoisonError};
11use std::time::SystemTimeError;
12
13#[cfg(target_os = "windows")]
14use crossbeam_channel::{RecvError, SendError};
15use flatbuffers::InvalidFlatbuffer;
16use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnValue};
17use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
18use thiserror::Error;
19
20use crate::hypervisor::hyperlight_vm::HyperlightVmError;
21#[cfg(target_os = "windows")]
22use crate::hypervisor::wrappers::HandleWrapper;
23use crate::mem::memory_region::MemoryRegionFlags;
24use crate::mem::ptr::RawPtr;
25
26#[derive(Error, Debug)]
28pub enum HyperlightError {
29 #[error("Anyhow Error was returned: {0}")]
31 AnyhowError(#[from] anyhow::Error),
32
33 #[error("Couldn't add offset to base address. Offset: {0}, Base Address: {1}")]
35 CheckedAddOverflow(u64, u64),
36
37 #[error("{0:?}")]
39 #[cfg(target_os = "windows")]
40 CrossBeamReceiveError(#[from] RecvError),
41
42 #[error("{0:?}")]
44 #[cfg(target_os = "windows")]
45 CrossBeamSendError(#[from] SendError<HandleWrapper>),
46
47 #[error("Error converting CString {0:?}")]
49 CStringConversionError(#[from] std::ffi::NulError),
50
51 #[error("{0}")]
53 Error(String),
54
55 #[error("Non-executable address {0:#x} tried to be executed")]
57 ExecutionAccessViolation(u64),
58
59 #[error("Execution was cancelled by the host.")]
61 ExecutionCanceledByHost(),
62
63 #[error("Failed to get a value from flat buffer parameter")]
65 FailedToGetValueFromParameter(),
66
67 #[error("Field Name {0} not found in decoded GuestLogData")]
69 FieldIsMissingInGuestLogData(String),
70
71 #[error("Guest aborted: {0} {1}")]
73 GuestAborted(u8, String),
74
75 #[error("Guest error occurred {0:?}: {1}")]
77 GuestError(ErrorCode, String),
78
79 #[error("Guest execution hung on the execution of a host function call")]
81 GuestExecutionHungOnHostFunctionCall(),
82
83 #[error("Guest call is already in progress")]
85 GuestFunctionCallAlreadyInProgress(),
86
87 #[error("Unsupported type: {0}")]
89 GuestInterfaceUnsupportedType(String),
90
91 #[error(
95 "Guest binary was built with hyperlight-guest-bin {guest_bin_version}, \
96 but the host is running hyperlight {host_version}"
97 )]
98 GuestBinVersionMismatch {
99 guest_bin_version: String,
101 host_version: String,
103 },
104
105 #[error("HostFunction {0} was not found")]
107 HostFunctionNotFound(String),
108
109 #[doc(hidden)]
114 #[error("Internal Hyperlight VM error: {0}")]
115 HyperlightVmError(#[from] HyperlightVmError),
116
117 #[error("Reading Writing or Seeking data failed {0:?}")]
119 IOError(#[from] std::io::Error),
120
121 #[error("Failed To Convert Size to usize")]
123 IntConversionFailure(#[from] TryFromIntError),
124
125 #[error("The flatbuffer is invalid")]
127 InvalidFlatBuffer(#[from] InvalidFlatbuffer),
128
129 #[error("Conversion of str data to json failed")]
131 JsonConversionFailure(#[from] serde_json::Error),
132
133 #[error("Unable to lock resource")]
135 LockAttemptFailed(String),
136
137 #[error("Memory Access Violation at address {0:#x} of type {1}, but memory is marked as {2}")]
139 MemoryAccessViolation(u64, MemoryRegionFlags, MemoryRegionFlags),
140
141 #[error("Memory requested {0} exceeds maximum size allowed {1}")]
143 MemoryRequestTooBig(usize, usize),
144
145 #[error("Memory requested {0} is less than the minimum size allowed {1}")]
148 MemoryRequestTooSmall(usize, usize),
149
150 #[error("Metric Not Found {0:?}.")]
152 MetricNotFound(&'static str),
153
154 #[error("No Hypervisor was found for Sandbox")]
156 NoHypervisorFound(),
157
158 #[error("Restore_state called with no valid snapshot")]
160 NoMemorySnapshot,
161
162 #[error("Failed To Convert Parameter Value {0:?} to {1:?}")]
164 ParameterValueConversionFailure(ParameterValue, &'static str),
165
166 #[error("Failure processing PE File {0:?}")]
168 PEFileProcessingFailure(#[from] goblin::error::Error),
169
170 #[error("The sandbox was poisoned")]
189 PoisonedSandbox,
190
191 #[error("The sandbox is unrecoverable and must be discarded")]
193 UnrecoverableSandbox,
194
195 #[error("Raw pointer ({0:?}) was less than the base address ({1})")]
197 RawPointerLessThanBaseAddress(RawPtr, u64),
198
199 #[error("RefCell borrow failed")]
201 RefCellBorrowFailed(#[from] BorrowError),
202
203 #[error("RefCell mut borrow failed")]
205 RefCellMutBorrowFailed(#[from] BorrowMutError),
206
207 #[error("Failed To Convert Return Value {0:?} to {1:?}")]
209 ReturnValueConversionFailure(ReturnValue, &'static str),
210
211 #[error("Failed to execute shared memory operation: {0}")]
213 SharedMemory(#[from] crate::mem::shared_mem::SharedMemoryError),
214 #[error(
217 "Snapshot host function mismatch: missing=[{}], signature mismatches=[{}]",
218 missing.join(", "),
219 signature_mismatches.join("; ")
220 )]
221 SnapshotHostFunctionMismatch {
222 missing: Vec<String>,
224 signature_mismatches: Vec<String>,
227 },
228
229 #[error("SystemTimeError {0:?}")]
231 SystemTimeError(#[from] SystemTimeError),
232
233 #[error("TryFromSliceError {0:?}")]
235 TryFromSliceError(#[from] TryFromSliceError),
236
237 #[error("The number of arguments to the function is wrong: got {0:?} expected {1:?}")]
239 UnexpectedNoOfArguments(usize, usize),
240
241 #[error("The parameter value type is unexpected got {0:?} expected {1:?}")]
243 UnexpectedParameterValueType(ParameterValue, String),
244
245 #[error("The return value type is unexpected got {0:?} expected {1:?}")]
247 UnexpectedReturnValueType(ReturnValue, String),
248
249 #[error("String Conversion of UTF8 data to str failed")]
251 UTF8StringConversionFailure(#[from] FromUtf8Error),
252
253 #[error(
255 "The capacity of the vector is incorrect. Capacity: {0}, Length: {1}, FlatBuffer Size: {2}"
256 )]
257 VectorCapacityIncorrect(usize, usize, i32),
258
259 #[error("vmm sys Error {0:?}")]
261 #[cfg(target_os = "linux")]
262 VmmSysError(vmm_sys_util::errno::Error),
263
264 #[cfg(target_os = "windows")]
266 #[error("Windows API Error Result {0:?}")]
267 WindowsAPIError(#[from] windows_result::Error),
268}
269
270impl From<Infallible> for HyperlightError {
271 fn from(_: Infallible) -> Self {
272 "Impossible as this is an infallible error".into()
273 }
274}
275
276impl From<&str> for HyperlightError {
277 fn from(s: &str) -> Self {
278 HyperlightError::Error(s.to_string())
279 }
280}
281
282impl<T> From<PoisonError<MutexGuard<'_, T>>> for HyperlightError {
283 fn from(e: PoisonError<MutexGuard<'_, T>>) -> Self {
287 let source = match e.source() {
288 Some(s) => s.to_string(),
289 None => String::from(""),
290 };
291 HyperlightError::LockAttemptFailed(source)
292 }
293}
294
295impl HyperlightError {
296 pub(crate) fn is_poison_error(&self) -> bool {
306 match self {
309 HyperlightError::GuestAborted(_, _)
312 | HyperlightError::ExecutionCanceledByHost()
313 | HyperlightError::PoisonedSandbox
314 | HyperlightError::ExecutionAccessViolation(_)
315 | HyperlightError::MemoryAccessViolation(_, _, _)
316 | HyperlightError::HyperlightVmError(HyperlightVmError::Restore(_)) => true,
319
320 HyperlightError::HyperlightVmError(HyperlightVmError::UpdateRegion(_))
324 | HyperlightError::HyperlightVmError(HyperlightVmError::AccessPageTable(_)) => true,
325
326 HyperlightError::HyperlightVmError(HyperlightVmError::DispatchGuestCall(e)) => {
328 e.is_poison_error()
329 }
330
331 HyperlightError::AnyhowError(_)
333 | HyperlightError::CheckedAddOverflow(_, _)
334 | HyperlightError::CStringConversionError(_)
335 | HyperlightError::Error(_)
336 | HyperlightError::FailedToGetValueFromParameter()
337 | HyperlightError::FieldIsMissingInGuestLogData(_)
338 | HyperlightError::GuestBinVersionMismatch { .. }
339 | HyperlightError::GuestError(_, _)
340 | HyperlightError::GuestExecutionHungOnHostFunctionCall()
341 | HyperlightError::GuestFunctionCallAlreadyInProgress()
342 | HyperlightError::GuestInterfaceUnsupportedType(_)
343 | HyperlightError::HostFunctionNotFound(_)
344 | HyperlightError::HyperlightVmError(HyperlightVmError::Create(_))
345 | HyperlightError::HyperlightVmError(HyperlightVmError::Initialize(_))
346 | HyperlightError::HyperlightVmError(HyperlightVmError::MapRegion(_))
347 | HyperlightError::HyperlightVmError(HyperlightVmError::UnmapRegion(_))
348 | HyperlightError::IOError(_)
349 | HyperlightError::IntConversionFailure(_)
350 | HyperlightError::InvalidFlatBuffer(_)
351 | HyperlightError::JsonConversionFailure(_)
352 | HyperlightError::LockAttemptFailed(_)
353 | HyperlightError::MemoryRequestTooBig(_, _)
354 | HyperlightError::MemoryRequestTooSmall(_, _)
355 | HyperlightError::MetricNotFound(_)
356 | HyperlightError::NoHypervisorFound()
357 | HyperlightError::NoMemorySnapshot
358 | HyperlightError::ParameterValueConversionFailure(_, _)
359 | HyperlightError::PEFileProcessingFailure(_)
360 | HyperlightError::RawPointerLessThanBaseAddress(_, _)
361 | HyperlightError::RefCellBorrowFailed(_)
362 | HyperlightError::RefCellMutBorrowFailed(_)
363 | HyperlightError::ReturnValueConversionFailure(_, _)
364 | HyperlightError::SnapshotHostFunctionMismatch { .. }
365 | HyperlightError::SystemTimeError(_)
366 | HyperlightError::TryFromSliceError(_)
367 | HyperlightError::UnexpectedNoOfArguments(_, _)
368 | HyperlightError::UnexpectedParameterValueType(_, _)
369 | HyperlightError::UnexpectedReturnValueType(_, _)
370 | HyperlightError::UnrecoverableSandbox
371 | HyperlightError::UTF8StringConversionFailure(_)
372 | HyperlightError::VectorCapacityIncorrect(_, _, _)
373 | HyperlightError::SharedMemory(_) => 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 }
384 }
385}
386
387#[macro_export]
389macro_rules! new_error {
390 ($msg:literal $(,)?) => {{
391 let __args = std::format_args!($msg);
392 let __err_msg = match __args.as_str() {
393 Some(msg) => String::from(msg),
394 None => std::format!($msg),
395 };
396 $crate::HyperlightError::Error(__err_msg)
397 }};
398 ($fmtstr:expr, $($arg:tt)*) => {{
399 let __err_msg = std::format!($fmtstr, $($arg)*);
400 $crate::error::HyperlightError::Error(__err_msg)
401 }};
402}
403
404#[cfg(test)]
405mod tests {
406 use super::*;
407 use crate::hypervisor::hyperlight_vm::{
408 DispatchGuestCallError, HandleIoError, HyperlightVmError, RunVmError,
409 };
410 use crate::sandbox::outb::HandleOutbError;
411
412 #[test]
414 fn test_promote_execution_cancelled_by_host() {
415 let err = DispatchGuestCallError::Run(RunVmError::ExecutionCancelledByHost);
416 let (promoted, should_poison) = err.promote();
417
418 assert!(
419 should_poison,
420 "ExecutionCancelledByHost should poison the sandbox"
421 );
422 assert!(
423 matches!(promoted, HyperlightError::ExecutionCanceledByHost()),
424 "Expected HyperlightError::ExecutionCanceledByHost, got {:?}",
425 promoted
426 );
427 }
428
429 #[test]
431 fn test_promote_guest_aborted() {
432 let err = DispatchGuestCallError::Run(RunVmError::HandleIo(HandleIoError::Outb(
433 HandleOutbError::GuestAborted {
434 code: 42,
435 message: "test abort".to_string(),
436 },
437 )));
438 let (promoted, should_poison) = err.promote();
439
440 assert!(should_poison, "GuestAborted should poison the sandbox");
441 match promoted {
442 HyperlightError::GuestAborted(code, msg) => {
443 assert_eq!(code, 42);
444 assert_eq!(msg, "test abort");
445 }
446 _ => panic!("Expected HyperlightError::GuestAborted, got {:?}", promoted),
447 }
448 }
449
450 #[test]
452 fn test_promote_memory_access_violation() {
453 let err = DispatchGuestCallError::Run(RunVmError::MemoryAccessViolation {
454 addr: 0xDEADBEEF,
455 access_type: MemoryRegionFlags::WRITE,
456 region_flags: MemoryRegionFlags::READ,
457 });
458 let (promoted, should_poison) = err.promote();
459
460 assert!(
461 should_poison,
462 "MemoryAccessViolation should poison the sandbox"
463 );
464 match promoted {
465 HyperlightError::MemoryAccessViolation(addr, access_type, region_flags) => {
466 assert_eq!(addr, 0xDEADBEEF);
467 assert_eq!(access_type, MemoryRegionFlags::WRITE);
468 assert_eq!(region_flags, MemoryRegionFlags::READ);
469 }
470 _ => panic!(
471 "Expected HyperlightError::MemoryAccessViolation, got {:?}",
472 promoted
473 ),
474 }
475 }
476
477 #[test]
479 fn test_promote_other_run_errors_wrapped() {
480 let err = DispatchGuestCallError::Run(RunVmError::MmioReadUnmapped(0x1000));
481 let (promoted, should_poison) = err.promote();
482
483 assert!(should_poison, "Run errors should poison the sandbox");
484 assert!(
485 matches!(
486 promoted,
487 HyperlightError::HyperlightVmError(HyperlightVmError::DispatchGuestCall(_))
488 ),
489 "Expected HyperlightError::HyperlightVmError, got {:?}",
490 promoted
491 );
492 }
493}