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("SystemTimeError {0:?}")]
221 SystemTimeError(#[from] SystemTimeError),
222
223 #[error("TryFromSliceError {0:?}")]
225 TryFromSliceError(#[from] TryFromSliceError),
226
227 #[error("The number of arguments to the function is wrong: got {0:?} expected {1:?}")]
229 UnexpectedNoOfArguments(usize, usize),
230
231 #[error("The parameter value type is unexpected got {0:?} expected {1:?}")]
233 UnexpectedParameterValueType(ParameterValue, String),
234
235 #[error("The return value type is unexpected got {0:?} expected {1:?}")]
237 UnexpectedReturnValueType(ReturnValue, String),
238
239 #[error("String Conversion of UTF8 data to str failed")]
241 UTF8StringConversionFailure(#[from] FromUtf8Error),
242
243 #[error(
245 "The capacity of the vector is incorrect. Capacity: {0}, Length: {1}, FlatBuffer Size: {2}"
246 )]
247 VectorCapacityIncorrect(usize, usize, i32),
248
249 #[error("vmm sys Error {0:?}")]
251 #[cfg(target_os = "linux")]
252 VmmSysError(vmm_sys_util::errno::Error),
253}
254
255impl From<Infallible> for HyperlightError {
256 fn from(_: Infallible) -> Self {
257 "Impossible as this is an infallible error".into()
258 }
259}
260
261impl From<&str> for HyperlightError {
262 fn from(s: &str) -> Self {
263 HyperlightError::Error(s.to_string())
264 }
265}
266
267impl<T> From<PoisonError<MutexGuard<'_, T>>> for HyperlightError {
268 fn from(e: PoisonError<MutexGuard<'_, T>>) -> Self {
272 let source = match e.source() {
273 Some(s) => s.to_string(),
274 None => String::from(""),
275 };
276 HyperlightError::LockAttemptFailed(source)
277 }
278}
279
280#[macro_export]
282macro_rules! new_error {
283 ($msg:literal $(,)?) => {{
284 let __args = std::format_args!($msg);
285 let __err_msg = match __args.as_str() {
286 Some(msg) => String::from(msg),
287 None => std::format!($msg),
288 };
289 $crate::HyperlightError::Error(__err_msg)
290 }};
291 ($fmtstr:expr, $($arg:tt)*) => {{
292 let __err_msg = std::format!($fmtstr, $($arg)*);
293 $crate::error::HyperlightError::Error(__err_msg)
294 }};
295}
296
297#[cfg(test)]
298mod tests {
299 use super::*;
300 use crate::hypervisor::hyperlight_vm::{
301 DispatchGuestCallError, HandleIoError, HyperlightVmError, RunVmError,
302 };
303 use crate::sandbox::outb::HandleOutbError;
304
305 #[test]
307 fn test_promote_execution_cancelled_by_host() {
308 let err = DispatchGuestCallError::Run(RunVmError::ExecutionCancelledByHost);
309 let (promoted, should_poison) = err.promote();
310
311 assert!(
312 should_poison,
313 "ExecutionCancelledByHost should poison the sandbox"
314 );
315 assert!(
316 matches!(promoted, HyperlightError::ExecutionCanceledByHost()),
317 "Expected HyperlightError::ExecutionCanceledByHost, got {:?}",
318 promoted
319 );
320 }
321
322 #[test]
324 fn test_promote_guest_aborted() {
325 let err = DispatchGuestCallError::Run(RunVmError::HandleIo(HandleIoError::Outb(
326 HandleOutbError::GuestAborted {
327 code: 42,
328 message: "test abort".to_string(),
329 },
330 )));
331 let (promoted, should_poison) = err.promote();
332
333 assert!(should_poison, "GuestAborted should poison the sandbox");
334 match promoted {
335 HyperlightError::GuestAborted(code, msg) => {
336 assert_eq!(code, 42);
337 assert_eq!(msg, "test abort");
338 }
339 _ => panic!("Expected HyperlightError::GuestAborted, got {:?}", promoted),
340 }
341 }
342
343 #[test]
345 fn test_promote_memory_access_violation() {
346 let err = DispatchGuestCallError::Run(RunVmError::MemoryAccessViolation {
347 addr: 0xDEADBEEF,
348 access_type: MemoryRegionFlags::WRITE,
349 region_flags: MemoryRegionFlags::READ,
350 });
351 let (promoted, should_poison) = err.promote();
352
353 assert!(
354 should_poison,
355 "MemoryAccessViolation should poison the sandbox"
356 );
357 match promoted {
358 HyperlightError::MemoryAccessViolation(addr, access_type, region_flags) => {
359 assert_eq!(addr, 0xDEADBEEF);
360 assert_eq!(access_type, MemoryRegionFlags::WRITE);
361 assert_eq!(region_flags, MemoryRegionFlags::READ);
362 }
363 _ => panic!(
364 "Expected HyperlightError::MemoryAccessViolation, got {:?}",
365 promoted
366 ),
367 }
368 }
369
370 #[test]
372 fn test_promote_other_run_errors_wrapped() {
373 let err = DispatchGuestCallError::Run(RunVmError::MmioReadUnmapped(0x1000));
374 let (promoted, should_poison) = err.promote();
375
376 assert!(should_poison, "Run errors should poison the sandbox");
377 assert!(
378 matches!(
379 promoted,
380 HyperlightError::HyperlightVmError(HyperlightVmError::DispatchGuestCall(_))
381 ),
382 "Expected HyperlightError::HyperlightVmError, got {:?}",
383 promoted
384 );
385 }
386}