diff --git a/CHANGELOG.md b/CHANGELOG.md index 54bc21eee..1bf45f3ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). assembly and extraction without flattening. ### Changed +* `Sandbox` is the primary initialized sandbox type. `MultiUseSandbox` remains + as a deprecated alias. +* `Sandbox` lives in the private `sandbox::initialized` module and is reached + through `hyperlight_host::Sandbox` or `hyperlight_host::sandbox::Sandbox`. + `sandbox::initialized_multi_use` remains as a deprecated public path. * Support overriding the guest log level when building or restoring initialized snapshots. * `Snapshot::save` now writes the guest memory blob sparsely, skipping all-zero diff --git a/Justfile b/Justfile index 28f22239b..26df27c9b 100644 --- a/Justfile +++ b/Justfile @@ -263,18 +263,18 @@ test-loom: test-isolated target=default-target features="" : {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::uninitialized::tests::test_log_trace --exact --ignored {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::outb::tests::test_log_emit_guest_log --exact --ignored - {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::from_snapshot::max_guest_log_level_is_honored_from_snapshot --exact --ignored - {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::from_snapshot::max_guest_log_level_overrides_initialized_snapshot --exact --ignored - {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::from_snapshot::max_guest_log_level_setter_survives_restore --exact --ignored - {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::from_snapshot::max_guest_log_level_can_be_disabled_and_reenabled --exact --ignored - {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::from_snapshot::max_guest_log_level_can_be_enabled_after_off_init --exact --ignored + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::initialized::tests::from_snapshot::max_guest_log_level_is_honored_from_snapshot --exact --ignored + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::initialized::tests::from_snapshot::max_guest_log_level_overrides_initialized_snapshot --exact --ignored + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::initialized::tests::from_snapshot::max_guest_log_level_setter_survives_restore --exact --ignored + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::initialized::tests::from_snapshot::max_guest_log_level_can_be_disabled_and_reenabled --exact --ignored + {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::initialized::tests::from_snapshot::max_guest_log_level_can_be_enabled_after_off_init --exact --ignored {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --test integration_test -- log_message --exact --ignored @# CPU vendor check, gated to known CI runner hardware {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::snapshot::file::config::tests::cpu_vendor_current_is_recognized --exact --ignored @# Slow host-dependent MSR audit. Run once per x86_64 CI profile. - {{ if features == "" { if hyperlight-target-arch == "x86_64" { cargo-cmd + " test --profile=" + (if target == "debug" { "dev" } else { target }) + " " + target-triple-flag + " -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::msr_tests::test_no_msr_leaks_across_restore_full_window_sweep --exact --ignored --nocapture" } else { "" } } else { "" } }} + {{ if features == "" { if hyperlight-target-arch == "x86_64" { cargo-cmd + " test --profile=" + (if target == "debug" { "dev" } else { target }) + " " + target-triple-flag + " -p hyperlight-host --lib -- sandbox::initialized::tests::msr_tests::test_no_msr_leaks_across_restore_full_window_sweep --exact --ignored --nocapture" } else { "" } } else { "" } }} @# LAPIC-enabled MSHV can expose additional MSRs. Audit it once in debug. - {{ if features == "mshv3,hw-interrupts" { if target == "debug" { if hyperlight-target-arch == "x86_64" { cargo-cmd + " test --no-default-features -F mshv3,hw-interrupts --profile=dev " + target-triple-flag + " -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::msr_tests::test_no_msr_leaks_across_restore_full_window_sweep --exact --ignored --nocapture" } else { "" } } else { "" } } else { "" } }} + {{ if features == "mshv3,hw-interrupts" { if target == "debug" { if hyperlight-target-arch == "x86_64" { cargo-cmd + " test --no-default-features -F mshv3,hw-interrupts --profile=dev " + target-triple-flag + " -p hyperlight-host --lib -- sandbox::initialized::tests::msr_tests::test_no_msr_leaks_across_restore_full_window_sweep --exact --ignored --nocapture" } else { "" } } else { "" } } else { "" } }} @# metrics tests {{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F function_call_metrics," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- metrics::tests::test_metrics_are_emitted --exact @@ -551,11 +551,11 @@ coverage-run hypervisor="kvm": ensure-cargo-llvm-cov # isolated tests (require running separately due to global state) cargo +{{nightly-toolchain}} test -p hyperlight-host --lib -- sandbox::uninitialized::tests::test_log_trace --exact --ignored cargo +{{nightly-toolchain}} test -p hyperlight-host --lib -- sandbox::outb::tests::test_log_emit_guest_log --exact --ignored - cargo +{{nightly-toolchain}} test -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::from_snapshot::max_guest_log_level_is_honored_from_snapshot --exact --ignored - cargo +{{nightly-toolchain}} test -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::from_snapshot::max_guest_log_level_overrides_initialized_snapshot --exact --ignored - cargo +{{nightly-toolchain}} test -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::from_snapshot::max_guest_log_level_setter_survives_restore --exact --ignored - cargo +{{nightly-toolchain}} test -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::from_snapshot::max_guest_log_level_can_be_disabled_and_reenabled --exact --ignored - cargo +{{nightly-toolchain}} test -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::from_snapshot::max_guest_log_level_can_be_enabled_after_off_init --exact --ignored + cargo +{{nightly-toolchain}} test -p hyperlight-host --lib -- sandbox::initialized::tests::from_snapshot::max_guest_log_level_is_honored_from_snapshot --exact --ignored + cargo +{{nightly-toolchain}} test -p hyperlight-host --lib -- sandbox::initialized::tests::from_snapshot::max_guest_log_level_overrides_initialized_snapshot --exact --ignored + cargo +{{nightly-toolchain}} test -p hyperlight-host --lib -- sandbox::initialized::tests::from_snapshot::max_guest_log_level_setter_survives_restore --exact --ignored + cargo +{{nightly-toolchain}} test -p hyperlight-host --lib -- sandbox::initialized::tests::from_snapshot::max_guest_log_level_can_be_disabled_and_reenabled --exact --ignored + cargo +{{nightly-toolchain}} test -p hyperlight-host --lib -- sandbox::initialized::tests::from_snapshot::max_guest_log_level_can_be_enabled_after_off_init --exact --ignored cargo +{{nightly-toolchain}} test -p hyperlight-host --test integration_test -- log_message --exact --ignored cargo +{{nightly-toolchain}} test -p hyperlight-host --no-default-features -F function_call_metrics,{{ if hypervisor == "mshv3" { "mshv3" } else { "kvm" } }} --lib -- metrics::tests::test_metrics_are_emitted --exact diff --git a/docs/cancellation.md b/docs/cancellation.md index 459e3a35d..3dead4037 100644 --- a/docs/cancellation.md +++ b/docs/cancellation.md @@ -19,7 +19,7 @@ The `LinuxInterruptHandle` uses a packed atomic u8 to track execution state: - **tid (AtomicU64)**: Thread ID where the vCPU is running - **dropped (AtomicBool)**: Set when the corresponding VM has been dropped -The packed state enables atomic reads of RUNNING_BIT, CANCEL_BIT and DEBUG_INTERRUPT_BIT simultaneously via `get_running_cancel_debug()`. Within a single `VirtualCPU::run()` call, the CANCEL_BIT remains set across vcpu exits and re-entries (such as when calling host functions), ensuring cancellation persists until the guest call completes. However, `clear_cancel()` resets the CANCEL_BIT at the beginning of each new guest function call (specifically in `MultiUseSandbox::call`, before `VirtualCPU::run()` is called), preventing cancellation requests from affecting subsequent guest function calls. +The packed state enables atomic reads of RUNNING_BIT, CANCEL_BIT and DEBUG_INTERRUPT_BIT simultaneously via `get_running_cancel_debug()`. Within a single `VirtualCPU::run()` call, the CANCEL_BIT remains set across vcpu exits and re-entries (such as when calling host functions), ensuring cancellation persists until the guest call completes. However, `clear_cancel()` resets the CANCEL_BIT at the beginning of each new guest function call (specifically in `Sandbox::call`, before `VirtualCPU::run()` is called), preventing cancellation requests from affecting subsequent guest function calls. ### Signal Mechanism diff --git a/docs/how-to-debug-a-hyperlight-guest.md b/docs/how-to-debug-a-hyperlight-guest.md index 52a1c8ba4..688b08767 100644 --- a/docs/how-to-debug-a-hyperlight-guest.md +++ b/docs/how-to-debug-a-hyperlight-guest.md @@ -229,7 +229,7 @@ To selectively disable this feature for a specific sandbox, call `guest_core_dum ## Creating a dump on demand -You can also create a core dump of the current state of the guest on demand by calling the `generate_crashdump` method on the `InitializedMultiUseSandbox` instance. This can be useful for debugging issues in the guest that do not cause crashes (e.g., a guest function that does not return). +You can also create a core dump of the current state of the guest on demand by calling the `generate_crashdump` method on the `Sandbox` instance. This can be useful for debugging issues in the guest that do not cause crashes (e.g., a guest function that does not return). This is only available when the `crashdump` feature is enabled and then only if the sandbox is also configured to allow core dumps (which is the default behavior). @@ -243,10 +243,10 @@ sudo gdb -p (gdb) info threads # find the thread that is running the guest function you want to debug (gdb) thread -# switch to the frame where you have access to your MultiUseSandbox instance +# switch to the frame where you have access to your Sandbox instance (gdb) backtrace (gdb) frame -# get the pointer to your MultiUseSandbox instance +# get the pointer to your Sandbox instance # Get the sandbox pointer (gdb) print sandbox # Call the crashdump function with the pointer diff --git a/docs/hyperlight-metrics-logs-and-traces.md b/docs/hyperlight-metrics-logs-and-traces.md index 3a18dab7e..02a57d125 100644 --- a/docs/hyperlight-metrics-logs-and-traces.md +++ b/docs/hyperlight-metrics-logs-and-traces.md @@ -146,7 +146,7 @@ This custom subscriber stores the spans and events in a buffer initialized only **NOTE**: The spans/events attributes are truncated to fit in the allocated buffer. The guest log level can be configured when building a sandbox and overridden -for an initialized sandbox with `MultiUseSandbox::log_level`. The override +for an initialized sandbox with `Sandbox::log_level`. The override applies to later guest calls and is reapplied after snapshot restore. When the storage space is filled, the guest triggers a VM Exit that sends the guest pointers to the host. The host can access the guest memory, get the data and parse it to create the `spans` and `events` using the `opentelemetry` crate which allows specifying the starting and ending timestamps diff --git a/docs/msr.md b/docs/msr.md index 3914e0ad6..aa5bf3794 100644 --- a/docs/msr.md +++ b/docs/msr.md @@ -5,7 +5,7 @@ A snapshot represents the state of a VM at a point in time. This includes MSR state that can affect later execution. -After `MultiUseSandbox::restore`, the destination sandbox's MSR state must match +After `Sandbox::restore`, the destination sandbox's MSR state must match the supplied snapshot, regardless of prior execution in the sandbox. ## How snapshot and restore work diff --git a/docs/virtio-host-guest-communication.md b/docs/virtio-host-guest-communication.md index cd03756d5..9734ef41e 100644 --- a/docs/virtio-host-guest-communication.md +++ b/docs/virtio-host-guest-communication.md @@ -327,7 +327,7 @@ memory. Guest producer and pool bookkeeping is normal guest state, while ring and pool bytes live in scratch. Snapshot capture needs a canonical transport state. -`MultiUseSandbox` tracks whether queue traffic occurred after the last +`Sandbox` tracks whether queue traffic occurred after the last canonical boundary. A cached or clean snapshot needs no VM entry. A dirty snapshot uses this flow: diff --git a/fuzz/fuzz_targets/guest_call.rs b/fuzz/fuzz_targets/guest_call.rs index 25e270b89..cf173666c 100644 --- a/fuzz/fuzz_targets/guest_call.rs +++ b/fuzz/fuzz_targets/guest_call.rs @@ -6,19 +6,19 @@ use std::sync::{Mutex, OnceLock}; use hyperlight_host::func::{ParameterValue, ReturnType}; -use hyperlight_host::{MultiUseSandbox, SandboxBuilder}; +use hyperlight_host::{Sandbox, SandboxBuilder}; use hyperlight_testing::simple_guest_for_fuzzing_as_pathbuf; use libfuzzer_sys::fuzz_target; -static SANDBOX: OnceLock> = OnceLock::new(); +static SANDBOX: OnceLock> = OnceLock::new(); // This fuzz target tests all combinations of ReturnType and Parameters for `call_guest_function_by_name`. // For fuzzing efficiency, we create one Sandbox and reuse it for all fuzzing iterations. fuzz_target!( init: { - let mu_sbox = SandboxBuilder::from_file(simple_guest_for_fuzzing_as_pathbuf()) + let sandbox = SandboxBuilder::from_file(simple_guest_for_fuzzing_as_pathbuf()) .build() .unwrap(); - SANDBOX.set(Mutex::new(mu_sbox)).unwrap(); + SANDBOX.set(Mutex::new(sandbox)).unwrap(); }, |data: (ReturnType, Vec)| { diff --git a/fuzz/fuzz_targets/guest_trace.rs b/fuzz/fuzz_targets/guest_trace.rs index a76828fd4..42a101363 100644 --- a/fuzz/fuzz_targets/guest_trace.rs +++ b/fuzz/fuzz_targets/guest_trace.rs @@ -9,12 +9,12 @@ compile_error!("feature `trace` must be enabled to correctly fuzz guest trace fu use std::sync::{Mutex, OnceLock}; use hyperlight_host::func::{ParameterValue, ReturnType, ReturnValue}; -use hyperlight_host::{MultiUseSandbox, SandboxBuilder}; +use hyperlight_host::{Sandbox, SandboxBuilder}; use hyperlight_testing::simple_guest_for_fuzzing_as_pathbuf; use libfuzzer_sys::arbitrary::Arbitrary; use libfuzzer_sys::{Corpus, fuzz_target}; -static SANDBOX: OnceLock> = OnceLock::new(); +static SANDBOX: OnceLock> = OnceLock::new(); #[derive(Debug)] struct FuzzInput { @@ -53,11 +53,11 @@ impl<'a> Arbitrary<'a> for FuzzInput { // Any unexpected errors from the guest should be reported. fuzz_target!( init: { - let mu_sbox = SandboxBuilder::from_file(simple_guest_for_fuzzing_as_pathbuf()) + let sandbox = SandboxBuilder::from_file(simple_guest_for_fuzzing_as_pathbuf()) .build() .unwrap(); - SANDBOX.set(Mutex::new(mu_sbox)).unwrap(); + SANDBOX.set(Mutex::new(sandbox)).unwrap(); }, |data: FuzzInput| -> Corpus { diff --git a/fuzz/fuzz_targets/host_call.rs b/fuzz/fuzz_targets/host_call.rs index c32fb1816..f7aa8d30b 100644 --- a/fuzz/fuzz_targets/host_call.rs +++ b/fuzz/fuzz_targets/host_call.rs @@ -8,11 +8,11 @@ use std::sync::{Mutex, OnceLock}; use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_host::func::{ParameterValue, ReturnType}; use hyperlight_host::sandbox::SandboxConfiguration; -use hyperlight_host::{GuestBinary, HyperlightError, MultiUseSandbox, UninitializedSandbox}; +use hyperlight_host::{GuestBinary, HyperlightError, Sandbox, UninitializedSandbox}; use hyperlight_testing::simple_guest_for_fuzzing_as_pathbuf; use libfuzzer_sys::fuzz_target; -static SANDBOX: OnceLock> = OnceLock::new(); +static SANDBOX: OnceLock> = OnceLock::new(); // This fuzz target tests all combinations of ReturnType and Parameters for `call_guest_function_by_name`. // For fuzzing efficiency, we create one Sandbox and reuse it for all fuzzing iterations. @@ -28,8 +28,8 @@ fuzz_target!( Some(cfg) ) .unwrap(); - let mu_sbox: MultiUseSandbox = u_sbox.evolve().unwrap(); - SANDBOX.set(Mutex::new(mu_sbox)).unwrap(); + let sandbox: Sandbox = u_sbox.evolve().unwrap(); + SANDBOX.set(Mutex::new(sandbox)).unwrap(); }, |data: (String, ReturnType, Vec)| { diff --git a/fuzz/fuzz_targets/host_print.rs b/fuzz/fuzz_targets/host_print.rs index faf389e68..4ecd557f6 100644 --- a/fuzz/fuzz_targets/host_print.rs +++ b/fuzz/fuzz_targets/host_print.rs @@ -2,11 +2,11 @@ use std::sync::{Mutex, OnceLock}; -use hyperlight_host::{MultiUseSandbox, SandboxBuilder}; +use hyperlight_host::{Sandbox, SandboxBuilder}; use hyperlight_testing::simple_guest_for_fuzzing_as_pathbuf; use libfuzzer_sys::{Corpus, fuzz_target}; -static SANDBOX: OnceLock> = OnceLock::new(); +static SANDBOX: OnceLock> = OnceLock::new(); // This fuzz target is used to test the HostPrint host function. We generate // an arbitrary ParameterValue::String, which is passed to the guest, which passes @@ -14,10 +14,10 @@ static SANDBOX: OnceLock> = OnceLock::new(); // For fuzzing efficiency, we create one Sandbox and reuse it for all fuzzing iterations. fuzz_target!( init: { - let mu_sbox = SandboxBuilder::from_file(simple_guest_for_fuzzing_as_pathbuf()) + let sandbox = SandboxBuilder::from_file(simple_guest_for_fuzzing_as_pathbuf()) .build() .unwrap(); - SANDBOX.set(Mutex::new(mu_sbox)).unwrap(); + SANDBOX.set(Mutex::new(sandbox)).unwrap(); }, |data: String| -> Corpus { diff --git a/src/hyperlight_component_util/src/host.rs b/src/hyperlight_component_util/src/host.rs index 10d2c7932..69bd1d13a 100644 --- a/src/hyperlight_component_util/src/host.rs +++ b/src/hyperlight_component_util/src/host.rs @@ -408,7 +408,7 @@ fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Com #(#exports)* } impl #ns::#r#trait<::hyperlight_common::component::Positive> for ::hyperlight_host::sandbox::UninitializedSandbox { - type Exports + ::std::marker::Send> = #wrapper_name; + type Exports + ::std::marker::Send> = #wrapper_name; fn instantiate + ::std::marker::Send + 'static>(mut self, i: I) -> <::hyperlight_common::component::Positive as ::hyperlight_common::component::Positivity>::CallResult> { let rts = register_host_functions(&mut self, i)?; let sb = self.evolve()?; diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index 48aba7a5b..e1aac27ee 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -15,7 +15,7 @@ use hyperlight_common::flatbuffer_wrappers::util::estimate_flatbuffer_capacity; use hyperlight_common::transport::ExternalValues; use hyperlight_common::vmem::PAGE_SIZE; use hyperlight_host::mem::shared_mem::ExclusiveSharedMemory; -use hyperlight_host::sandbox::{MultiUseSandbox, SandboxConfiguration, UninitializedSandbox}; +use hyperlight_host::sandbox::{Sandbox, SandboxConfiguration, UninitializedSandbox}; use hyperlight_host::{GuestBinary, SandboxBuilder}; use hyperlight_testing::sandbox_sizes::{LARGE_HEAP_SIZE, MEDIUM_HEAP_SIZE, SMALL_HEAP_SIZE}; use hyperlight_testing::{c_simple_guest_as_pathbuf, simple_guest_as_pathbuf}; @@ -62,7 +62,7 @@ impl SandboxSize { } } -fn create_multiuse_sandbox_with_size(size: SandboxSize) -> MultiUseSandbox { +fn create_multiuse_sandbox_with_size(size: SandboxSize) -> Sandbox { size.builder().build().unwrap() } @@ -99,7 +99,7 @@ fn sandbox_lifecycle_benchmark(c: &mut Criterion) { ); } - // Isolates the cost of building a MultiUseSandbox from an + // Isolates the cost of building a Sandbox from an // already-resident Snapshot. The Snapshot is loaded outside the // timed region. for size in SandboxSize::all() { @@ -317,7 +317,7 @@ fn bench_sandbox_from_snapshot(b: &mut criterion::Bencher, size: SandboxSize) { // Drop is not included. b.iter_batched( || (), - |_| MultiUseSandbox::from_snapshot(loaded.clone(), HostFunctions::default(), None).unwrap(), + |_| Sandbox::from_snapshot(loaded.clone(), HostFunctions::default(), None).unwrap(), criterion::BatchSize::PerIteration, ); } @@ -698,7 +698,7 @@ fn snapshot_file_benchmark(c: &mut Criterion) { |_| { let loaded = Snapshot::checked_load(&snap_path, OciTag::new("latest").unwrap()).unwrap(); - let mut sbox = MultiUseSandbox::from_snapshot( + let mut sbox = Sandbox::from_snapshot( std::sync::Arc::new(loaded), HostFunctions::default(), None, @@ -723,7 +723,7 @@ fn snapshot_file_benchmark(c: &mut Criterion) { |_| { let loaded = Snapshot::load(&snap_path, OciTag::new("latest").unwrap()).unwrap(); - let mut sbox = MultiUseSandbox::from_snapshot( + let mut sbox = Sandbox::from_snapshot( std::sync::Arc::new(loaded), HostFunctions::default(), None, diff --git a/src/hyperlight_host/examples/crashdump/main.rs b/src/hyperlight_host/examples/crashdump/main.rs index 5ff0a895e..6d5c3ad7b 100644 --- a/src/hyperlight_host/examples/crashdump/main.rs +++ b/src/hyperlight_host/examples/crashdump/main.rs @@ -25,7 +25,7 @@ //! 2. **On-demand crash dump** — When the guest's IDT catches the fault //! (e.g., undefined instruction) and reports it back as a `GuestAborted` //! error, the automatic crash dump is not triggered. You can call -//! [`MultiUseSandbox::generate_crashdump`] explicitly to capture the +//! [`Sandbox::generate_crashdump`] explicitly to capture the //! VM state. //! //! 3. **Disabling crash dumps per sandbox** — You can opt out of crash dump @@ -260,7 +260,7 @@ fn guest_crash_with_dump_disabled(_guest_path: &Path) -> hyperlight_host::Result /// Prints information about the on-demand crash dump API. /// -/// The [`MultiUseSandbox::generate_crashdump`] method captures the current +/// The [`Sandbox::generate_crashdump`] method captures the current /// vCPU state and writes it to an ELF core dump file. This is primarily /// useful when attached to a running process via gdb — for example, when a /// guest function hangs or takes too long to complete. @@ -288,7 +288,7 @@ fn guest_crash_with_dump_disabled(_guest_path: &Path) -> hyperlight_host::Result fn print_on_demand_info() { #[cfg(crashdump)] println!( - "\nUse MultiUseSandbox::generate_crashdump() from gdb to capture\n\ + "\nUse Sandbox::generate_crashdump() from gdb to capture\n\ VM state mid-execution. See docs/how-to-debug-a-hyperlight-guest.md." ); } diff --git a/src/hyperlight_host/examples/func_ctx/main.rs b/src/hyperlight_host/examples/func_ctx/main.rs index 65169def9..dbb6fff24 100644 --- a/src/hyperlight_host/examples/func_ctx/main.rs +++ b/src/hyperlight_host/examples/func_ctx/main.rs @@ -5,7 +5,7 @@ use hyperlight_host::SandboxBuilder; use hyperlight_testing::simple_guest_as_pathbuf; fn main() { - // create a new `MultiUseSandbox` configured to run the `simpleguest.exe` + // create a new `Sandbox` configured to run the `simpleguest.exe` // test guest binary let path = simple_guest_as_pathbuf(); let mut sbox = SandboxBuilder::from_file(path).build().unwrap(); diff --git a/src/hyperlight_host/src/error.rs b/src/hyperlight_host/src/error.rs index 1070ea9f4..9fa9c1456 100644 --- a/src/hyperlight_host/src/error.rs +++ b/src/hyperlight_host/src/error.rs @@ -189,7 +189,7 @@ pub enum HyperlightError { /// /// ## Recovery /// - /// Use [`crate::MultiUseSandbox::restore()`] to recover from a poisoned sandbox. + /// Use [`crate::Sandbox::restore()`] to recover from a poisoned sandbox. #[error("The sandbox was poisoned")] PoisonedSandbox, @@ -312,7 +312,7 @@ impl HyperlightError { /// /// If this method returns `true`, the sandbox will be poisoned and all further operations /// will fail until the sandbox is restored from a non-poisoned snapshot using - /// [`crate::MultiUseSandbox::restore()`]. + /// [`crate::Sandbox::restore()`]. pub(crate) fn is_poison_error(&self) -> bool { // wildcard _ or matches! not used here purposefully to ensure that new error variants // are explicitly considered for poisoning behavior. diff --git a/src/hyperlight_host/src/func/host_functions.rs b/src/hyperlight_host/src/func/host_functions.rs index 9ead200d3..f9bec8390 100644 --- a/src/hyperlight_host/src/func/host_functions.rs +++ b/src/hyperlight_host/src/func/host_functions.rs @@ -45,16 +45,16 @@ impl Registerable for UninitializedSandbox { } /// Allow registering host functions on an already-evolved -/// [`crate::MultiUseSandbox`]. +/// [`crate::Sandbox`]. /// /// The primary entry point for host-function registration is /// [`crate::SandboxBuilder::host_function`] — that's the lifecycle /// phase where the guest hasn't yet been allowed to issue host calls. -/// There are, however, cases where a `MultiUseSandbox` is obtained +/// There are, however, cases where a `Sandbox` is obtained /// without going through the builder: /// /// - Sandboxes loaded from a persisted snapshot. -/// - Any future API that yields a `MultiUseSandbox` directly. +/// - Any future API that yields a `Sandbox` directly. /// /// In those cases the caller never had a chance to register up front, /// so we expose the same trait implementation here for late @@ -63,7 +63,7 @@ impl Registerable for UninitializedSandbox { /// time, so inserting into the registry after the sandbox is built is /// semantically safe as long as the first host-function invocation /// happens after registration completes. -impl Registerable for crate::MultiUseSandbox { +impl Registerable for crate::Sandbox { fn register_host_function( &mut self, name: &str, diff --git a/src/hyperlight_host/src/lib.rs b/src/hyperlight_host/src/lib.rs index 28bbf9472..afd9ade1f 100644 --- a/src/hyperlight_host/src/lib.rs +++ b/src/hyperlight_host/src/lib.rs @@ -9,7 +9,7 @@ //! and host-guest communication. //! //! The primary entry point is [`SandboxBuilder`], which produces a -//! [`MultiUseSandbox`] for executing guest functions. +//! [`Sandbox`] for executing guest functions. //! //! ## Guest Requirements //! @@ -73,17 +73,20 @@ pub(crate) mod testing; pub use error::HyperlightError; /// The re-export for the `is_hypervisor_present` type pub use hypervisor::virtual_machine::is_hypervisor_present; +/// Deprecated name for [`Sandbox`]. +#[allow(deprecated)] +pub use sandbox::MultiUseSandbox; /// A sandbox that can call be used to make multiple calls to guest functions, /// and otherwise reused multiple times -pub use sandbox::MultiUseSandbox; -/// The lifecycle state of a [`MultiUseSandbox`]. +pub use sandbox::Sandbox; +/// The lifecycle state of a [`Sandbox`]. pub use sandbox::SandboxStatus; /// The re-export for the `UninitializedSandbox` type pub use sandbox::UninitializedSandbox; /// The re-export for the `SandboxBuilder` type pub use sandbox::builder::SandboxBuilder; /// A collection of host functions that can be supplied to a sandbox -/// constructor (e.g. [`MultiUseSandbox::from_snapshot`]). +/// constructor (e.g. [`Sandbox::from_snapshot`]). pub use sandbox::host_funcs::HostFunctions; /// The re-export for the `GuestBinary` type pub use sandbox::uninitialized::GuestBinary; diff --git a/src/hyperlight_host/src/mem/memory_region.rs b/src/hyperlight_host/src/mem/memory_region.rs index 8f6e978c5..75636a6c7 100644 --- a/src/hyperlight_host/src/mem/memory_region.rs +++ b/src/hyperlight_host/src/mem/memory_region.rs @@ -127,7 +127,7 @@ pub enum MemoryRegionType { Scratch, /// The snapshot region Snapshot, - /// An externally-mapped file (via [`MultiUseSandbox::map_file_cow`]). + /// An externally-mapped file (via [`Sandbox::map_file_cow`]). /// These regions are backed by file handles (Windows) or mmap /// (Linux) and are read-only + executable. They are cleaned up /// during restore/drop — not part of the guest's own allocator. diff --git a/src/hyperlight_host/src/sandbox/builder.rs b/src/hyperlight_host/src/sandbox/builder.rs index d30a8dbdd..144aa5eec 100644 --- a/src/hyperlight_host/src/sandbox/builder.rs +++ b/src/hyperlight_host/src/sandbox/builder.rs @@ -19,9 +19,7 @@ use crate::sandbox::config::GuestMsrError; use crate::sandbox::host_funcs::FunctionEntry; use crate::sandbox::snapshot::Snapshot; use crate::sandbox::uninitialized::{GuestBlob, GuestEnvironment}; -use crate::{ - GuestBinary, HostFunctions, MultiUseSandbox as Sandbox, Result, UninitializedSandbox, new_error, -}; +use crate::{GuestBinary, HostFunctions, Result, Sandbox, UninitializedSandbox, new_error}; /// What a [`SandboxBuilder`] builds the sandbox from. enum Source { diff --git a/src/hyperlight_host/src/sandbox/config.rs b/src/hyperlight_host/src/sandbox/config.rs index 0d1ad103a..edd632d16 100644 --- a/src/hyperlight_host/src/sandbox/config.rs +++ b/src/hyperlight_host/src/sandbox/config.rs @@ -196,8 +196,8 @@ impl SandboxConfiguration { /// Declares the MSRs the guest depends on. /// /// A declared MSR's value is part of the sandbox's saved state: captured by - /// [`MultiUseSandbox::snapshot`](crate::MultiUseSandbox::snapshot) and written - /// back on [`MultiUseSandbox::restore`](crate::MultiUseSandbox::restore). Every + /// [`Sandbox::snapshot`](crate::Sandbox::snapshot) and written + /// back on [`Sandbox::restore`](crate::Sandbox::restore). Every /// MSR you do not declare is reset to a clean default on each restore. /// /// If this method is not called, only a small core of essential CPU state diff --git a/src/hyperlight_host/src/sandbox/file_mapping.rs b/src/hyperlight_host/src/sandbox/file_mapping.rs index 94a70d999..8d65c29e4 100644 --- a/src/hyperlight_host/src/sandbox/file_mapping.rs +++ b/src/hyperlight_host/src/sandbox/file_mapping.rs @@ -6,8 +6,8 @@ //! This module splits the file mapping operation into two phases: //! - **Prepare** ([`prepare_file_cow`]): performs host-side OS calls //! (open file, create mapping) without requiring a VM. -//! - **Apply**: performed by the caller (either [`MultiUseSandbox::map_file_cow`] -//! or [`evolve_impl_multi_use`]) to map the prepared region into +//! - **Apply**: performed by the caller (either [`Sandbox::map_file_cow`] +//! or [`initialize_sandbox`]) to map the prepared region into //! the guest via [`HyperlightVm::map_region`]. //! //! This separation allows [`UninitializedSandbox`] to accept diff --git a/src/hyperlight_host/src/sandbox/host_funcs.rs b/src/hyperlight_host/src/sandbox/host_funcs.rs index a5b9a645d..381d7b8e5 100644 --- a/src/hyperlight_host/src/sandbox/host_funcs.rs +++ b/src/hyperlight_host/src/sandbox/host_funcs.rs @@ -23,7 +23,7 @@ pub struct FunctionRegistry { } /// A collection of host functions that can be supplied to a sandbox -/// constructor (e.g. [`crate::MultiUseSandbox::from_snapshot`]) to +/// constructor (e.g. [`crate::Sandbox::from_snapshot`]) to /// expose host-side functionality to the guest. /// /// Use [`HostFunctions::default`] to start with the standard diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized.rs similarity index 98% rename from src/hyperlight_host/src/sandbox/initialized_multi_use.rs rename to src/hyperlight_host/src/sandbox/initialized.rs index a560f8c60..e5ab44469 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized.rs @@ -28,7 +28,7 @@ use crate::metrics::{ }; use crate::{HyperlightError, Result, log_then_return}; -/// The lifecycle state of a [`MultiUseSandbox`]. +/// The lifecycle state of a [`Sandbox`]. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum SandboxStatus { /// The sandbox can execute guest operations. @@ -78,7 +78,7 @@ impl SandboxStatus { /// memory mappings can leave the sandbox /// [`Unrecoverable`](SandboxStatus::Unrecoverable). Further restore attempts and /// guest operations are rejected. The sandbox must be discarded. -pub struct MultiUseSandbox { +pub struct Sandbox { status: SandboxStatus, pub(crate) host_funcs: Arc>, pub(crate) mem_mgr: SandboxMemoryManager, @@ -96,9 +96,13 @@ pub struct MultiUseSandbox { max_guest_log_level: Option, } +/// Deprecated name for [`Sandbox`]. +#[deprecated(since = "0.18.0", note = "use Sandbox")] +pub type MultiUseSandbox = Sandbox; + /// Callback for discovering page table roots from guest memory. /// -/// Called during [`MultiUseSandbox::snapshot`] with: +/// Called during [`Sandbox::snapshot`] with: /// - `snapshot_mem` - the sandbox's snapshot (shared) memory as a byte slice /// - `scratch_mem` - the sandbox's scratch memory as a byte slice /// - `root_pt_gpa` - the root page table GPA of the currently-executing @@ -108,7 +112,7 @@ pub struct MultiUseSandbox { /// empty, only `root_pt_gpa` is used. pub type PtRootFinder = Box Vec + Send>; -impl MultiUseSandbox { +impl Sandbox { fn check_ready(&self) -> Result<()> { match self.status { SandboxStatus::Ready => Ok(()), @@ -123,7 +127,7 @@ impl MultiUseSandbox { } } - /// Move an `UninitializedSandbox` into a new `MultiUseSandbox` instance. + /// Move an `UninitializedSandbox` into a new `Sandbox` instance. /// /// This function is not equivalent to doing an `evolve` from uninitialized /// to initialized, and is purposely not exposed publicly outside the crate @@ -133,7 +137,7 @@ impl MultiUseSandbox { host_funcs: Arc>, mgr: SandboxMemoryManager, vm: HyperlightVm, - ) -> MultiUseSandbox { + ) -> Sandbox { // Initialization can log or call the host before the first guest call. let transport_dirty = matches!(mgr.next_action, super::snapshot::NextAction::Initialise(_)); @@ -168,7 +172,7 @@ impl MultiUseSandbox { self.pt_root_finder = Some(finder); } - /// Create a `MultiUseSandbox` directly from a [`Snapshot`], + /// Create a `Sandbox` directly from a [`Snapshot`], /// bypassing guest binary loading and initialization. /// /// This is useful for fast sandbox creation when a snapshot of @@ -204,7 +208,7 @@ impl MultiUseSandbox { /// /// ```no_run /// # use std::sync::Arc; - /// # use hyperlight_host::{HostFunctions, MultiUseSandbox, SandboxBuilder}; + /// # use hyperlight_host::{HostFunctions, Sandbox, SandboxBuilder}; /// # fn example() -> Result<(), Box> { /// // Create and initialize a sandbox the normal way /// let mut sandbox = SandboxBuilder::from_file("guest.bin").build()?; @@ -213,7 +217,7 @@ impl MultiUseSandbox { /// let snapshot = sandbox.snapshot()?; /// /// // Create a new sandbox directly from the snapshot - /// let mut sandbox2 = MultiUseSandbox::from_snapshot(snapshot, HostFunctions::default(), None)?; + /// let mut sandbox2 = Sandbox::from_snapshot(snapshot, HostFunctions::default(), None)?; /// let result: i32 = sandbox2.call("GetValue", ())?; /// # Ok(()) /// # } @@ -223,12 +227,12 @@ impl MultiUseSandbox { /// /// ```no_run /// # use std::sync::Arc; - /// # use hyperlight_host::{HostFunctions, MultiUseSandbox}; + /// # use hyperlight_host::{HostFunctions, Sandbox}; /// # use hyperlight_host::sandbox::snapshot::{OciTag, Snapshot}; /// # fn example() -> Result<(), Box> { /// let tag = OciTag::new("latest")?; /// let snapshot = Arc::new(Snapshot::load("./guest_snapshot", tag)?); - /// let mut sandbox = MultiUseSandbox::from_snapshot(snapshot, HostFunctions::default(), None)?; + /// let mut sandbox = Sandbox::from_snapshot(snapshot, HostFunctions::default(), None)?; /// let result: String = sandbox.call("Echo", "hello".to_string())?; /// # Ok(()) /// # } @@ -359,7 +363,7 @@ impl MultiUseSandbox { hshm.restore_virtq(virtq)?; } - let mut sbox = MultiUseSandbox::from_uninit(host_funcs, hshm, vm); + let mut sbox = Sandbox::from_uninit(host_funcs, hshm, vm); if let Some(log_level) = max_guest_log_level { sbox.log_level(log_level)?; @@ -371,10 +375,10 @@ impl MultiUseSandbox { /// Creates a snapshot of the sandbox's current memory state. /// /// The returned snapshot can be applied to any - /// [`MultiUseSandbox`] whose registered host functions are a + /// [`Sandbox`] whose registered host functions are a /// superset of those registered here at the time of capture. See - /// [`MultiUseSandbox::restore`] and - /// [`MultiUseSandbox::from_snapshot`] for the exact compatibility + /// [`Sandbox::restore`] and + /// [`Sandbox::from_snapshot`] for the exact compatibility /// rules and the error variants returned on mismatch. /// /// On x86_64, the snapshot saves a small core of essential CPU state plus @@ -507,7 +511,7 @@ impl MultiUseSandbox { /// carrying the missing names and signature differences. /// /// On x86_64, this restores the MSR state captured by - /// [`MultiUseSandbox::snapshot`]: + /// [`Sandbox::snapshot`]: /// [`SandboxBuilder::guest_msrs`](crate::SandboxBuilder::guest_msrs) /// selects which MSRs are saved and restored. /// @@ -1078,10 +1082,10 @@ impl MultiUseSandbox { /// (gdb) info threads /// # find the thread that is running the guest function you want to debug /// (gdb) thread - /// # switch to the frame where you have access to your MultiUseSandbox instance + /// # switch to the frame where you have access to your Sandbox instance /// (gdb) backtrace /// (gdb) frame - /// # get the pointer to your MultiUseSandbox instance + /// # get the pointer to your Sandbox instance /// # Get the sandbox pointer /// (gdb) print sandbox /// # Call the crashdump function @@ -1159,7 +1163,7 @@ impl MultiUseSandbox { } } -impl Callable for MultiUseSandbox { +impl Callable for Sandbox { fn call( &mut self, func_name: &str, @@ -1170,14 +1174,14 @@ impl Callable for MultiUseSandbox { } } -impl std::fmt::Debug for MultiUseSandbox { +impl std::fmt::Debug for Sandbox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("MultiUseSandbox").finish() + f.debug_struct("Sandbox").finish() } } /// Emit a warning for each memory-layout field in `caller` that -/// disagrees with `snapshot`. Used by [`MultiUseSandbox::from_snapshot`] +/// disagrees with `snapshot`. Used by [`Sandbox::from_snapshot`] /// to surface ignored caller-supplied layout values, since those /// fields are always taken from the snapshot. fn warn_on_layout_override( @@ -1256,7 +1260,7 @@ mod tests { use crate::sandbox::SandboxConfiguration; use crate::sandbox::uninitialized::{GuestBlob, GuestEnvironment}; use crate::{ - GuestBinary, HyperlightError, MultiUseSandbox, Result, SandboxBuilder, SandboxStatus, + GuestBinary, HyperlightError, Result, Sandbox, SandboxBuilder, SandboxStatus, UninitializedSandbox, }; @@ -1275,7 +1279,7 @@ mod tests { assert!(SandboxStatus::Unrecoverable.is_unrecoverable()); } - fn assert_virtq_attached(sbox: &MultiUseSandbox) { + fn assert_virtq_attached(sbox: &Sandbox) { assert!(sbox.mem_mgr.g2h_consumer.is_some()); assert!(sbox.mem_mgr.h2g_consumer.is_some()); } @@ -1483,7 +1487,7 @@ mod tests { } } - /// Tests that evolving from MultiUseSandbox to MultiUseSandbox creates a new state + /// Tests that evolving from Sandbox to Sandbox creates a new state /// and restoring a snapshot from before evolving restores the previous state #[test] fn snapshot_evolve_restore_handles_state_correctly() { @@ -2959,7 +2963,7 @@ mod tests { #[test] #[cfg(target_arch = "x86_64")] fn snapshot_restore_resets_xcr0() { - let mut sandbox: MultiUseSandbox = { + let mut sandbox: Sandbox = { let path = simple_guest_as_pathbuf(); let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); u_sbox.evolve().unwrap() @@ -3026,9 +3030,9 @@ mod tests { } } - /// Helper: create a MultiUseSandbox from the simple guest with default config. + /// Helper: create a Sandbox from the simple guest with default config. #[cfg(feature = "trace_guest")] - fn sandbox_for_gva_tests() -> MultiUseSandbox { + fn sandbox_for_gva_tests() -> Sandbox { let path = simple_guest_as_pathbuf(); SandboxBuilder::from_file(path).build().unwrap() } @@ -3037,7 +3041,7 @@ mod tests { /// `ReadMappedBuffer(gva, len, false)` and from the host side via /// `read_guest_memory_by_gva`, then assert both views are identical. #[cfg(feature = "trace_guest")] - fn assert_gva_read_matches(sbox: &mut MultiUseSandbox, gva: u64, len: usize) { + fn assert_gva_read_matches(sbox: &mut Sandbox, gva: u64, len: usize) { // Guest reads via its own page tables let expected: Vec = sbox .call("ReadMappedBuffer", (gva, len as u64, true)) @@ -4460,7 +4464,7 @@ mod tests { } } - fn assert_omitted_msr_does_not_retain(sbox: &mut MultiUseSandbox, index: u32) { + fn assert_omitted_msr_does_not_retain(sbox: &mut Sandbox, index: u32) { let baseline = sbox.snapshot().unwrap(); let original: u64 = match sbox.call("ReadMSR", index) { Ok(value) => value, @@ -4560,7 +4564,7 @@ mod tests { } fn assert_guest_msr_is_writable_and_restored( - sbox: &mut MultiUseSandbox, + sbox: &mut Sandbox, index: u32, sentinel: u64, ) { @@ -4585,7 +4589,7 @@ mod tests { ); } - fn assert_guest_counter_is_writable_and_restored(sbox: &mut MultiUseSandbox, index: u32) { + fn assert_guest_counter_is_writable_and_restored(sbox: &mut Sandbox, index: u32) { let baseline = sbox.snapshot().unwrap(); let original: u64 = sbox.call("ReadMSR", index).unwrap(); let jump = original.wrapping_add(1 << 60); @@ -4607,11 +4611,7 @@ mod tests { /// Verifies that a guest MSR write faults or resets to its baseline. #[cfg(target_arch = "x86_64")] - fn assert_msr_write_does_not_survive_restore( - sbox: &mut MultiUseSandbox, - msr: u32, - sentinel: u64, - ) { + fn assert_msr_write_does_not_survive_restore(sbox: &mut Sandbox, msr: u32, sentinel: u64) { let baseline = sbox.snapshot().unwrap(); let original: u64 = match sbox.call("ReadMSR", msr) { Ok(v) => v, @@ -4869,7 +4869,7 @@ mod tests { } } - /// Tests for [`MultiUseSandbox::from_snapshot`] in-memory. + /// Tests for [`Sandbox::from_snapshot`] in-memory. mod from_snapshot { use std::sync::Arc; @@ -4879,15 +4879,15 @@ mod tests { use crate::func::Registerable; use crate::sandbox::SandboxConfiguration; use crate::sandbox::snapshot::Snapshot; - use crate::{GuestBinary, HostFunctions, HyperlightError, MultiUseSandbox, SandboxBuilder}; + use crate::{GuestBinary, HostFunctions, HyperlightError, Sandbox, SandboxBuilder}; - fn make_sandbox() -> MultiUseSandbox { + fn make_sandbox() -> Sandbox { let path = simple_guest_as_pathbuf(); SandboxBuilder::from_file(path).build().unwrap() } /// Sandbox with an extra `Add(i32, i32) -> i32` host function. - fn make_sandbox_with_add() -> MultiUseSandbox { + fn make_sandbox_with_add() -> Sandbox { let path = simple_guest_as_pathbuf(); SandboxBuilder::from_file(path) .host_function("Add", |a: i32, b: i32| a + b) @@ -4985,12 +4985,9 @@ mod tests { .unwrap(); let mut config = SandboxConfiguration::default(); config.set_max_guest_log_level(max_level); - let mut sbox = MultiUseSandbox::from_snapshot( - Arc::new(snap), - HostFunctions::default(), - Some(config), - ) - .unwrap(); + let mut sbox = + Sandbox::from_snapshot(Arc::new(snap), HostFunctions::default(), Some(config)) + .unwrap(); // Drop any log records emitted while the guest initialised. LOGGER.clear_log_calls(); @@ -5060,8 +5057,7 @@ mod tests { config }); let mut sandbox = - MultiUseSandbox::from_snapshot(snapshot, HostFunctions::default(), config) - .unwrap(); + Sandbox::from_snapshot(snapshot, HostFunctions::default(), config).unwrap(); LOGGER.clear_log_calls(); for level in [ @@ -5107,7 +5103,7 @@ mod tests { ); } - /// A runtime log-level override set on a MultiUseSandbox survives restore. + /// A runtime log-level override set on a Sandbox survives restore. /// /// Ignored because it installs a process-global `log` logger; run /// in isolation via the `test-isolated` Justfile recipe. @@ -5131,7 +5127,7 @@ mod tests { .unwrap(); sandbox.log_level(LevelFilter::ERROR).unwrap(); - let count_guest_logs = |sandbox: &mut MultiUseSandbox| { + let count_guest_logs = |sandbox: &mut Sandbox| { LOGGER.clear_log_calls(); for level in [ LevelFilter::TRACE, @@ -5180,7 +5176,7 @@ mod tests { .build() .unwrap(); let encoded: u64 = GuestLogFilter::Trace.into(); - let count_guest_logs = |sandbox: &mut MultiUseSandbox| { + let count_guest_logs = |sandbox: &mut Sandbox| { LOGGER.clear_log_calls(); sandbox .call::<()>("LogMessage", ("hello".to_string(), encoded as i32)) @@ -5214,7 +5210,7 @@ mod tests { LOGGER.set_max_level(log::LevelFilter::Trace); let encoded: u64 = GuestLogFilter::Trace.into(); - let count_guest_logs = |sandbox: &mut MultiUseSandbox| { + let count_guest_logs = |sandbox: &mut Sandbox| { LOGGER.clear_log_calls(); sandbox .call::<()>("LogMessage", ("hello".to_string(), encoded as i32)) @@ -5500,7 +5496,7 @@ mod tests { } /// Registering a host function on an already-evolved - /// `MultiUseSandbox` must invalidate its cached snapshot, so + /// `Sandbox` must invalidate its cached snapshot, so /// that the next `snapshot()` reflects the new required /// host-function set. #[test] diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index 9953e0df1..ca2c94b8e 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -11,7 +11,14 @@ pub(crate) mod file_mapping; pub(crate) mod host_funcs; /// Functionality for dealing with initialized sandboxes that can /// call 0 or more guest functions -pub mod initialized_multi_use; +mod initialized; +/// Deprecated path for the items in the `initialized` module. +#[deprecated(since = "0.18.0", note = "use hyperlight_host::sandbox")] +pub mod initialized_multi_use { + #[allow(deprecated)] + pub use super::initialized::MultiUseSandbox; + pub use super::initialized::{PtRootFinder, Sandbox, SandboxStatus}; +} pub(crate) mod outb; /// Functionality for creating uninitialized sandboxes, manipulating them, /// and converting them to initialized sandboxes. @@ -34,8 +41,11 @@ pub(crate) mod trace; pub use callable::Callable; /// Re-export for `SandboxConfiguration` type pub use config::SandboxConfiguration; -/// Re-export for the `MultiUseSandbox` type -pub use initialized_multi_use::{MultiUseSandbox, PtRootFinder, SandboxStatus}; +/// Re-export for the deprecated `MultiUseSandbox` name +#[allow(deprecated)] +pub use initialized::MultiUseSandbox; +/// Re-export for the `Sandbox` type +pub use initialized::{PtRootFinder, Sandbox, SandboxStatus}; /// Re-export for `GuestBinary` type pub use uninitialized::GuestBinary; /// Re-export for `UninitializedSandbox` type @@ -50,12 +60,12 @@ mod tests { use hyperlight_testing::simple_guest_as_pathbuf; use crate::sandbox::uninitialized::GuestBinary; - use crate::{MultiUseSandbox, UninitializedSandbox, new_error}; + use crate::{Sandbox, UninitializedSandbox, new_error}; #[test] fn check_create_and_use_sandbox_on_different_threads() { let unintializedsandbox_queue = Arc::new(ArrayQueue::::new(10)); - let sandbox_queue = Arc::new(ArrayQueue::::new(10)); + let sandbox_queue = Arc::new(ArrayQueue::::new(10)); for i in 0..10 { let simple_guest_path = simple_guest_as_pathbuf(); diff --git a/src/hyperlight_host/src/sandbox/snapshot/file/mod.rs b/src/hyperlight_host/src/sandbox/snapshot/file/mod.rs index d69c954f5..b336907f5 100644 --- a/src/hyperlight_host/src/sandbox/snapshot/file/mod.rs +++ b/src/hyperlight_host/src/sandbox/snapshot/file/mod.rs @@ -713,12 +713,12 @@ impl Snapshot { /// /// ```no_run /// # use std::sync::Arc; - /// # use hyperlight_host::{HostFunctions, MultiUseSandbox}; + /// # use hyperlight_host::{HostFunctions, Sandbox}; /// # use hyperlight_host::sandbox::snapshot::{OciTag, Snapshot}; /// # fn example() -> Result<(), Box> { /// let tag = OciTag::new("latest")?; /// let snapshot = Arc::new(Snapshot::load("./guest_snapshot", tag)?); - /// let mut sandbox = MultiUseSandbox::from_snapshot(snapshot, HostFunctions::default(), None)?; + /// let mut sandbox = Sandbox::from_snapshot(snapshot, HostFunctions::default(), None)?; /// let result: String = sandbox.call("Echo", "hello".to_string())?; /// # Ok(()) /// # } diff --git a/src/hyperlight_host/src/sandbox/snapshot/file_tests.rs b/src/hyperlight_host/src/sandbox/snapshot/file_tests.rs index a6df4ba1a..d36b4b277 100644 --- a/src/hyperlight_host/src/sandbox/snapshot/file_tests.rs +++ b/src/hyperlight_host/src/sandbox/snapshot/file_tests.rs @@ -15,27 +15,27 @@ use sha2::{Digest as _, Sha256}; use crate::func::Registerable; use crate::mem::shared_mem::SharedMemory; use crate::sandbox::snapshot::{OciDigest, OciReference, OciTag, Snapshot}; -use crate::{GuestBinary, HostFunctions, MultiUseSandbox, SandboxBuilder, UninitializedSandbox}; +use crate::{GuestBinary, HostFunctions, Sandbox, SandboxBuilder, UninitializedSandbox}; -fn create_test_sandbox() -> MultiUseSandbox { +fn create_test_sandbox() -> Sandbox { let path = simple_guest_as_pathbuf(); SandboxBuilder::from_file(path).build().unwrap() } -fn create_c_test_sandbox() -> MultiUseSandbox { +fn create_c_test_sandbox() -> Sandbox { let path = c_simple_guest_as_pathbuf(); SandboxBuilder::from_file(path).build().unwrap() } -fn random_sequence(sandbox: &mut MultiUseSandbox) -> [i32; 4] { +fn random_sequence(sandbox: &mut Sandbox) -> [i32; 4] { std::array::from_fn(|_| sandbox.call("NextRandom", ()).unwrap()) } -fn random_long_sequence(sandbox: &mut MultiUseSandbox) -> [i64; 4] { +fn random_long_sequence(sandbox: &mut Sandbox) -> [i64; 4] { std::array::from_fn(|_| sandbox.call("NextRandomLong", ()).unwrap()) } -fn libc_rng_reseed_request(sandbox: &MultiUseSandbox) -> u64 { +fn libc_rng_reseed_request(sandbox: &Sandbox) -> u64 { let scratch_size = sandbox.mem_mgr.scratch_mem.mem_size(); sandbox .mem_mgr @@ -130,8 +130,7 @@ fn find_transport_blob(oci_dir: &std::path::Path) -> std::path::PathBuf { #[test] fn from_snapshot_already_initialized_in_memory() { let snapshot = create_snapshot(); - let mut sbox2 = - MultiUseSandbox::from_snapshot(snapshot, HostFunctions::default(), None).unwrap(); + let mut sbox2 = Sandbox::from_snapshot(snapshot, HostFunctions::default(), None).unwrap(); let result: i32 = sbox2.call("GetStatic", ()).unwrap(); assert_eq!(result, 0); } @@ -143,8 +142,7 @@ fn from_snapshot_in_memory_pre_init() { crate::sandbox::SandboxConfiguration::default(), ) .unwrap(); - let mut sbox = - MultiUseSandbox::from_snapshot(Arc::new(snap), HostFunctions::default(), None).unwrap(); + let mut sbox = Sandbox::from_snapshot(Arc::new(snap), HostFunctions::default(), None).unwrap(); assert_eq!(libc_rng_reseed_request(&sbox), 0); let result: i32 = sbox.call("GetStatic", ()).unwrap(); assert_eq!(result, 0); @@ -203,7 +201,7 @@ fn round_trip_save_load_call() { let loaded = Snapshot::checked_load(&oci, OciTag::new("latest").unwrap()).unwrap(); let mut sbox2 = - MultiUseSandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); + Sandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); let result: String = sbox2.call("Echo", "hello\n".to_string()).unwrap(); assert_eq!(result, "hello\n"); @@ -291,7 +289,7 @@ fn save_self_heals_same_length_wrong_content_snapshot_blob() { // descriptor digest. let loaded = Snapshot::checked_load(&oci, OciTag::new("latest").unwrap()).unwrap(); let mut sbox2 = - MultiUseSandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); + Sandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); let result: String = sbox2.call("Echo", "hello\n".to_string()).unwrap(); assert_eq!(result, "hello\n"); } @@ -469,7 +467,7 @@ fn disk_snapshot_non_superset_guest_msrs_rejected() { snap.save(&path, &OciTag::new("latest").unwrap()).unwrap(); let loaded = Arc::new(Snapshot::checked_load(&path, OciTag::new("latest").unwrap()).unwrap()); - let err = MultiUseSandbox::from_snapshot(loaded.clone(), HostFunctions::default(), None) + let err = Sandbox::from_snapshot(loaded.clone(), HostFunctions::default(), None) .expect_err("loading a snapshot MSR the destination cannot restore must fail"); assert!( format!("{err:?}").contains("InvalidSnapshotMsrIndex"), @@ -523,8 +521,7 @@ fn restore_from_loaded_snapshot() { .unwrap(); let loaded = Arc::new(Snapshot::checked_load(&path, OciTag::new("latest").unwrap()).unwrap()); - let mut sbox2 = - MultiUseSandbox::from_snapshot(loaded.clone(), HostFunctions::default(), None).unwrap(); + let mut sbox2 = Sandbox::from_snapshot(loaded.clone(), HostFunctions::default(), None).unwrap(); sbox2.call::("AddToStatic", 5i32).unwrap(); assert_eq!(sbox2.call::("GetStatic", ()).unwrap(), 5); @@ -644,7 +641,7 @@ fn restore_across_independent_oci_loads_succeeds() { let loaded1 = Arc::new(Snapshot::checked_load(&p1, OciTag::new("latest").unwrap()).unwrap()); let loaded2 = Arc::new(Snapshot::checked_load(&p2, OciTag::new("latest").unwrap()).unwrap()); - let mut sbox = MultiUseSandbox::from_snapshot(loaded2, HostFunctions::default(), None).unwrap(); + let mut sbox = Sandbox::from_snapshot(loaded2, HostFunctions::default(), None).unwrap(); sbox.restore(loaded1).unwrap(); assert_eq!(sbox.call::("GetStatic", ()).unwrap(), 0); } @@ -673,8 +670,7 @@ fn cow_does_not_mutate_backing_file() { { let loaded = Snapshot::checked_load(&path, OciTag::new("latest").unwrap()).unwrap(); let mut sbox = - MultiUseSandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None) - .unwrap(); + Sandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); sbox.call::("AddToStatic", 99).unwrap(); } @@ -937,9 +933,9 @@ fn call_snapshot_without_sregs_rejected() { // Host-function validation. The loaded sandbox's `HostFunctions` must // be a superset (by name and signature) of those recorded in the snapshot. -/// Build a `MultiUseSandbox` with the default host functions plus a +/// Build a `Sandbox` with the default host functions plus a /// custom `Add(i32, i32) -> i32`. -fn create_sandbox_with_custom_host_funcs() -> MultiUseSandbox { +fn create_sandbox_with_custom_host_funcs() -> Sandbox { let path = simple_guest_as_pathbuf(); SandboxBuilder::from_file(path) .host_function("Add", |a: i32, b: i32| Ok(a + b)) @@ -965,8 +961,7 @@ fn from_snapshot_accepts_matching_host_functions() { let loaded = Snapshot::checked_load(&path, OciTag::new("latest").unwrap()).unwrap(); let mut sbox2 = - MultiUseSandbox::from_snapshot(Arc::new(loaded), host_funcs_with_matching_add(), None) - .unwrap(); + Sandbox::from_snapshot(Arc::new(loaded), host_funcs_with_matching_add(), None).unwrap(); assert_eq!(sbox2.call::("GetStatic", ()).unwrap(), 0); } @@ -981,7 +976,7 @@ fn from_snapshot_rejects_missing_host_function() { snap.save(&path, &OciTag::new("latest").unwrap()).unwrap(); let loaded = Snapshot::checked_load(&path, OciTag::new("latest").unwrap()).unwrap(); - let err = MultiUseSandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None) + let err = Sandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None) .expect_err("from_snapshot must reject a HostFunctions set missing `Add`"); let msg = format!("{}", err); assert!( @@ -1006,7 +1001,7 @@ fn from_snapshot_rejects_signature_mismatch() { .unwrap(); let loaded = Snapshot::checked_load(&path, OciTag::new("latest").unwrap()).unwrap(); - let err = MultiUseSandbox::from_snapshot(Arc::new(loaded), hf, None) + let err = Sandbox::from_snapshot(Arc::new(loaded), hf, None) .expect_err("from_snapshot must reject a signature mismatch on Add"); let msg = format!("{}", err); assert!( @@ -1031,7 +1026,7 @@ fn from_snapshot_accepts_extra_host_functions() { .unwrap(); let loaded = Snapshot::checked_load(&path, OciTag::new("latest").unwrap()).unwrap(); - let mut sbox2 = MultiUseSandbox::from_snapshot(Arc::new(loaded), hf, None).unwrap(); + let mut sbox2 = Sandbox::from_snapshot(Arc::new(loaded), hf, None).unwrap(); assert_eq!(sbox2.call::("GetStatic", ()).unwrap(), 0); } @@ -1052,7 +1047,7 @@ fn from_snapshot_accepts_zero_arg_host_function() { hf.register_host_function("Zero", || Ok(7i64)).unwrap(); let loaded = Snapshot::checked_load(&path, OciTag::new("latest").unwrap()).unwrap(); - let _sbox2 = MultiUseSandbox::from_snapshot(Arc::new(loaded), hf, None) + let _sbox2 = Sandbox::from_snapshot(Arc::new(loaded), hf, None) .expect("zero-arg host function must round-trip through OCI"); } @@ -2188,7 +2183,7 @@ fn manifest_and_index_annotations_tolerated() { let loaded = Snapshot::checked_load(&path, OciTag::new("latest").unwrap()).unwrap(); let mut sbox2 = - MultiUseSandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); + Sandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); assert_eq!(sbox2.call::("GetStatic", ()).unwrap(), 0); } @@ -2396,7 +2391,7 @@ fn load_round_trips() { let loaded = Snapshot::load(&path, OciTag::new("latest").unwrap()).unwrap(); let mut sbox2 = - MultiUseSandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); + Sandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); let result: String = sbox2.call("Echo", "hi\n".to_string()).unwrap(); assert_eq!(result, "hi\n"); } @@ -3065,7 +3060,7 @@ fn save_replaces_symlink_snapshot_blob_with_regular_file() { let loaded = Snapshot::checked_load(&path, OciTag::new("latest").unwrap()).unwrap(); let mut sbox = - MultiUseSandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); + Sandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); let result: String = sbox.call("Echo", "hello\n".to_string()).unwrap(); assert_eq!(result, "hello\n"); } @@ -3154,8 +3149,7 @@ fn persisted_non_default_layout_loads_and_runs() { assert_eq!(loaded.layout().heap_size(), 0x40_000); assert_eq!(loaded.layout().get_scratch_size(), 0x90_000); - let mut restored = - MultiUseSandbox::from_snapshot(loaded, HostFunctions::default(), None).unwrap(); + let mut restored = Sandbox::from_snapshot(loaded, HostFunctions::default(), None).unwrap(); assert_eq!(restored.call::("GetStatic", ()).unwrap(), 42); let large = "x".repeat(0x5000); assert_eq!( @@ -3245,8 +3239,7 @@ fn round_trip_preserves_host_function_signatures() { ); // Loading and using the snapshot must accept the same signature. let loaded = Snapshot::checked_load(&path, OciTag::new("latest").unwrap()).unwrap(); - let _ = MultiUseSandbox::from_snapshot(Arc::new(loaded), host_funcs_with_matching_add(), None) - .unwrap(); + let _ = Sandbox::from_snapshot(Arc::new(loaded), host_funcs_with_matching_add(), None).unwrap(); } #[test] @@ -3266,8 +3259,7 @@ fn snapshot_with_no_host_functions_round_trips() { assert!(cfg["host_functions"].as_array().unwrap().is_empty()); let loaded = Snapshot::load(&path, OciTag::new("latest").unwrap()).unwrap(); - let _ = - MultiUseSandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); + let _ = Sandbox::from_snapshot(Arc::new(loaded), HostFunctions::default(), None).unwrap(); } // Snapshot lineage and restore semantics. `restore` accepts snapshots @@ -3320,8 +3312,7 @@ fn separate_oci_loads_are_mutually_restore_compatible() { let s_x = Arc::new(Snapshot::checked_load(&path, OciTag::new("v1").unwrap()).unwrap()); let s_y = Arc::new(Snapshot::checked_load(&path, OciTag::new("v1").unwrap()).unwrap()); - let mut sbox_x = - MultiUseSandbox::from_snapshot(s_x.clone(), HostFunctions::default(), None).unwrap(); + let mut sbox_x = Sandbox::from_snapshot(s_x.clone(), HostFunctions::default(), None).unwrap(); sbox_x.restore(s_y.clone()).unwrap(); assert_eq!(sbox_x.call::("GetStatic", ()).unwrap(), 0); @@ -3340,8 +3331,7 @@ fn oci_loaded_snapshot_supports_full_lifecycle() { snap.save(&path, &OciTag::new("v1").unwrap()).unwrap(); let loaded = Arc::new(Snapshot::checked_load(&path, OciTag::new("v1").unwrap()).unwrap()); - let mut sbox = - MultiUseSandbox::from_snapshot(loaded.clone(), HostFunctions::default(), None).unwrap(); + let mut sbox = Sandbox::from_snapshot(loaded.clone(), HostFunctions::default(), None).unwrap(); sbox.call::("AddToStatic", 1i32).unwrap(); let s1 = sbox.snapshot().unwrap(); @@ -3554,7 +3544,7 @@ fn save_new_tag_into_loaded_layout_preserves_live_mapping() { // A sandbox built on the live mapping still restores cleanly. let mut live = - MultiUseSandbox::from_snapshot(loaded_a.clone(), HostFunctions::default(), None).unwrap(); + Sandbox::from_snapshot(loaded_a.clone(), HostFunctions::default(), None).unwrap(); live.call::("AddToStatic", 7i32).unwrap(); assert_eq!(live.call::("GetStatic", ()).unwrap(), 7); live.restore(loaded_a).unwrap(); @@ -3634,9 +3624,8 @@ fn random_guest_libc_rng_reseeds_from_snapshot() { let snapshot = sandbox.snapshot().unwrap(); let mut first = - MultiUseSandbox::from_snapshot(snapshot.clone(), HostFunctions::default(), None).unwrap(); - let mut second = - MultiUseSandbox::from_snapshot(snapshot, HostFunctions::default(), None).unwrap(); + Sandbox::from_snapshot(snapshot.clone(), HostFunctions::default(), None).unwrap(); + let mut second = Sandbox::from_snapshot(snapshot, HostFunctions::default(), None).unwrap(); assert_ne!(random_sequence(&mut first), random_sequence(&mut second)); } @@ -3647,9 +3636,8 @@ fn guest_libc_rng_random_reseeds_from_snapshot() { let snapshot = sandbox.snapshot().unwrap(); let mut first = - MultiUseSandbox::from_snapshot(snapshot.clone(), HostFunctions::default(), None).unwrap(); - let mut second = - MultiUseSandbox::from_snapshot(snapshot, HostFunctions::default(), None).unwrap(); + Sandbox::from_snapshot(snapshot.clone(), HostFunctions::default(), None).unwrap(); + let mut second = Sandbox::from_snapshot(snapshot, HostFunctions::default(), None).unwrap(); assert_ne!( random_long_sequence(&mut first), @@ -3713,10 +3701,8 @@ fn persisted_guest_libc_rng_snapshot_reseeds_each_instance() { .unwrap(); let loaded = Arc::new(Snapshot::checked_load(&path, OciTag::new("latest").unwrap()).unwrap()); - let mut first = - MultiUseSandbox::from_snapshot(loaded.clone(), HostFunctions::default(), None).unwrap(); - let mut second = - MultiUseSandbox::from_snapshot(loaded, HostFunctions::default(), None).unwrap(); + let mut first = Sandbox::from_snapshot(loaded.clone(), HostFunctions::default(), None).unwrap(); + let mut second = Sandbox::from_snapshot(loaded, HostFunctions::default(), None).unwrap(); assert_ne!(random_sequence(&mut first), random_sequence(&mut second)); } diff --git a/src/hyperlight_host/src/sandbox/snapshot/mod.rs b/src/hyperlight_host/src/sandbox/snapshot/mod.rs index 63636a9c5..32b5fb730 100644 --- a/src/hyperlight_host/src/sandbox/snapshot/mod.rs +++ b/src/hyperlight_host/src/sandbox/snapshot/mod.rs @@ -114,7 +114,7 @@ struct SnapshotState { /// Names and signatures of host functions registered on the /// sandbox at the time this snapshot was taken. Used by - /// [`crate::MultiUseSandbox::from_snapshot`] to reject a + /// [`crate::Sandbox::from_snapshot`] to reject a /// `HostFunctions` set that is missing required functions or /// has mismatched signatures. host_functions: HostFunctionDetails, diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index 8eb478fea..267f87325 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -11,7 +11,7 @@ use tracing_core::LevelFilter; use super::host_funcs::FunctionRegistry; use super::snapshot::Snapshot; -use super::uninitialized_evolve::evolve_impl_multi_use; +use super::uninitialized_evolve::initialize_sandbox; use crate::func::host_functions::{HostFunction, register_host_function}; use crate::func::{ParameterTuple, SupportedReturnType}; #[cfg(feature = "build-metadata")] @@ -20,7 +20,7 @@ use crate::mem::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegionFlags} use crate::mem::mgr::SandboxMemoryManager; use crate::mem::shared_mem::{ExclusiveSharedMemory, SharedMemory}; use crate::sandbox::SandboxConfiguration; -use crate::{MultiUseSandbox, Result, new_error}; +use crate::{Result, Sandbox, new_error}; #[cfg(any(crashdump, gdb))] #[derive(Clone, Debug, Default)] @@ -51,7 +51,7 @@ pub(crate) struct SandboxRuntimeConfig { /// - Configure sandbox settings before VM creation /// /// The virtual machine is not created until you call [`evolve`](Self::evolve) to transform -/// this into an initialized [`MultiUseSandbox`]. +/// this into an initialized [`Sandbox`]. pub struct UninitializedSandbox { /// Registered host functions pub(crate) host_funcs: Arc>, @@ -254,10 +254,10 @@ impl UninitializedSandbox { /// /// This method consumes the `UninitializedSandbox` and performs the final initialization /// steps to create the underlying virtual machine. Once evolved, the resulting - /// [`MultiUseSandbox`] can execute guest code and handle function calls. + /// [`Sandbox`] can execute guest code and handle function calls. #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - pub fn evolve(self) -> Result { - evolve_impl_multi_use(self) + pub fn evolve(self) -> Result { + initialize_sandbox(self) } /// Map the contents of a file into the guest at a particular address. @@ -401,7 +401,7 @@ mod tests { use crate::sandbox::SandboxConfiguration; use crate::sandbox::uninitialized::{GuestBinary, GuestEnvironment}; - use crate::{MultiUseSandbox, Result, UninitializedSandbox, new_error}; + use crate::{Result, Sandbox, UninitializedSandbox, new_error}; #[cfg(target_os = "linux")] #[test] @@ -502,7 +502,7 @@ mod tests { usbox.register("test0", |arg: i32| Ok(arg + 1)).unwrap(); - let sandbox: Result = usbox.evolve(); + let sandbox: Result = usbox.evolve(); assert!(sandbox.is_ok()); let sandbox = sandbox.unwrap(); @@ -527,7 +527,7 @@ mod tests { usbox.register("test1", |a: i32, b: i32| Ok(a + b)).unwrap(); - let sandbox: Result = usbox.evolve(); + let sandbox: Result = usbox.evolve(); assert!(sandbox.is_ok()); let sandbox = sandbox.unwrap(); @@ -560,7 +560,7 @@ mod tests { }) .unwrap(); - let sandbox: Result = usbox.evolve(); + let sandbox: Result = usbox.evolve(); assert!(sandbox.is_ok()); let sandbox = sandbox.unwrap(); @@ -578,7 +578,7 @@ mod tests { // calling a function that doesn't exist { let usbox = uninitialized_sandbox(); - let sandbox: Result = usbox.evolve(); + let sandbox: Result = usbox.evolve(); assert!(sandbox.is_ok()); let sandbox = sandbox.unwrap(); @@ -753,7 +753,7 @@ mod tests { #[test] fn check_create_and_use_sandbox_on_different_threads() { let unintializedsandbox_queue = Arc::new(ArrayQueue::::new(10)); - let sandbox_queue = Arc::new(ArrayQueue::::new(10)); + let sandbox_queue = Arc::new(ArrayQueue::::new(10)); for i in 0..10 { let simple_guest_path = simple_guest_as_pathbuf(); @@ -1051,12 +1051,11 @@ mod tests { TEST_LOGGER.clear_log_calls(); TEST_LOGGER.set_max_level(log::LevelFilter::Info); - let mut valid_binary_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - valid_binary_path.push("src"); - valid_binary_path.push("sandbox"); - valid_binary_path.push("initialized.rs"); + // An existing file that is never a valid guest binary. + let mut invalid_binary_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + invalid_binary_path.push("Cargo.toml"); - let sbox = UninitializedSandbox::new(GuestBinary::FilePath(valid_binary_path), None); + let sbox = UninitializedSandbox::new(GuestBinary::FilePath(invalid_binary_path), None); assert!(sbox.is_err()); // There should be 2 calls this time when we change to the log @@ -1076,11 +1075,7 @@ mod tests { let logcall = TEST_LOGGER.get_log_call(1).unwrap(); assert_eq!(Level::Error, logcall.level); - assert!( - logcall - .args - .starts_with("error=Error(\"GuestBinary not found:") - ); + assert!(logcall.args.starts_with("error=PEFileProcessingFailure")); assert_eq!("hyperlight_host::sandbox::uninitialized", logcall.target); } { @@ -1094,7 +1089,7 @@ mod tests { ); res.unwrap() }; - let _: Result = sbox.evolve(); + let _: Result = sbox.evolve(); let num_calls = TEST_LOGGER.num_log_calls(); diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index 0404988f6..0bd355474 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -17,10 +17,10 @@ use crate::sandbox::config::DebugInfo; use crate::sandbox::trace::MemTraceInfo; #[cfg(target_os = "linux")] use crate::signal_handlers::setup_signal_handlers; -use crate::{MultiUseSandbox, Result, UninitializedSandbox}; +use crate::{Result, Sandbox, UninitializedSandbox}; #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] -pub(super) fn evolve_impl_multi_use(u_sbox: UninitializedSandbox) -> Result { +pub(super) fn initialize_sandbox(u_sbox: UninitializedSandbox) -> Result { let max_guest_log_level = u_sbox.config.get_max_guest_log_level(); let (mut hshm, gshm) = u_sbox.mgr.build()?; @@ -86,7 +86,7 @@ pub(super) fn evolve_impl_multi_use(u_sbox: UninitializedSandbox) -> Result PathBuf { // Rust guest helpers // ============================================================================= -/// Builds a Rust guest MultiUseSandbox, applying `configure` to the builder. -pub fn build_rust_sandbox(configure: C) -> MultiUseSandbox +/// Builds a Rust guest Sandbox, applying `configure` to the builder. +pub fn build_rust_sandbox(configure: C) -> Sandbox where C: FnOnce(SandboxBuilder) -> SandboxBuilder, { @@ -31,24 +31,24 @@ where .unwrap() } -/// Creates a new Rust guest MultiUseSandbox. -pub fn new_rust_sandbox() -> MultiUseSandbox { +/// Creates a new Rust guest Sandbox. +pub fn new_rust_sandbox() -> Sandbox { build_rust_sandbox(|builder| builder) } -/// Runs a test with a Rust guest MultiUseSandbox. +/// Runs a test with a Rust guest Sandbox. pub fn with_rust_sandbox(f: F) where - F: FnOnce(MultiUseSandbox), + F: FnOnce(Sandbox), { f(new_rust_sandbox()); } -/// Runs a test with a Rust guest MultiUseSandbox built with `configure`. +/// Runs a test with a Rust guest Sandbox built with `configure`. pub fn with_rust_sandbox_from(configure: C, f: F) where C: FnOnce(SandboxBuilder) -> SandboxBuilder, - F: FnOnce(MultiUseSandbox), + F: FnOnce(Sandbox), { f(build_rust_sandbox(configure)); } @@ -75,8 +75,8 @@ where // C guest helpers // ============================================================================= -/// Builds a C guest MultiUseSandbox, applying `configure` to the builder. -pub fn build_c_sandbox(configure: C) -> MultiUseSandbox +/// Builds a C guest Sandbox, applying `configure` to the builder. +pub fn build_c_sandbox(configure: C) -> Sandbox where C: FnOnce(SandboxBuilder) -> SandboxBuilder, { @@ -85,19 +85,19 @@ where .unwrap() } -/// Runs a test with a C guest MultiUseSandbox. +/// Runs a test with a C guest Sandbox. pub fn with_c_sandbox(f: F) where - F: FnOnce(MultiUseSandbox), + F: FnOnce(Sandbox), { f(build_c_sandbox(|builder| builder)); } -/// Runs a test with a C guest MultiUseSandbox built with `configure`. +/// Runs a test with a C guest Sandbox built with `configure`. pub fn with_c_sandbox_from(configure: C, f: F) where C: FnOnce(SandboxBuilder) -> SandboxBuilder, - F: FnOnce(MultiUseSandbox), + F: FnOnce(Sandbox), { f(build_c_sandbox(configure)); } @@ -119,10 +119,10 @@ where } } -/// Runs a test with both Rust and C guest MultiUseSandboxes. +/// Runs a test with both Rust and C guest Sandboxes. pub fn with_all_sandboxes(f: F) where - F: Fn(MultiUseSandbox), + F: Fn(Sandbox), { with_all_guests(|path| { f(SandboxBuilder::from_file(path).build().unwrap()); diff --git a/src/hyperlight_host/tests/integration_test.rs b/src/hyperlight_host/tests/integration_test.rs index 25ba18ea7..f2b1b3ee1 100644 --- a/src/hyperlight_host/tests/integration_test.rs +++ b/src/hyperlight_host/tests/integration_test.rs @@ -9,7 +9,7 @@ use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::func::Bytes; use hyperlight_common::log_level::GuestLogFilter; use hyperlight_host::sandbox::SandboxConfiguration; -use hyperlight_host::{HyperlightError, MultiUseSandbox, SandboxBuilder, UninitializedSandbox}; +use hyperlight_host::{HyperlightError, Sandbox, SandboxBuilder, UninitializedSandbox}; use hyperlight_testing::simplelogger::{LOGGER, SimpleLogger}; use serial_test::serial; use tracing_core::LevelFilter; @@ -20,6 +20,26 @@ use crate::common::{ with_rust_sandbox, with_rust_sandbox_from, with_rust_uninit_sandbox_cfg, }; +/// The deprecated sandbox paths stay reachable from outside the crate. +/// +/// This has to live in an integration test. Paths that resolve inside +/// `hyperlight_host` prove nothing about what downstream crates can reach. +#[test] +#[allow(deprecated)] +fn deprecated_sandbox_paths_stay_public() { + use hyperlight_host::sandbox::initialized_multi_use as legacy; + + fn accepts_sandbox(_: Option) {} + fn accepts_status(_: Option) {} + fn accepts_finder(_: Option) {} + + accepts_sandbox(None::); + accepts_sandbox(None::); + accepts_sandbox(None::); + accepts_status(None::); + accepts_finder(None::); +} + // A host function cannot be interrupted, but we can at least make sure after requesting to interrupt a host call, // we don't re-enter the guest again once the host call is done #[test] @@ -916,7 +936,7 @@ fn c_guest_accesses_byte_chunks() { fn interrupt_random_kill_stress_test() { // Wrapper to hold a sandbox and its snapshot together struct SandboxWithSnapshot { - sandbox: MultiUseSandbox, + sandbox: Sandbox, snapshot: Arc, } @@ -1884,7 +1904,7 @@ fn non_pie_guest_hello_world() { let sandbox = UninitializedSandbox::new(hyperlight_host::GuestBinary::FilePath(path.into()), None) .unwrap(); - let mut multi_use_sandbox: MultiUseSandbox = sandbox.evolve().unwrap(); + let mut multi_use_sandbox: Sandbox = sandbox.evolve().unwrap(); let result: i32 = multi_use_sandbox .call("PrintOutput", "Hello from non-PIE guest!\n".to_string()) .unwrap(); diff --git a/src/hyperlight_host/tests/snapshot_goldens/checks.rs b/src/hyperlight_host/tests/snapshot_goldens/checks.rs index 06cb014bd..589144a8a 100644 --- a/src/hyperlight_host/tests/snapshot_goldens/checks.rs +++ b/src/hyperlight_host/tests/snapshot_goldens/checks.rs @@ -4,7 +4,7 @@ //! Functional checks against goldens loaded from the on-disk goldens //! directory. //! -//! Each check builds its own `MultiUseSandbox` from the golden with +//! Each check builds its own `Sandbox` from the golden with //! `GoldenTest::load_sandbox`, so checks are independent and one //! failure does not poison the next. See `docs/snapshot-versioning.md` //! for how to add a check. @@ -13,7 +13,7 @@ use std::path::Path; use std::sync::Arc; use hyperlight_host::sandbox::snapshot::{OciTag, Snapshot}; -use hyperlight_host::{HostFunctions, MultiUseSandbox, SandboxBuilder}; +use hyperlight_host::{HostFunctions, Sandbox, SandboxBuilder}; use crate::fixtures::{CALL_COUNTER_BUMP, HEAP_PATTERN_LEN, register_host_echo_fns}; @@ -41,7 +41,7 @@ impl<'a> GoldenTest<'a> { /// Load the golden into a fresh sandbox with the checks' host /// functions registered. - pub(crate) fn load_sandbox(&self) -> Result { + pub(crate) fn load_sandbox(&self) -> Result { let reference = OciTag::new(self.tag()) .map_err(|e| format!("invalid golden tag {}: {e}", self.tag()))?; let snap = Snapshot::checked_load(self.dir(), reference) diff --git a/src/hyperlight_host/tests/snapshot_goldens/fixtures.rs b/src/hyperlight_host/tests/snapshot_goldens/fixtures.rs index 7ad4cd3eb..45a792bee 100644 --- a/src/hyperlight_host/tests/snapshot_goldens/fixtures.rs +++ b/src/hyperlight_host/tests/snapshot_goldens/fixtures.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use hyperlight_host::func::Registerable; use hyperlight_host::sandbox::SandboxConfiguration; use hyperlight_host::sandbox::snapshot::Snapshot; -use hyperlight_host::{GuestBinary, MultiUseSandbox, UninitializedSandbox}; +use hyperlight_host::{GuestBinary, Sandbox, UninitializedSandbox}; use hyperlight_testing::simple_guest_as_pathbuf; /// Heap pattern length used by the golden. Small enough to @@ -55,7 +55,7 @@ pub(crate) fn generate() -> Arc { /// before snapshotting. Each call lands a specific bit of state /// (BSS, heap, host-call wiring) that one of the per-surface /// checks then asserts on after the golden is loaded. -fn run_canonical_calls(sbox: &mut MultiUseSandbox) { +fn run_canonical_calls(sbox: &mut Sandbox) { let bumped: i32 = sbox .call("AddToStatic", CALL_COUNTER_BUMP) .expect("AddToStatic"); diff --git a/src/hyperlight_host/tests/wit_test.rs b/src/hyperlight_host/tests/wit_test.rs index d19cfcbdb..bc79c95a8 100644 --- a/src/hyperlight_host/tests/wit_test.rs +++ b/src/hyperlight_host/tests/wit_test.rs @@ -6,7 +6,7 @@ use std::sync::{Arc, Mutex}; use hyperlight_common::component::{Negative, Positive}; use hyperlight_common::resource::BorrowedResourceGuard; -use hyperlight_host::{GuestBinary, MultiUseSandbox, UninitializedSandbox}; +use hyperlight_host::{GuestBinary, Sandbox, UninitializedSandbox}; use hyperlight_testing::{ c_simple_guest_as_pathbuf, simple_guest_as_pathbuf, wit_guest_as_pathbuf, }; @@ -275,11 +275,11 @@ impl test::wit::TestImports for Host { } } -fn sb() -> TestSandbox { +fn sb() -> TestSandbox { sb_from_guest(wit_guest_as_pathbuf()) } -fn sb_from_guest(path: PathBuf) -> TestSandbox { +fn sb_from_guest(path: PathBuf) -> TestSandbox { let guest_path = GuestBinary::FilePath(path); let uninit = UninitializedSandbox::new(guest_path, None).unwrap(); test::wit::Test::instantiate(uninit, Host {}).unwrap()