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
26use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnValue};
27use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
28use thiserror::Error;
29
30use crate::hypervisor::hyperlight_vm::HyperlightVmError;
31use crate::mem::memory_region::MemoryRegionFlags;
32use crate::mem::ptr::RawPtr;
33
34#[derive(Error, Debug)]
36pub enum HyperlightError {
37 #[error("Anyhow Error was returned: {0}")]
39 AnyhowError(#[from] anyhow::Error),
40 #[error("Offset: {0} out of bounds, Max is: {1}")]
42 BoundsCheckFailed(u64, usize),
43
44 #[error("Couldn't add offset to base address. Offset: {0}, Base Address: {1}")]
46 CheckedAddOverflow(u64, u64),
47
48 #[error("Error converting CString {0:?}")]
50 CStringConversionError(#[from] std::ffi::NulError),
51
52 #[error("{0}")]
54 Error(String),
55
56 #[error("Non-executable address {0:#x} tried to be executed")]
58 ExecutionAccessViolation(u64),
59
60 #[error("Execution was cancelled by the host.")]
62 ExecutionCanceledByHost(),
63
64 #[error("Failed to get a value from flat buffer parameter")]
66 FailedToGetValueFromParameter(),
67
68 #[error("Field Name {0} not found in decoded GuestLogData")]
70 FieldIsMissingInGuestLogData(String),
71
72 #[error("Guest aborted: {0} {1}")]
74 GuestAborted(u8, String),
75
76 #[error("Guest error occurred {0:?}: {1}")]
78 GuestError(ErrorCode, String),
79
80 #[error("Guest execution hung on the execution of a host function call")]
82 GuestExecutionHungOnHostFunctionCall(),
83
84 #[error("Guest call is already in progress")]
86 GuestFunctionCallAlreadyInProgress(),
87
88 #[error("Unsupported type: {0}")]
90 GuestInterfaceUnsupportedType(String),
91
92 #[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("Conversion of str data to json failed")]
127 JsonConversionFailure(#[from] serde_json::Error),
128
129 #[error("Unable to lock resource")]
131 LockAttemptFailed(String),
132
133 #[error("Memory Access Violation at address {0:#x} of type {1}, but memory is marked as {2}")]
135 MemoryAccessViolation(u64, MemoryRegionFlags, MemoryRegionFlags),
136
137 #[error("Memory Allocation Failed with OS Error {0:?}.")]
139 MemoryAllocationFailed(Option<i32>),
140
141 #[error("Memory Protection Failed with OS Error {0:?}.")]
143 MemoryProtectionFailed(Option<i32>),
144
145 #[error("Memory region size mismatch: host size {0:?}, guest size {1:?} region {2:?}")]
147 MemoryRegionSizeMismatch(usize, usize, String),
148
149 #[error("Memory requested {0} exceeds maximum size allowed {1}")]
151 MemoryRequestTooBig(usize, usize),
152
153 #[error("Memory requested {0} is less than the minimum size allowed {1}")]
156 MemoryRequestTooSmall(usize, usize),
157
158 #[error("Metric Not Found {0:?}.")]
160 MetricNotFound(&'static str),
161
162 #[error("mmap failed with os error {0:?}")]
164 MmapFailed(Option<i32>),
165
166 #[error("mprotect failed with os error {0:?}")]
168 MprotectFailed(Option<i32>),
169
170 #[error("No Hypervisor was found for Sandbox")]
172 NoHypervisorFound(),
173
174 #[error("Failed To Convert Parameter Value {0:?} to {1:?}")]
176 ParameterValueConversionFailure(ParameterValue, &'static str),
177
178 #[error("Failure processing PE File {0:?}")]
180 PEFileProcessingFailure(#[from] goblin::error::Error),
181
182 #[error("The sandbox was poisoned")]
201 PoisonedSandbox,
202
203 #[error("Raw pointer ({0:?}) was less than the base address ({1})")]
205 RawPointerLessThanBaseAddress(RawPtr, u64),
206
207 #[error("RefCell borrow failed")]
209 RefCellBorrowFailed(#[from] BorrowError),
210
211 #[error("RefCell mut borrow failed")]
213 RefCellMutBorrowFailed(#[from] BorrowMutError),
214
215 #[error("Failed To Convert Return Value {0:?} to {1:?}")]
217 ReturnValueConversionFailure(ReturnValue, &'static str),
218
219 #[error(
229 "a Hyperlight sandbox was already created in this process; the KVM substrate supports \
230 at most one live sandbox per process (the kernel-shadow is a MAP_FIXED overlay at a \
231 single fixed VA inside the one process-wide guest-VA reservation — a second sandbox \
232 would silently corrupt the first one's guest memory)"
233 )]
234 SandboxAlreadyCreated(),
235
236 #[error("SystemTimeError {0:?}")]
238 SystemTimeError(#[from] SystemTimeError),
239
240 #[error("TryFromSliceError {0:?}")]
242 TryFromSliceError(#[from] TryFromSliceError),
243
244 #[error("The number of arguments to the function is wrong: got {0:?} expected {1:?}")]
246 UnexpectedNoOfArguments(usize, usize),
247
248 #[error("The parameter value type is unexpected got {0:?} expected {1:?}")]
250 UnexpectedParameterValueType(ParameterValue, String),
251
252 #[error("The return value type is unexpected got {0:?} expected {1:?}")]
254 UnexpectedReturnValueType(ReturnValue, String),
255
256 #[error("String Conversion of UTF8 data to str failed")]
258 UTF8StringConversionFailure(#[from] FromUtf8Error),
259
260 #[error(
262 "The capacity of the vector is incorrect. Capacity: {0}, Length: {1}, FlatBuffer Size: {2}"
263 )]
264 VectorCapacityIncorrect(usize, usize, i32),
265
266 #[error("vmm sys Error {0:?}")]
268 #[cfg(target_os = "linux")]
269 VmmSysError(vmm_sys_util::errno::Error),
270}
271
272impl From<Infallible> for HyperlightError {
273 fn from(_: Infallible) -> Self {
274 "Impossible as this is an infallible error".into()
275 }
276}
277
278impl From<&str> for HyperlightError {
279 fn from(s: &str) -> Self {
280 HyperlightError::Error(s.to_string())
281 }
282}
283
284impl<T> From<PoisonError<MutexGuard<'_, T>>> for HyperlightError {
285 fn from(e: PoisonError<MutexGuard<'_, T>>) -> Self {
289 let source = match e.source() {
290 Some(s) => s.to_string(),
291 None => String::from(""),
292 };
293 HyperlightError::LockAttemptFailed(source)
294 }
295}
296
297#[macro_export]
299macro_rules! new_error {
300 ($msg:literal $(,)?) => {{
301 let __args = std::format_args!($msg);
302 let __err_msg = match __args.as_str() {
303 Some(msg) => String::from(msg),
304 None => std::format!($msg),
305 };
306 $crate::HyperlightError::Error(__err_msg)
307 }};
308 ($fmtstr:expr, $($arg:tt)*) => {{
309 let __err_msg = std::format!($fmtstr, $($arg)*);
310 $crate::error::HyperlightError::Error(__err_msg)
311 }};
312}
313
314#[cfg(test)]
315mod tests {
316 use super::*;
317 use crate::hypervisor::hyperlight_vm::{
318 DispatchGuestCallError, HandleIoError, HyperlightVmError, RunVmError,
319 };
320 use crate::sandbox::outb::HandleOutbError;
321
322 #[test]
324 fn test_promote_execution_cancelled_by_host() {
325 let err = DispatchGuestCallError::Run(RunVmError::ExecutionCancelledByHost);
326 let (promoted, should_poison) = err.promote();
327
328 assert!(
329 should_poison,
330 "ExecutionCancelledByHost should poison the sandbox"
331 );
332 assert!(
333 matches!(promoted, HyperlightError::ExecutionCanceledByHost()),
334 "Expected HyperlightError::ExecutionCanceledByHost, got {:?}",
335 promoted
336 );
337 }
338
339 #[test]
341 fn test_promote_guest_aborted() {
342 let err = DispatchGuestCallError::Run(RunVmError::HandleIo(HandleIoError::Outb(
343 HandleOutbError::GuestAborted {
344 code: 42,
345 message: "test abort".to_string(),
346 },
347 )));
348 let (promoted, should_poison) = err.promote();
349
350 assert!(should_poison, "GuestAborted should poison the sandbox");
351 match promoted {
352 HyperlightError::GuestAborted(code, msg) => {
353 assert_eq!(code, 42);
354 assert_eq!(msg, "test abort");
355 }
356 _ => panic!("Expected HyperlightError::GuestAborted, got {:?}", promoted),
357 }
358 }
359
360 #[test]
362 fn test_promote_memory_access_violation() {
363 let err = DispatchGuestCallError::Run(RunVmError::MemoryAccessViolation {
364 addr: 0xDEADBEEF,
365 access_type: MemoryRegionFlags::WRITE,
366 region_flags: MemoryRegionFlags::READ,
367 });
368 let (promoted, should_poison) = err.promote();
369
370 assert!(
371 should_poison,
372 "MemoryAccessViolation should poison the sandbox"
373 );
374 match promoted {
375 HyperlightError::MemoryAccessViolation(addr, access_type, region_flags) => {
376 assert_eq!(addr, 0xDEADBEEF);
377 assert_eq!(access_type, MemoryRegionFlags::WRITE);
378 assert_eq!(region_flags, MemoryRegionFlags::READ);
379 }
380 _ => panic!(
381 "Expected HyperlightError::MemoryAccessViolation, got {:?}",
382 promoted
383 ),
384 }
385 }
386
387 #[test]
389 fn test_promote_other_run_errors_wrapped() {
390 let err = DispatchGuestCallError::Run(RunVmError::MmioReadUnmapped(0x1000));
391 let (promoted, should_poison) = err.promote();
392
393 assert!(should_poison, "Run errors should poison the sandbox");
394 assert!(
395 matches!(
396 promoted,
397 HyperlightError::HyperlightVmError(HyperlightVmError::DispatchGuestCall(_))
398 ),
399 "Expected HyperlightError::HyperlightVmError, got {:?}",
400 promoted
401 );
402 }
403}