hyperlight_host/
error.rs

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