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