Skip to content

Commit 427ea34

Browse files
committed
Test cross-guest snapshot restore
Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent 638f96b commit 427ea34

2 files changed

Lines changed: 349 additions & 5 deletions

File tree

src/hyperlight_host/src/sandbox/initialized_multi_use.rs

Lines changed: 186 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,14 +1188,15 @@ mod tests {
11881188

11891189
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
11901190
use hyperlight_testing::sandbox_sizes::{LARGE_HEAP_SIZE, MEDIUM_HEAP_SIZE, SMALL_HEAP_SIZE};
1191-
use hyperlight_testing::simple_guest_as_pathbuf;
1191+
use hyperlight_testing::{c_simple_guest_as_pathbuf, simple_guest_as_pathbuf};
11921192

11931193
use crate::func::host_functions::Registerable;
11941194
#[cfg(not(gdb))]
11951195
use crate::hypervisor::hyperlight_vm::test_support::VmOperation;
11961196
use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags, MemoryRegionType};
11971197
use crate::mem::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, SharedMemory as _};
11981198
use crate::sandbox::SandboxConfiguration;
1199+
use crate::sandbox::uninitialized::{GuestBlob, GuestEnvironment};
11991200
use crate::{
12001201
GuestBinary, HyperlightError, MultiUseSandbox, Result, SandboxStatus, UninitializedSandbox,
12011202
};
@@ -2260,6 +2261,189 @@ mod tests {
22602261
assert_eq!(target.mem_mgr.layout.heap_size(), 0x6000);
22612262
}
22622263

2264+
#[test]
2265+
fn snapshot_restore_replaces_rust_guest_with_c_guest() {
2266+
let init_data = b"cross-layout-init-data";
2267+
let source_env = GuestEnvironment {
2268+
guest_binary: GuestBinary::FilePath(c_simple_guest_as_pathbuf()),
2269+
init_data: Some(GuestBlob {
2270+
data: init_data,
2271+
permissions: MemoryRegionFlags::READ | MemoryRegionFlags::WRITE,
2272+
}),
2273+
};
2274+
let mut source = UninitializedSandbox::new(source_env, None)
2275+
.unwrap()
2276+
.evolve()
2277+
.unwrap();
2278+
let mut target =
2279+
UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_as_pathbuf()), None)
2280+
.unwrap()
2281+
.evolve()
2282+
.unwrap();
2283+
2284+
assert_eq!(source.call::<i32>("StackAllocate", 256i32).unwrap(), 256);
2285+
assert_eq!(target.call::<i32>("AddToStatic", 17i32).unwrap(), 17);
2286+
target.set_pt_root_finder(Box::new(|_, _, root| vec![root]));
2287+
assert!(target.pt_root_finder.is_some());
2288+
2289+
assert_ne!(
2290+
source.mem_mgr.layout.code_size(),
2291+
target.mem_mgr.layout.code_size()
2292+
);
2293+
assert_ne!(
2294+
source.mem_mgr.layout.init_data_size(),
2295+
target.mem_mgr.layout.init_data_size()
2296+
);
2297+
assert_ne!(
2298+
source.mem_mgr.layout.init_data_permissions(),
2299+
target.mem_mgr.layout.init_data_permissions()
2300+
);
2301+
2302+
let snapshot = source.snapshot().unwrap();
2303+
target.restore(snapshot).unwrap();
2304+
assert!(target.pt_root_finder.is_none());
2305+
assert_eq!(target.call::<i32>("StackAllocate", 512i32).unwrap(), 512);
2306+
assert!(matches!(
2307+
target.call::<i32>("GetStatic", ()),
2308+
Err(HyperlightError::GuestError(
2309+
ErrorCode::GuestFunctionNotFound,
2310+
name
2311+
)) if name == "GetStatic"
2312+
));
2313+
}
2314+
2315+
#[test]
2316+
fn snapshot_restore_replaces_c_guest_with_rust_guest() {
2317+
let mut source =
2318+
UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_as_pathbuf()), None)
2319+
.unwrap()
2320+
.evolve()
2321+
.unwrap();
2322+
assert_eq!(source.call::<i32>("AddToStatic", 42i32).unwrap(), 42);
2323+
let snapshot = source.snapshot().unwrap();
2324+
2325+
let mut target =
2326+
UninitializedSandbox::new(GuestBinary::FilePath(c_simple_guest_as_pathbuf()), None)
2327+
.unwrap()
2328+
.evolve()
2329+
.unwrap();
2330+
assert_eq!(target.call::<i32>("StackAllocate", 256i32).unwrap(), 256);
2331+
2332+
target.restore(snapshot).unwrap();
2333+
assert_eq!(target.call::<i32>("GetStatic", ()).unwrap(), 42);
2334+
assert!(matches!(
2335+
target.call::<i32>("StackAllocate", 512i32),
2336+
Err(HyperlightError::GuestError(
2337+
ErrorCode::GuestFunctionNotFound,
2338+
name
2339+
)) if name == "StackAllocate"
2340+
));
2341+
}
2342+
2343+
#[test]
2344+
fn snapshot_restore_alternates_c_and_rust_guests() {
2345+
let mut c_source =
2346+
UninitializedSandbox::new(GuestBinary::FilePath(c_simple_guest_as_pathbuf()), None)
2347+
.unwrap()
2348+
.evolve()
2349+
.unwrap();
2350+
assert_eq!(c_source.call::<i32>("StackAllocate", 256i32).unwrap(), 256);
2351+
let c_snapshot = c_source.snapshot().unwrap();
2352+
2353+
let mut rust_source =
2354+
UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_as_pathbuf()), None)
2355+
.unwrap()
2356+
.evolve()
2357+
.unwrap();
2358+
rust_source.call::<i32>("AddToStatic", 42i32).unwrap();
2359+
let rust_snapshot = rust_source.snapshot().unwrap();
2360+
2361+
let mut target =
2362+
UninitializedSandbox::new(GuestBinary::FilePath(c_simple_guest_as_pathbuf()), None)
2363+
.unwrap()
2364+
.evolve()
2365+
.unwrap();
2366+
assert_eq!(target.call::<i32>("StackAllocate", 256i32).unwrap(), 256);
2367+
2368+
target.restore(rust_snapshot).unwrap();
2369+
assert_eq!(target.call::<i32>("GetStatic", ()).unwrap(), 42);
2370+
assert!(matches!(
2371+
target.call::<i32>("StackAllocate", 512i32),
2372+
Err(HyperlightError::GuestError(
2373+
ErrorCode::GuestFunctionNotFound,
2374+
name
2375+
)) if name == "StackAllocate"
2376+
));
2377+
2378+
target.restore(c_snapshot).unwrap();
2379+
assert_eq!(target.call::<i32>("StackAllocate", 512i32).unwrap(), 512);
2380+
assert!(matches!(
2381+
target.call::<i32>("GetStatic", ()),
2382+
Err(HyperlightError::GuestError(
2383+
ErrorCode::GuestFunctionNotFound,
2384+
name
2385+
)) if name == "GetStatic"
2386+
));
2387+
}
2388+
2389+
#[test]
2390+
fn snapshot_restore_keeps_target_host_function_implementation() {
2391+
let path = simple_guest_as_pathbuf();
2392+
let mut source = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap();
2393+
source
2394+
.register_host_function("Echo42", || Ok(1i64))
2395+
.unwrap();
2396+
let mut source = source.evolve().unwrap();
2397+
let snapshot = source.snapshot().unwrap();
2398+
2399+
let path = simple_guest_as_pathbuf();
2400+
let mut target = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap();
2401+
target
2402+
.register_host_function("Echo42", || Ok(42i64))
2403+
.unwrap();
2404+
let mut target = target.evolve().unwrap();
2405+
2406+
target.restore(snapshot).unwrap();
2407+
assert_eq!(
2408+
target
2409+
.call::<i64>(
2410+
"CallGivenParamlessHostFuncThatReturnsI64",
2411+
"Echo42".to_string(),
2412+
)
2413+
.unwrap(),
2414+
42
2415+
);
2416+
}
2417+
2418+
#[test]
2419+
fn snapshot_restore_recovers_poison_with_different_guest() {
2420+
let mut source =
2421+
UninitializedSandbox::new(GuestBinary::FilePath(c_simple_guest_as_pathbuf()), None)
2422+
.unwrap()
2423+
.evolve()
2424+
.unwrap();
2425+
let snapshot = source.snapshot().unwrap();
2426+
2427+
let path = simple_guest_as_pathbuf();
2428+
let mut target = UninitializedSandbox::new(GuestBinary::FilePath(path), None)
2429+
.unwrap()
2430+
.evolve()
2431+
.unwrap();
2432+
assert!(target.call::<()>("ExhaustHeap", ()).is_err());
2433+
assert!(target.status().is_poisoned());
2434+
2435+
target.restore(snapshot).unwrap();
2436+
assert!(!target.status().is_poisoned());
2437+
assert_eq!(target.call::<i32>("StackAllocate", 512i32).unwrap(), 512);
2438+
assert!(matches!(
2439+
target.call::<i32>("GetStatic", ()),
2440+
Err(HyperlightError::GuestError(
2441+
ErrorCode::GuestFunctionNotFound,
2442+
name
2443+
)) if name == "GetStatic"
2444+
));
2445+
}
2446+
22632447
/// Validation runs before any memory or vCPU mutation, so a
22642448
/// rejected `restore` leaves the target usable.
22652449
#[test]
@@ -2271,14 +2455,14 @@ mod tests {
22712455
.unwrap();
22722456
let mut source = source.evolve().unwrap();
22732457

2458+
let map_mem = allocate_guest_memory();
22742459
let path = simple_guest_as_pathbuf();
22752460
let mut target = UninitializedSandbox::new(GuestBinary::FilePath(path), None)
22762461
.unwrap()
22772462
.evolve()
22782463
.unwrap();
22792464

22802465
target.call::<i32>("AddToStatic", 5i32).unwrap();
2281-
let map_mem = allocate_guest_memory();
22822466
let guest_base = 0x200000000_usize;
22832467
let region = region_for_memory(&map_mem, guest_base, MemoryRegionFlags::READ);
22842468
// SAFETY: `map_mem` is page-aligned and outlives every use of `target`.

0 commit comments

Comments
 (0)