Skip to content

Commit d00dbbb

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

2 files changed

Lines changed: 359 additions & 4 deletions

File tree

src/hyperlight_host/src/sandbox/initialized_multi_use.rs

Lines changed: 199 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1194,14 +1194,15 @@ mod tests {
11941194

11951195
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
11961196
use hyperlight_testing::sandbox_sizes::{LARGE_HEAP_SIZE, MEDIUM_HEAP_SIZE, SMALL_HEAP_SIZE};
1197-
use hyperlight_testing::simple_guest_as_pathbuf;
1197+
use hyperlight_testing::{c_simple_guest_as_pathbuf, simple_guest_as_pathbuf};
11981198

11991199
use crate::func::host_functions::Registerable;
12001200
#[cfg(not(gdb))]
12011201
use crate::hypervisor::hyperlight_vm::test_support::VmOperation;
12021202
use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags, MemoryRegionType};
12031203
use crate::mem::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, SharedMemory as _};
12041204
use crate::sandbox::SandboxConfiguration;
1205+
use crate::sandbox::uninitialized::{GuestBlob, GuestEnvironment};
12051206
use crate::{
12061207
GuestBinary, HyperlightError, MultiUseSandbox, Result, SandboxStatus, UninitializedSandbox,
12071208
};
@@ -2256,6 +2257,203 @@ mod tests {
22562257
assert_eq!(target.mem_mgr.layout.heap_size(), 0x6000);
22572258
}
22582259

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

0 commit comments

Comments
 (0)