hyperlight_host/
error.rs

1/*
2Copyright 2025  The Hyperlight Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#[cfg(mshv2)]
18extern crate mshv_ioctls2 as mshv_ioctls;
19
20#[cfg(mshv3)]
21extern crate mshv_ioctls3 as mshv_ioctls;
22
23use std::array::TryFromSliceError;
24use std::cell::{BorrowError, BorrowMutError};
25use std::convert::Infallible;
26use std::error::Error;
27use std::num::TryFromIntError;
28use std::string::FromUtf8Error;
29use std::sync::{MutexGuard, PoisonError};
30use std::time::SystemTimeError;
31
32#[cfg(target_os = "windows")]
33use crossbeam_channel::{RecvError, SendError};
34use flatbuffers::InvalidFlatbuffer;
35use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnValue};
36use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
37use thiserror::Error;
38
39#[cfg(target_os = "windows")]
40use crate::hypervisor::wrappers::HandleWrapper;
41use crate::mem::memory_region::MemoryRegionFlags;
42use crate::mem::ptr::RawPtr;
43
44/// The error type for Hyperlight operations
45#[derive(Error, Debug)]
46pub enum HyperlightError {
47    /// Anyhow error
48    #[error("Anyhow Error was returned: {0}")]
49    AnyhowError(#[from] anyhow::Error),
50    /// Memory access out of bounds
51    #[error("Offset: {0} out of bounds, Max is: {1}")]
52    BoundsCheckFailed(u64, usize),
53
54    /// Checked Add Overflow
55    #[error("Couldn't add offset to base address. Offset: {0}, Base Address: {1}")]
56    CheckedAddOverflow(u64, u64),
57
58    /// Cross beam channel receive error
59    #[error("{0:?}")]
60    #[cfg(target_os = "windows")]
61    CrossBeamReceiveError(#[from] RecvError),
62
63    /// Cross beam channel send error
64    #[error("{0:?}")]
65    #[cfg(target_os = "windows")]
66    CrossBeamSendError(#[from] SendError<HandleWrapper>),
67
68    /// CString conversion error
69    #[error("Error converting CString {0:?}")]
70    CStringConversionError(#[from] std::ffi::NulError),
71
72    /// A disallowed syscall was caught
73    #[error("Seccomp filter trapped on disallowed syscall (check STDERR for offending syscall)")]
74    #[cfg(all(feature = "seccomp", target_os = "linux"))]
75    DisallowedSyscall,
76
77    /// A generic error with a message
78    #[error("{0}")]
79    Error(String),
80
81    /// Execution violation
82    #[error("Non-executable address {0:#x} tried to be executed")]
83    ExecutionAccessViolation(u64),
84
85    /// Guest execution was cancelled by the host
86    #[error("Execution was cancelled by the host.")]
87    ExecutionCanceledByHost(),
88
89    /// Accessing the value of a flatbuffer parameter failed
90    #[error("Failed to get a value from flat buffer parameter")]
91    FailedToGetValueFromParameter(),
92
93    ///Field Name not found in decoded GuestLogData
94    #[error("Field Name {0} not found in decoded GuestLogData")]
95    FieldIsMissingInGuestLogData(String),
96
97    /// Guest aborted during outb
98    #[error("Guest aborted: {0} {1}")]
99    GuestAborted(u8, String),
100
101    /// Guest call resulted in error in guest
102    #[error("Guest error occurred {0:?}: {1}")]
103    GuestError(ErrorCode, String),
104
105    /// An attempt to cancel guest execution failed because it is hanging on a host function call
106    #[error("Guest execution hung on the execution of a host function call")]
107    GuestExecutionHungOnHostFunctionCall(),
108
109    /// Guest call already in progress
110    #[error("Guest call is already in progress")]
111    GuestFunctionCallAlreadyInProgress(),
112
113    /// The given type is not supported by the guest interface.
114    #[error("Unsupported type: {0}")]
115    GuestInterfaceUnsupportedType(String),
116
117    /// The guest offset is invalid.
118    #[error("The guest offset {0} is invalid.")]
119    GuestOffsetIsInvalid(usize),
120
121    /// A Host function was called by the guest but it was not registered.
122    #[error("HostFunction {0} was not found")]
123    HostFunctionNotFound(String),
124
125    /// Reading Writing or Seeking data failed.
126    #[error("Reading Writing or Seeking data failed {0:?}")]
127    IOError(#[from] std::io::Error),
128
129    /// Failed to convert to Integer
130    #[error("Failed To Convert Size to usize")]
131    IntConversionFailure(#[from] TryFromIntError),
132
133    /// The flatbuffer is invalid
134    #[error("The flatbuffer is invalid")]
135    InvalidFlatBuffer(#[from] InvalidFlatbuffer),
136
137    /// Conversion of str to Json failed
138    #[error("Conversion of str data to json failed")]
139    JsonConversionFailure(#[from] serde_json::Error),
140
141    /// An attempt to get a lock from a Mutex failed.
142    #[error("Unable to lock resource")]
143    LockAttemptFailed(String),
144
145    /// Memory Access Violation at the given address. The access type and memory region flags are provided.
146    #[error("Memory Access Violation at address {0:#x} of type {1}, but memory is marked as {2}")]
147    MemoryAccessViolation(u64, MemoryRegionFlags, MemoryRegionFlags),
148
149    /// Memory Allocation Failed.
150    #[error("Memory Allocation Failed with OS Error {0:?}.")]
151    MemoryAllocationFailed(Option<i32>),
152
153    /// Memory Protection Failed
154    #[error("Memory Protection Failed with OS Error {0:?}.")]
155    MemoryProtectionFailed(Option<i32>),
156
157    /// The memory request exceeds the maximum size allowed
158    #[error("Memory requested {0} exceeds maximum size allowed {1}")]
159    MemoryRequestTooBig(usize, usize),
160
161    /// Metric Not Found.
162    #[error("Metric Not Found {0:?}.")]
163    MetricNotFound(&'static str),
164
165    /// mmap Failed.
166    #[error("mmap failed with os error {0:?}")]
167    MmapFailed(Option<i32>),
168
169    /// mprotect Failed.
170    #[error("mprotect failed with os error {0:?}")]
171    MprotectFailed(Option<i32>),
172
173    /// mshv Error Occurred
174    #[error("mshv Error {0:?}")]
175    #[cfg(mshv)]
176    MSHVError(#[from] mshv_ioctls::MshvError),
177
178    /// No Hypervisor was found for Sandbox.
179    #[error("No Hypervisor was found for Sandbox")]
180    NoHypervisorFound(),
181
182    /// Restore_state called with no valid snapshot
183    #[error("Restore_state called with no valid snapshot")]
184    NoMemorySnapshot,
185
186    /// Failed to get value from parameter value
187    #[error("Failed To Convert Parameter Value {0:?} to {1:?}")]
188    ParameterValueConversionFailure(ParameterValue, &'static str),
189
190    /// a failure occurred processing a PE file
191    #[error("Failure processing PE File {0:?}")]
192    PEFileProcessingFailure(#[from] goblin::error::Error),
193
194    /// Raw pointer is less than base address
195    #[error("Raw pointer ({0:?}) was less than the base address ({1})")]
196    RawPointerLessThanBaseAddress(RawPtr, u64),
197
198    /// RefCell borrow failed
199    #[error("RefCell borrow failed")]
200    RefCellBorrowFailed(#[from] BorrowError),
201
202    /// RefCell mut borrow failed
203    #[error("RefCell mut borrow failed")]
204    RefCellMutBorrowFailed(#[from] BorrowMutError),
205
206    /// Failed to get value from return value
207    #[error("Failed To Convert Return Value {0:?} to {1:?}")]
208    ReturnValueConversionFailure(ReturnValue, &'static str),
209
210    /// Stack overflow detected in guest
211    #[error("Stack overflow detected")]
212    StackOverflow(),
213
214    /// a backend error occurred with seccomp filters
215    #[error("Backend Error with Seccomp Filter {0:?}")]
216    #[cfg(all(feature = "seccomp", target_os = "linux"))]
217    SeccompFilterBackendError(#[from] seccompiler::BackendError),
218
219    /// an error occurred with seccomp filters
220    #[error("Error with Seccomp Filter {0:?}")]
221    #[cfg(all(feature = "seccomp", target_os = "linux"))]
222    SeccompFilterError(#[from] seccompiler::Error),
223
224    /// SystemTimeError
225    #[error("SystemTimeError {0:?}")]
226    SystemTimeError(#[from] SystemTimeError),
227
228    /// Error occurred when translating guest address
229    #[error("An error occurred when translating guest address: {0:?}")]
230    #[cfg(gdb)]
231    TranslateGuestAddress(u64),
232
233    /// Error occurred converting a slice to an array
234    #[error("TryFromSliceError {0:?}")]
235    TryFromSliceError(#[from] TryFromSliceError),
236
237    /// A function was called with an incorrect number of arguments
238    #[error("The number of arguments to the function is wrong: got {0:?} expected {1:?}")]
239    UnexpectedNoOfArguments(usize, usize),
240
241    /// The parameter value type is unexpected
242    #[error("The parameter value type is unexpected got {0:?} expected {1:?}")]
243    UnexpectedParameterValueType(ParameterValue, String),
244
245    /// The return value type is unexpected
246    #[error("The return value type is unexpected got {0:?} expected {1:?}")]
247    UnexpectedReturnValueType(ReturnValue, String),
248
249    /// Slice conversion to UTF8 failed
250    #[error("String Conversion of UTF8 data to str failed")]
251    UTF8StringConversionFailure(#[from] FromUtf8Error),
252
253    /// The capacity of the vector is incorrect
254    #[error(
255        "The capacity of the vector is incorrect. Capacity: {0}, Length: {1}, FlatBuffer Size: {2}"
256    )]
257    VectorCapacityIncorrect(usize, usize, i32),
258
259    /// vmm sys Error Occurred
260    #[error("vmm sys Error {0:?}")]
261    #[cfg(target_os = "linux")]
262    VmmSysError(#[from] vmm_sys_util::errno::Error),
263
264    /// Windows Error
265    #[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    // Implemented this way rather than passing the error as a source to LockAttemptFailed as that would require
284    // Box<dyn Error + Send + Sync> which is not easy to implement for PoisonError<MutexGuard<'_, T>>
285    // This is a good enough solution and allows use to use the ? operator on lock() calls
286    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
295/// Creates a `HyperlightError::Error` from a string literal or format string
296#[macro_export]
297macro_rules! new_error {
298    ($msg:literal $(,)?) => {{
299        let __args = std::format_args!($msg);
300        let __err_msg = match __args.as_str() {
301            Some(msg) => String::from(msg),
302            None => std::format!($msg),
303        };
304        $crate::HyperlightError::Error(__err_msg)
305    }};
306    ($fmtstr:expr, $($arg:tt)*) => {{
307           let __err_msg = std::format!($fmtstr, $($arg)*);
308           $crate::error::HyperlightError::Error(__err_msg)
309    }};
310}