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::str::Utf8Error;
29use std::string::FromUtf8Error;
30use std::sync::{MutexGuard, PoisonError};
31use std::time::SystemTimeError;
32
33#[cfg(target_os = "windows")]
34use crossbeam_channel::{RecvError, SendError};
35use flatbuffers::InvalidFlatbuffer;
36use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnValue};
37use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
38use serde::{Deserialize, Serialize};
39use serde_yaml;
40use thiserror::Error;
41
42#[cfg(target_os = "windows")]
43use crate::hypervisor::wrappers::HandleWrapper;
44use crate::mem::memory_region::MemoryRegionFlags;
45use crate::mem::ptr::RawPtr;
46
47#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
48pub(crate) struct HyperlightHostError {
49    pub(crate) message: String,
50    pub(crate) source: String,
51}
52
53/// The error type for Hyperlight operations
54#[derive(Error, Debug)]
55pub enum HyperlightError {
56    /// Anyhow error
57    #[error("Anyhow Error was returned: {0}")]
58    AnyhowError(#[from] anyhow::Error),
59    /// Memory access out of bounds
60    #[error("Offset: {0} out of bounds, Max is: {1}")]
61    BoundsCheckFailed(u64, usize),
62
63    /// Checked Add Overflow
64    #[error("Couldn't add offset to base address. Offset: {0}, Base Address: {1}")]
65    CheckedAddOverflow(u64, u64),
66
67    /// Cross beam channel receive error
68    #[error("{0:?}")]
69    #[cfg(target_os = "windows")]
70    CrossBeamReceiveError(#[from] RecvError),
71
72    /// Cross beam channel send error
73    #[error("{0:?}")]
74    #[cfg(target_os = "windows")]
75    CrossBeamSendError(#[from] SendError<HandleWrapper>),
76
77    /// CString conversion error
78    #[error("Error converting CString {0:?}")]
79    CStringConversionError(#[from] std::ffi::NulError),
80
81    /// A disallowed syscall was caught
82    #[error("Seccomp filter trapped on disallowed syscall (check STDERR for offending syscall)")]
83    #[cfg(all(feature = "seccomp", target_os = "linux"))]
84    DisallowedSyscall,
85
86    /// A generic error with a message
87    #[error("{0}")]
88    Error(String),
89
90    /// Exception Data Length is incorrect
91    #[error("Exception Data Length is incorrect. Expected: {0}, Actual: {1}")]
92    ExceptionDataLengthIncorrect(i32, usize),
93
94    /// Exception Message is too big
95    #[error("Exception Message is too big. Max Size: {0}, Actual: {1}")]
96    ExceptionMessageTooBig(usize, usize),
97
98    /// Execution violation
99    #[error("Non-executable address {0:#x} tried to be executed")]
100    ExecutionAccessViolation(u64),
101
102    /// Guest execution was cancelled by the host
103    #[error("Execution was cancelled by the host.")]
104    ExecutionCanceledByHost(),
105
106    /// Accessing the value of a flatbuffer parameter failed
107    #[error("Failed to get a value from flat buffer parameter")]
108    FailedToGetValueFromParameter(),
109
110    ///Field Name not found in decoded GuestLogData
111    #[error("Field Name {0} not found in decoded GuestLogData")]
112    FieldIsMissingInGuestLogData(String),
113
114    /// Guest aborted during outb
115    #[error("Guest aborted: {0} {1}")]
116    GuestAborted(u8, String),
117
118    ///Cannot run from guest binary unless the binary is a file
119    #[error("Cannot run from guest binary when guest binary is a buffer")]
120    GuestBinaryShouldBeAFile(),
121
122    /// Guest call resulted in error in guest
123    #[error("Guest error occurred {0:?}: {1}")]
124    GuestError(ErrorCode, String),
125
126    /// An attempt to cancel guest execution failed because it is hanging on a host function call
127    #[error("Guest execution hung on the execution of a host function call")]
128    GuestExecutionHungOnHostFunctionCall(),
129
130    /// Guest call already in progress
131    #[error("Guest call is already in progress")]
132    GuestFunctionCallAlreadyInProgress(),
133
134    /// The given type is not supported by the guest interface.
135    #[error("Unsupported type: {0}")]
136    GuestInterfaceUnsupportedType(String),
137
138    /// The guest offset is invalid.
139    #[error("The guest offset {0} is invalid.")]
140    GuestOffsetIsInvalid(usize),
141
142    /// A Host function was called by the guest but it was not registered.
143    #[error("HostFunction {0} was not found")]
144    HostFunctionNotFound(String),
145
146    /// An attempt to communicate with or from the Hypervisor Handler thread failed
147    /// (i.e., usually a failure call to `.send()` or `.recv()` on a message passing
148    /// channel)
149    #[error("Communication failure with the Hypervisor Handler thread")]
150    HypervisorHandlerCommunicationFailure(),
151
152    /// An attempt to cancel a Hypervisor Handler execution failed.
153    /// See `terminate_hypervisor_handler_execution_and_reinitialise`
154    /// for more details.
155    #[error("Hypervisor Handler execution cancel attempt on a finished execution")]
156    HypervisorHandlerExecutionCancelAttemptOnFinishedExecution(),
157
158    /// A Receive for a Hypervisor Handler Message Timedout
159    #[error("Hypervisor Handler Message Receive Timedout")]
160    HypervisorHandlerMessageReceiveTimedout(),
161
162    /// Reading Writing or Seeking data failed.
163    #[error("Reading Writing or Seeking data failed {0:?}")]
164    IOError(#[from] std::io::Error),
165
166    /// Failed to convert to Integer
167    #[error("Failed To Convert Size to usize")]
168    IntConversionFailure(#[from] TryFromIntError),
169
170    /// The flatbuffer is invalid
171    #[error("The flatbuffer is invalid")]
172    InvalidFlatBuffer(#[from] InvalidFlatbuffer),
173
174    /// Conversion of str to Json failed
175    #[error("Conversion of str data to json failed")]
176    JsonConversionFailure(#[from] serde_json::Error),
177
178    /// Error occurred in KVM Operation
179    #[error("KVM Error {0:?}")]
180    #[cfg(kvm)]
181    KVMError(#[source] kvm_ioctls::Error),
182
183    /// An attempt to get a lock from a Mutex failed.
184    #[error("Unable to lock resource")]
185    LockAttemptFailed(String),
186
187    /// Memory Access Violation at the given address. The access type and memory region flags are provided.
188    #[error("Memory Access Violation at address {0:#x} of type {1}, but memory is marked as {2}")]
189    MemoryAccessViolation(u64, MemoryRegionFlags, MemoryRegionFlags),
190
191    /// Memory Allocation Failed.
192    #[error("Memory Allocation Failed with OS Error {0:?}.")]
193    MemoryAllocationFailed(Option<i32>),
194
195    /// Memory Protection Failed
196    #[error("Memory Protection Failed with OS Error {0:?}.")]
197    MemoryProtectionFailed(Option<i32>),
198
199    /// The memory request exceeds the maximum size allowed
200    #[error("Memory requested {0} exceeds maximum size allowed {1}")]
201    MemoryRequestTooBig(usize, usize),
202
203    /// Metric Not Found.
204    #[error("Metric Not Found {0:?}.")]
205    MetricNotFound(&'static str),
206
207    /// mmap Failed.
208    #[error("mmap failed with os error {0:?}")]
209    MmapFailed(Option<i32>),
210
211    /// mprotect Failed.
212    #[error("mprotect failed with os error {0:?}")]
213    MprotectFailed(Option<i32>),
214
215    /// mshv Error Occurred
216    #[error("mshv Error {0:?}")]
217    #[cfg(mshv)]
218    MSHVError(#[from] mshv_ioctls::MshvError),
219
220    /// No Hypervisor was found for Sandbox.
221    #[error("No Hypervisor was found for Sandbox")]
222    NoHypervisorFound(),
223
224    /// Restore_state called with no valid snapshot
225    #[error("Restore_state called with no valid snapshot")]
226    NoMemorySnapshot,
227
228    /// An error occurred handling an outb message
229    #[error("An error occurred handling an outb message {0:?}: {1}")]
230    OutBHandlingError(String, String),
231
232    /// Failed to get value from parameter value
233    #[error("Failed To Convert Parameter Value {0:?} to {1:?}")]
234    ParameterValueConversionFailure(ParameterValue, &'static str),
235
236    /// a failure occurred processing a PE file
237    #[error("Failure processing PE File {0:?}")]
238    PEFileProcessingFailure(#[from] goblin::error::Error),
239
240    /// a Prometheus error occurred
241    #[error("Prometheus Error {0:?}")]
242    Prometheus(#[from] prometheus::Error),
243
244    /// Raw pointer is less than base address
245    #[error("Raw pointer ({0:?}) was less than the base address ({1})")]
246    RawPointerLessThanBaseAddress(RawPtr, u64),
247
248    /// RefCell borrow failed
249    #[error("RefCell borrow failed")]
250    RefCellBorrowFailed(#[from] BorrowError),
251
252    /// RefCell mut borrow failed
253    #[error("RefCell mut borrow failed")]
254    RefCellMutBorrowFailed(#[from] BorrowMutError),
255
256    /// Failed to get value from return value
257    #[error("Failed To Convert Return Value {0:?} to {1:?}")]
258    ReturnValueConversionFailure(ReturnValue, &'static str),
259
260    /// Stack overflow detected in guest
261    #[error("Stack overflow detected")]
262    StackOverflow(),
263
264    /// a backend error occurred with seccomp filters
265    #[error("Backend Error with Seccomp Filter {0:?}")]
266    #[cfg(all(feature = "seccomp", target_os = "linux"))]
267    SeccompFilterBackendError(#[from] seccompiler::BackendError),
268
269    /// an error occurred with seccomp filters
270    #[error("Error with Seccomp Filter {0:?}")]
271    #[cfg(all(feature = "seccomp", target_os = "linux"))]
272    SeccompFilterError(#[from] seccompiler::Error),
273
274    /// SystemTimeError
275    #[error("SystemTimeError {0:?}")]
276    SystemTimeError(#[from] SystemTimeError),
277
278    /// Error occurred when translating guest address
279    #[error("An error occurred when translating guest address: {0:?}")]
280    #[cfg(gdb)]
281    TranslateGuestAddress(u64),
282
283    /// Error occurred converting a slice to an array
284    #[error("TryFromSliceError {0:?}")]
285    TryFromSliceError(#[from] TryFromSliceError),
286
287    /// A function was called with an incorrect number of arguments
288    #[error("The number of arguments to the function is wrong: got {0:?} expected {1:?}")]
289    UnexpectedNoOfArguments(usize, usize),
290
291    /// The parameter value type is unexpected
292    #[error("The parameter value type is unexpected got {0:?} expected {1:?}")]
293    UnexpectedParameterValueType(ParameterValue, String),
294
295    /// The return value type is unexpected
296    #[error("The return value type is unexpected got {0:?} expected {1:?}")]
297    UnexpectedReturnValueType(ReturnValue, String),
298
299    /// Slice conversion to UTF8 failed
300    #[error("Slice Conversion of UTF8 data to str failed")]
301    UTF8SliceConversionFailure(#[from] Utf8Error),
302
303    /// Slice conversion to UTF8 failed
304    #[error("String Conversion of UTF8 data to str failed")]
305    UTF8StringConversionFailure(#[from] FromUtf8Error),
306
307    /// The capacity of the vector is incorrect
308    #[error(
309        "The capacity of the vector is incorrect. Capacity: {0}, Length: {1}, FlatBuffer Size: {2}"
310    )]
311    VectorCapacityIncorrect(usize, usize, i32),
312
313    /// vmm sys Error Occurred
314    #[error("vmm sys Error {0:?}")]
315    #[cfg(target_os = "linux")]
316    VmmSysError(#[from] vmm_sys_util::errno::Error),
317
318    /// Windows Error
319    #[cfg(target_os = "windows")]
320    #[error("Windows API Error Result {0:?}")]
321    WindowsAPIError(#[from] windows_result::Error),
322
323    /// Conversion of str to YAML failed
324    #[error("Conversion of str data to yaml failed")]
325    YamlConversionFailure(#[from] serde_yaml::Error),
326}
327
328impl From<Infallible> for HyperlightError {
329    fn from(_: Infallible) -> Self {
330        "Impossible as this is an infallible error".into()
331    }
332}
333
334impl From<&str> for HyperlightError {
335    fn from(s: &str) -> Self {
336        HyperlightError::Error(s.to_string())
337    }
338}
339
340impl<T> From<PoisonError<MutexGuard<'_, T>>> for HyperlightError {
341    // Implemented this way rather than passing the error as a source to LockAttemptFailed as that would require
342    // Box<dyn Error + Send + Sync> which is not easy to implement for PoisonError<MutexGuard<'_, T>>
343    // This is a good enough solution and allows use to use the ? operator on lock() calls
344    fn from(e: PoisonError<MutexGuard<'_, T>>) -> Self {
345        let source = match e.source() {
346            Some(s) => s.to_string(),
347            None => String::from(""),
348        };
349        HyperlightError::LockAttemptFailed(source)
350    }
351}
352
353/// Creates a `HyperlightError::Error` from a string literal or format string
354#[macro_export]
355macro_rules! new_error {
356    ($msg:literal $(,)?) => {{
357        let __args = std::format_args!($msg);
358        let __err_msg = match __args.as_str() {
359            Some(msg) => String::from(msg),
360            None => std::format!($msg),
361        };
362        $crate::HyperlightError::Error(__err_msg)
363    }};
364    ($fmtstr:expr, $($arg:tt)*) => {{
365           let __err_msg = std::format!($fmtstr, $($arg)*);
366           $crate::error::HyperlightError::Error(__err_msg)
367    }};
368}