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