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    /// KVM Error Occurred
142    #[error("KVM Error {0:?}")]
143    #[cfg(kvm)]
144    KVMError(#[from] kvm_ioctls::Error),
145
146    /// An attempt to get a lock from a Mutex failed.
147    #[error("Unable to lock resource")]
148    LockAttemptFailed(String),
149
150    /// Memory Access Violation at the given address. The access type and memory region flags are provided.
151    #[error("Memory Access Violation at address {0:#x} of type {1}, but memory is marked as {2}")]
152    MemoryAccessViolation(u64, MemoryRegionFlags, MemoryRegionFlags),
153
154    /// Memory Allocation Failed.
155    #[error("Memory Allocation Failed with OS Error {0:?}.")]
156    MemoryAllocationFailed(Option<i32>),
157
158    /// Memory Protection Failed
159    #[error("Memory Protection Failed with OS Error {0:?}.")]
160    MemoryProtectionFailed(Option<i32>),
161
162    /// The memory request exceeds the maximum size allowed
163    #[error("Memory requested {0} exceeds maximum size allowed {1}")]
164    MemoryRequestTooBig(usize, usize),
165
166    /// Metric Not Found.
167    #[error("Metric Not Found {0:?}.")]
168    MetricNotFound(&'static str),
169
170    /// mmap Failed.
171    #[error("mmap failed with os error {0:?}")]
172    MmapFailed(Option<i32>),
173
174    /// mprotect Failed.
175    #[error("mprotect failed with os error {0:?}")]
176    MprotectFailed(Option<i32>),
177
178    /// mshv Error Occurred
179    #[error("mshv Error {0:?}")]
180    #[cfg(mshv)]
181    MSHVError(#[from] mshv_ioctls::MshvError),
182
183    /// No Hypervisor was found for Sandbox.
184    #[error("No Hypervisor was found for Sandbox")]
185    NoHypervisorFound(),
186
187    /// Restore_state called with no valid snapshot
188    #[error("Restore_state called with no valid snapshot")]
189    NoMemorySnapshot,
190
191    /// Failed to get value from parameter value
192    #[error("Failed To Convert Parameter Value {0:?} to {1:?}")]
193    ParameterValueConversionFailure(ParameterValue, &'static str),
194
195    /// a failure occurred processing a PE file
196    #[error("Failure processing PE File {0:?}")]
197    PEFileProcessingFailure(#[from] goblin::error::Error),
198
199    /// Raw pointer is less than base address
200    #[error("Raw pointer ({0:?}) was less than the base address ({1})")]
201    RawPointerLessThanBaseAddress(RawPtr, u64),
202
203    /// RefCell borrow failed
204    #[error("RefCell borrow failed")]
205    RefCellBorrowFailed(#[from] BorrowError),
206
207    /// RefCell mut borrow failed
208    #[error("RefCell mut borrow failed")]
209    RefCellMutBorrowFailed(#[from] BorrowMutError),
210
211    /// Failed to get value from return value
212    #[error("Failed To Convert Return Value {0:?} to {1:?}")]
213    ReturnValueConversionFailure(ReturnValue, &'static str),
214
215    /// Stack overflow detected in guest
216    #[error("Stack overflow detected")]
217    StackOverflow(),
218
219    /// a backend error occurred with seccomp filters
220    #[error("Backend Error with Seccomp Filter {0:?}")]
221    #[cfg(all(feature = "seccomp", target_os = "linux"))]
222    SeccompFilterBackendError(#[from] seccompiler::BackendError),
223
224    /// an error occurred with seccomp filters
225    #[error("Error with Seccomp Filter {0:?}")]
226    #[cfg(all(feature = "seccomp", target_os = "linux"))]
227    SeccompFilterError(#[from] seccompiler::Error),
228
229    /// Tried to restore snapshot to a sandbox that is not the same as the one the snapshot was taken from
230    #[error("Snapshot was taken from a different sandbox")]
231    SnapshotSandboxMismatch,
232
233    /// SystemTimeError
234    #[error("SystemTimeError {0:?}")]
235    SystemTimeError(#[from] SystemTimeError),
236
237    /// Error occurred when translating guest address
238    #[error("An error occurred when translating guest address: {0:?}")]
239    #[cfg(gdb)]
240    TranslateGuestAddress(u64),
241
242    /// Error occurred converting a slice to an array
243    #[error("TryFromSliceError {0:?}")]
244    TryFromSliceError(#[from] TryFromSliceError),
245
246    /// A function was called with an incorrect number of arguments
247    #[error("The number of arguments to the function is wrong: got {0:?} expected {1:?}")]
248    UnexpectedNoOfArguments(usize, usize),
249
250    /// The parameter value type is unexpected
251    #[error("The parameter value type is unexpected got {0:?} expected {1:?}")]
252    UnexpectedParameterValueType(ParameterValue, String),
253
254    /// The return value type is unexpected
255    #[error("The return value type is unexpected got {0:?} expected {1:?}")]
256    UnexpectedReturnValueType(ReturnValue, String),
257
258    /// Slice conversion to UTF8 failed
259    #[error("String Conversion of UTF8 data to str failed")]
260    UTF8StringConversionFailure(#[from] FromUtf8Error),
261
262    /// The capacity of the vector is incorrect
263    #[error(
264        "The capacity of the vector is incorrect. Capacity: {0}, Length: {1}, FlatBuffer Size: {2}"
265    )]
266    VectorCapacityIncorrect(usize, usize, i32),
267
268    /// vmm sys Error Occurred
269    #[error("vmm sys Error {0:?}")]
270    #[cfg(target_os = "linux")]
271    VmmSysError(vmm_sys_util::errno::Error),
272
273    /// Windows Error
274    #[cfg(target_os = "windows")]
275    #[error("Windows API Error Result {0:?}")]
276    WindowsAPIError(#[from] windows_result::Error),
277}
278
279impl From<Infallible> for HyperlightError {
280    fn from(_: Infallible) -> Self {
281        "Impossible as this is an infallible error".into()
282    }
283}
284
285impl From<&str> for HyperlightError {
286    fn from(s: &str) -> Self {
287        HyperlightError::Error(s.to_string())
288    }
289}
290
291impl<T> From<PoisonError<MutexGuard<'_, T>>> for HyperlightError {
292    // Implemented this way rather than passing the error as a source to LockAttemptFailed as that would require
293    // Box<dyn Error + Send + Sync> which is not easy to implement for PoisonError<MutexGuard<'_, T>>
294    // This is a good enough solution and allows use to use the ? operator on lock() calls
295    fn from(e: PoisonError<MutexGuard<'_, T>>) -> Self {
296        let source = match e.source() {
297            Some(s) => s.to_string(),
298            None => String::from(""),
299        };
300        HyperlightError::LockAttemptFailed(source)
301    }
302}
303
304/// Creates a `HyperlightError::Error` from a string literal or format string
305#[macro_export]
306macro_rules! new_error {
307    ($msg:literal $(,)?) => {{
308        let __args = std::format_args!($msg);
309        let __err_msg = match __args.as_str() {
310            Some(msg) => String::from(msg),
311            None => std::format!($msg),
312        };
313        $crate::HyperlightError::Error(__err_msg)
314    }};
315    ($fmtstr:expr, $($arg:tt)*) => {{
316           let __err_msg = std::format!($fmtstr, $($arg)*);
317           $crate::error::HyperlightError::Error(__err_msg)
318    }};
319}