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