hyperlight_host/
lib.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#![deny(dead_code, missing_docs, unused_mut)]
17//! This crate contains an SDK that is used to execute specially-
18// compiled binaries within a very lightweight hypervisor environment.
19
20#![cfg_attr(not(any(test, debug_assertions)), warn(clippy::panic))]
21#![cfg_attr(not(any(test, debug_assertions)), warn(clippy::expect_used))]
22#![cfg_attr(not(any(test, debug_assertions)), warn(clippy::unwrap_used))]
23#![cfg_attr(any(test, debug_assertions), allow(clippy::disallowed_macros))]
24
25use std::sync::Once;
26
27use log::info;
28/// The `built` crate is used to generate a `built.rs` file that contains
29/// information about the build environment. This information is used to
30/// populate the `built_info` module, which is re-exported here.
31pub(crate) mod built_info {
32    include!(concat!(env!("OUT_DIR"), "/built.rs"));
33}
34/// Dealing with errors, including errors across VM boundaries
35pub mod error;
36/// Wrappers for host and guest functions.
37pub mod func;
38/// Wrappers for hypervisor implementations
39pub mod hypervisor;
40/// Functionality to establish and manage an individual sandbox's
41/// memory.
42///
43/// The following structs are not used other than to calculate the size of the memory needed
44/// and also to illustrate the layout of the memory:
45///
46/// - `HostFunctionDefinitions`
47/// - `HostExceptionData`
48/// - `GuestError`
49/// - `CodeAndOutBPointers`
50/// - `InputData`
51/// - `OutputData`
52/// - `GuestHeap`
53/// - `GuestStack`
54///
55/// the start of the guest  memory contains the page tables and is always located at the Virtual Address 0x00200000 when
56/// running in a Hypervisor:
57///
58/// Virtual Address
59///
60/// 0x200000    PML4
61/// 0x201000    PDPT
62/// 0x202000    PD
63/// 0x203000    The guest PE code (When the code has been loaded using LoadLibrary to debug the guest this will not be
64/// present and code length will be zero;
65///
66/// The pointer passed to the Entrypoint in the Guest application is the 0x200000 + size of page table + size of code,
67/// at this address structs below are laid out in this order
68pub mod mem;
69/// Metric definitions and helpers
70pub mod metrics;
71/// The main sandbox implementations. Do not use this module directly in code
72/// outside this file. Types from this module needed for public consumption are
73/// re-exported below.
74pub mod sandbox;
75/// `trait`s and other functionality for dealing with defining sandbox
76/// states and moving between them
77pub mod sandbox_state;
78#[cfg(all(feature = "seccomp", target_os = "linux"))]
79pub(crate) mod seccomp;
80/// Signal handling for Linux
81#[cfg(target_os = "linux")]
82pub(crate) mod signal_handlers;
83/// Utilities for testing including interacting with `simpleguest.exe`
84/// and `callbackguest.exe`, our two most basic guest binaries for testing
85#[cfg(test)]
86pub(crate) mod testing;
87
88/// The re-export for the `HyperlightError` type
89pub use error::HyperlightError;
90/// The re-export for the set_registry function
91pub use metrics::set_metrics_registry;
92/// The re-export for the `is_hypervisor_present` type
93pub use sandbox::is_hypervisor_present;
94/// The re-export for the `GuestBinary` type
95pub use sandbox::uninitialized::GuestBinary;
96/// Re-export for `HypervisorWrapper` trait
97/// Re-export for `MemMgrWrapper` type
98/// A sandbox that can call be used to make multiple calls to guest functions,
99/// and otherwise reused multiple times
100pub use sandbox::MultiUseSandbox;
101/// The re-export for the `SandboxRunOptions` type
102pub use sandbox::SandboxRunOptions;
103/// The re-export for the `UninitializedSandbox` type
104pub use sandbox::UninitializedSandbox;
105
106/// The re-export for the `MultiUseGuestCallContext` type`
107pub use crate::func::call_ctx::MultiUseGuestCallContext;
108
109/// The universal `Result` type used throughout the Hyperlight codebase.
110pub type Result<T> = core::result::Result<T, error::HyperlightError>;
111
112/// Logs an error then returns with it, more or less equivalent to the bail! macro in anyhow
113/// but for HyperlightError instead of anyhow::Error
114#[macro_export]
115macro_rules! log_then_return {
116    ($msg:literal $(,)?) => {{
117        let __args = std::format_args!($msg);
118        let __err_msg = match __args.as_str() {
119            Some(msg) => String::from(msg),
120            None => std::format!($msg),
121        };
122        let __err = $crate::HyperlightError::Error(__err_msg);
123        log::error!("{}", __err);
124        return Err(__err);
125    }};
126    ($err:expr $(,)?) => {
127        log::error!("{}", $err);
128        return Err($err);
129    };
130    ($err:stmt $(,)?) => {
131        log::error!("{}", $err);
132        return Err($err);
133    };
134    ($fmtstr:expr, $($arg:tt)*) => {
135           let __err_msg = std::format!($fmtstr, $($arg)*);
136           let __err = $crate::error::HyperlightError::Error(__err_msg);
137           log::error!("{}", __err);
138           return Err(__err);
139    };
140}
141
142/// Same as log::debug!, but will additionally print to stdout if the print_debug feature is enabled
143#[macro_export]
144macro_rules! debug {
145    ($($arg:tt)+) =>
146    {
147        #[cfg(print_debug)]
148        println!($($arg)+);
149        log::debug!($($arg)+);
150    }
151}
152
153// LOG_ONCE is used to log information about the crate version once
154static LOG_ONCE: Once = Once::new();
155
156pub(crate) fn log_build_details() {
157    LOG_ONCE.call_once(|| {
158        info!("Package name: {}", built_info::PKG_NAME);
159        info!("Package version: {}", built_info::PKG_VERSION);
160        info!("Package features: {:?}", built_info::FEATURES);
161        info!("Target triple: {}", built_info::TARGET);
162        info!("Optimization level: {}", built_info::OPT_LEVEL);
163        info!("Profile: {}", built_info::PROFILE);
164        info!("Debug: {}", built_info::DEBUG);
165        info!("Rustc: {}", built_info::RUSTC);
166        info!("Built at: {}", built_info::BUILT_TIME_UTC);
167        match built_info::CI_PLATFORM.unwrap_or("") {
168            "" => info!("Not built on  a CI platform"),
169            other => info!("Built on : {}", other),
170        }
171        match built_info::GIT_COMMIT_HASH.unwrap_or("") {
172            "" => info!("No git commit hash found"),
173            other => info!("Git commit hash: {}", other),
174        }
175
176        let git = match built_info::GIT_HEAD_REF.unwrap_or("") {
177            "" => {
178                info!("No git head ref found");
179                false
180            }
181            other => {
182                info!("Git head ref: {}", other);
183                true
184            }
185        };
186        match built_info::GIT_VERSION.unwrap_or("") {
187            "" => info!("No git version found"),
188            other => info!("Git version: {}", other),
189        }
190        match built_info::GIT_DIRTY.unwrap_or(false) {
191            true => info!("Repo had uncommitted changes"),
192            false => {
193                if git {
194                    info!("Repo had no uncommitted changes")
195                } else {
196                    info!("No git repo found")
197                }
198            }
199        }
200    });
201}