pub mod config;
mod host_funcs;
pub(crate) mod hypervisor;
pub mod initialized_multi_use;
pub mod initialized_single_use;
#[cfg(inprocess)]
pub(crate) mod leaked_outb;
pub(crate) mod mem_access;
pub(crate) mod mem_mgr;
pub(crate) mod outb;
mod run_options;
pub mod uninitialized;
pub(crate) mod uninitialized_evolve;
pub(crate) mod metrics;
use std::collections::HashMap;
pub use config::SandboxConfiguration;
pub use initialized_multi_use::MultiUseSandbox;
pub use initialized_single_use::SingleUseSandbox;
pub use run_options::SandboxRunOptions;
use tracing::{instrument, Span};
pub use uninitialized::GuestBinary;
pub use uninitialized::UninitializedSandbox;
use self::mem_mgr::MemMgrWrapper;
use crate::func::HyperlightFunction;
use crate::hypervisor::hypervisor_handler::HypervisorHandler;
#[cfg(target_os = "windows")]
use crate::hypervisor::windows_hypervisor_platform;
use crate::mem::shared_mem::HostSharedMemory;
#[instrument(skip_all, parent = Span::current())]
pub fn is_supported_platform() -> bool {
#[cfg(not(target_os = "linux"))]
#[cfg(not(target_os = "windows"))]
return false;
true
}
pub type ExtraAllowedSyscall = i64;
#[derive(Clone, Default)]
pub(super) struct FunctionsMap(
HashMap<String, (HyperlightFunction, Option<Vec<ExtraAllowedSyscall>>)>,
);
impl FunctionsMap {
pub(super) fn insert(
&mut self,
key: String,
value: HyperlightFunction,
extra_syscalls: Option<Vec<ExtraAllowedSyscall>>,
) {
self.0.insert(key, (value, extra_syscalls));
}
pub(super) fn get(
&self,
key: &str,
) -> Option<&(HyperlightFunction, Option<Vec<ExtraAllowedSyscall>>)> {
self.0.get(key)
}
fn len(&self) -> usize {
self.0.len()
}
}
impl PartialEq for FunctionsMap {
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.0.keys().all(|k| other.0.contains_key(k))
}
}
impl Eq for FunctionsMap {}
#[instrument(skip_all, parent = Span::current())]
pub fn is_hypervisor_present() -> bool {
hypervisor::get_available_hypervisor().is_some()
}
pub(crate) trait WrapperGetter {
#[allow(dead_code)]
fn get_mgr_wrapper(&self) -> &MemMgrWrapper<HostSharedMemory>;
fn get_mgr_wrapper_mut(&mut self) -> &mut MemMgrWrapper<HostSharedMemory>;
fn get_hv_handler(&self) -> &HypervisorHandler;
#[allow(dead_code)]
fn get_hv_handler_mut(&mut self) -> &mut HypervisorHandler;
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use std::thread;
use crossbeam_queue::ArrayQueue;
use hyperlight_testing::simple_guest_as_string;
#[cfg(target_os = "linux")]
use super::is_hypervisor_present;
#[cfg(mshv)]
use crate::hypervisor::hyperv_linux::test_cfg::TEST_CONFIG as HYPERV_TEST_CONFIG;
#[cfg(kvm)]
use crate::hypervisor::kvm::test_cfg::TEST_CONFIG as KVM_TEST_CONFIG;
use crate::sandbox::uninitialized::GuestBinary;
use crate::sandbox_state::sandbox::EvolvableSandbox;
use crate::sandbox_state::transition::Noop;
use crate::{new_error, MultiUseSandbox, UninitializedSandbox};
#[test]
#[cfg(target_os = "linux")]
fn test_is_hypervisor_present() {
cfg_if::cfg_if! {
if #[cfg(all(kvm, mshv))] {
if KVM_TEST_CONFIG.kvm_should_be_present || HYPERV_TEST_CONFIG.hyperv_should_be_present {
assert!(is_hypervisor_present());
} else {
assert!(!is_hypervisor_present());
}
} else if #[cfg(kvm)] {
if KVM_TEST_CONFIG.kvm_should_be_present {
assert!(is_hypervisor_present());
} else {
assert!(!is_hypervisor_present());
}
} else if #[cfg(mshv)] {
if HYPERV_TEST_CONFIG.hyperv_should_be_present {
assert!(is_hypervisor_present());
} else {
assert!(!is_hypervisor_present());
}
} else {
assert!(!is_hypervisor_present());
}
}
}
#[test]
fn check_create_and_use_sandbox_on_different_threads() {
let unintializedsandbox_queue = Arc::new(ArrayQueue::<UninitializedSandbox>::new(10));
let sandbox_queue = Arc::new(ArrayQueue::<MultiUseSandbox>::new(10));
for i in 0..10 {
let simple_guest_path = simple_guest_as_string().expect("Guest Binary Missing");
let unintializedsandbox = UninitializedSandbox::new(
GuestBinary::FilePath(simple_guest_path),
None,
None,
None,
)
.unwrap_or_else(|_| panic!("Failed to create UninitializedSandbox {}", i));
unintializedsandbox_queue
.push(unintializedsandbox)
.unwrap_or_else(|_| panic!("Failed to push UninitializedSandbox {}", i));
}
let thread_handles = (0..10)
.map(|i| {
let uq = unintializedsandbox_queue.clone();
let sq = sandbox_queue.clone();
thread::spawn(move || {
let uninitialized_sandbox = uq.pop().unwrap_or_else(|| {
panic!("Failed to pop UninitializedSandbox thread {}", i)
});
let host_funcs = uninitialized_sandbox
.host_funcs
.try_lock()
.map_err(|_| new_error!("Error locking"));
assert!(host_funcs.is_ok());
host_funcs
.unwrap()
.host_print(format!(
"Printing from UninitializedSandbox on Thread {}\n",
i
))
.unwrap();
let sandbox = uninitialized_sandbox
.evolve(Noop::default())
.unwrap_or_else(|_| {
panic!("Failed to initialize UninitializedSandbox thread {}", i)
});
sq.push(sandbox).unwrap_or_else(|_| {
panic!("Failed to push UninitializedSandbox thread {}", i)
})
})
})
.collect::<Vec<_>>();
for handle in thread_handles {
handle.join().unwrap();
}
let thread_handles = (0..10)
.map(|i| {
let sq = sandbox_queue.clone();
thread::spawn(move || {
let sandbox = sq
.pop()
.unwrap_or_else(|| panic!("Failed to pop Sandbox thread {}", i));
let host_funcs = sandbox
._host_funcs
.try_lock()
.map_err(|_| new_error!("Error locking"));
assert!(host_funcs.is_ok());
host_funcs
.unwrap()
.host_print(format!("Print from Sandbox on Thread {}\n", i))
.unwrap();
})
})
.collect::<Vec<_>>();
for handle in thread_handles {
handle.join().unwrap();
}
}
}