use core::time::Duration;
use std::sync::{Arc, Mutex};
use rand::Rng;
use tracing::{instrument, Span};
use crate::hypervisor::hypervisor_handler::{
HvHandlerConfig, HypervisorHandler, HypervisorHandlerAction,
};
use crate::mem::mgr::SandboxMemoryManager;
use crate::mem::ptr::RawPtr;
use crate::mem::shared_mem::GuestSharedMemory;
use crate::sandbox::host_funcs::HostFuncsWrapper;
use crate::sandbox::mem_access::mem_access_handler_wrapper;
use crate::sandbox::outb::outb_handler_wrapper;
use crate::sandbox::{HostSharedMemory, MemMgrWrapper};
use crate::sandbox_state::sandbox::Sandbox;
use crate::{new_error, MultiUseSandbox, Result, SingleUseSandbox, UninitializedSandbox};
#[instrument(err(Debug), skip_all, , parent = Span::current(), level = "Trace")]
fn evolve_impl<TransformFunc, ResSandbox: Sandbox>(
u_sbox: UninitializedSandbox,
transform: TransformFunc,
) -> Result<ResSandbox>
where
TransformFunc: Fn(
Arc<Mutex<HostFuncsWrapper>>,
MemMgrWrapper<HostSharedMemory>,
HypervisorHandler,
) -> Result<ResSandbox>,
{
let (hshm, gshm) = u_sbox.mgr.build();
let hv_handler = {
let mut hv_handler = hv_init(
&hshm,
gshm,
u_sbox.host_funcs.clone(),
u_sbox.max_initialization_time,
u_sbox.max_execution_time,
u_sbox.max_wait_for_cancellation,
)?;
{
let dispatch_function_addr = hshm.as_ref().get_pointer_to_dispatch_function()?;
assert_ne!(dispatch_function_addr, 0);
hv_handler.set_dispatch_function_addr(RawPtr::from(dispatch_function_addr))?;
}
hv_handler
};
transform(u_sbox.host_funcs, hshm, hv_handler)
}
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
pub(super) fn evolve_impl_multi_use(u_sbox: UninitializedSandbox) -> Result<MultiUseSandbox> {
evolve_impl(u_sbox, |hf, mut hshm, hv_handler| {
{
hshm.as_mut().push_state()?;
}
Ok(MultiUseSandbox::from_uninit(hf, hshm, hv_handler))
})
}
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
pub(super) fn evolve_impl_single_use(u_sbox: UninitializedSandbox) -> Result<SingleUseSandbox> {
evolve_impl(u_sbox, |_hf, hshm, hv_handler| {
Ok(SingleUseSandbox::from_uninit(hshm, hv_handler))
})
}
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
fn hv_init(
hshm: &MemMgrWrapper<HostSharedMemory>,
gshm: SandboxMemoryManager<GuestSharedMemory>,
host_funcs: Arc<Mutex<HostFuncsWrapper>>,
max_init_time: Duration,
max_exec_time: Duration,
max_wait_for_cancellation: Duration,
) -> Result<HypervisorHandler> {
let outb_hdl = outb_handler_wrapper(hshm.clone(), host_funcs);
let mem_access_hdl = mem_access_handler_wrapper(hshm.clone());
let seed = {
let mut rng = rand::thread_rng();
rng.gen::<u64>()
};
let peb_addr = {
let peb_u64 = u64::try_from(gshm.layout.peb_address)?;
RawPtr::from(peb_u64)
};
let page_size = u32::try_from(page_size::get())?;
let hv_handler_config = HvHandlerConfig {
outb_handler: outb_hdl,
mem_access_handler: mem_access_hdl,
seed,
page_size,
peb_addr,
dispatch_function_addr: Arc::new(Mutex::new(None)),
max_init_time,
max_exec_time,
max_wait_for_cancellation,
};
let mut hv_handler = HypervisorHandler::new(hv_handler_config);
hv_handler.start_hypervisor_handler(gshm)?;
hv_handler
.execute_hypervisor_handler_action(HypervisorHandlerAction::Initialise)
.map_err(|exec_e| match hv_handler.kill_hypervisor_handler_thread() {
Ok(_) => exec_e,
Err(kill_e) => new_error!("{}", format!("{}, {}", exec_e, kill_e)),
})?;
Ok(hv_handler)
}
#[cfg(test)]
mod tests {
use hyperlight_testing::{callback_guest_as_string, simple_guest_as_string};
use super::evolve_impl_multi_use;
use crate::sandbox::uninitialized::GuestBinary;
use crate::UninitializedSandbox;
#[test]
fn test_evolve() {
let guest_bin_paths = vec![
simple_guest_as_string().unwrap(),
callback_guest_as_string().unwrap(),
];
for guest_bin_path in guest_bin_paths {
let u_sbox = UninitializedSandbox::new(
GuestBinary::FilePath(guest_bin_path.clone()),
None,
None,
None,
)
.unwrap();
evolve_impl_multi_use(u_sbox).unwrap();
}
}
#[test]
#[cfg(target_os = "windows")]
fn test_evolve_in_proc() {
use crate::SandboxRunOptions;
let guest_bin_paths = vec![
simple_guest_as_string().unwrap(),
callback_guest_as_string().unwrap(),
];
for guest_bin_path in guest_bin_paths {
let u_sbox: UninitializedSandbox = UninitializedSandbox::new(
GuestBinary::FilePath(guest_bin_path.clone()),
None,
Some(SandboxRunOptions::RunInHypervisor),
None,
)
.unwrap();
let err = format!("error evolving sandbox with guest binary {guest_bin_path}");
let err_str = err.as_str();
evolve_impl_multi_use(u_sbox).expect(err_str);
}
}
}