Repository navigation
Add opt-in native-host image-backed edge lifecycle - #418
Draft
Enrique Saurez (esaurez) wants to merge 5 commits into
Draft
Enrique Saurez (esaurez) wants to merge 5 commits into
Enrique Saurez (esaurez) wants to merge 5 commits into
Conversation
Load a separately supplied, caller-approved native host library for scratchless image-backed provision/start/exec/stop/deprovision. Keep the direct backend as default, isolate persisted state, fence unsupported capabilities, and pin the RAM-overlay OpenVMM change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bound guest-session disposal by each operation deadline, preserve zero as an unbounded command timeout while rejecting sub-second precision, keep native-only files outside direct-backend cleanup, and validate both derived Unix socket paths before loading the library. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Show a concrete WHP invocation, the separately supplied artifacts and trust requirement, and the unverified MSHV path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
OpenVMM serves one boot-console client at a time and retains guest output while none is connected. The native backend keyed its console listener by sandbox only, so a restart after an OpenVMM crash reused the finished listener of the crashed launch; with no listener, a verbose guest stalled until start timed out. A second backend instance that reattached to a running guest could not connect while the first one held the console, and stop then failed after the guest had already stopped. Key listeners by the OpenVMM process identity and retire stale ones before a launch. A listener that finds the console held elsewhere waits, without the start deadline, to take it over and ends quietly when OpenVMM exits; a reset after OpenVMM exits ends the log. Stop and deprovision report capture failures as consoleError metadata instead of failing. Extend the opt-in WHP suite with exec semantics, lifecycle errors and restarts, reattachment from a new backend, a crashed guest, a guest that outlives the process that started it, starts killed at several points, parallel sandboxes, and concurrent commands. List OpenVMM processes in a way that fails loudly, so the leak checks cannot pass vacuously. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Hash the image once when it is registered, or record a digest that the caller already verified, and refer to it by content ID. Provision and start compare cheap file seals instead of hashing again, and fail closed when a file changed. Hash OpenVMM, the kernel, and the initramfs once per backend, optionally against approved digests, and keep full re-hashing as an opt-in diagnostic. Starts now cost about the guest boot time. Windows seals omit the change time: writers can set it, and the system updates it when it caches a file hash in an extended attribute, which failed an unchanged OpenVMM executable closed during testing. Claim the OpenVMM log before a native launch. OpenVMM inherits the claim, so recovery can clear an interrupted start that recorded no process identity once nothing holds the log, instead of leaving the sandbox unusable. Markers of the default backend are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Stop deadlines can be exceeded, binary output is not preserved, and failed example startup can leak OpenVMM.
Review effort: Balanced
Findings: 3
Open (3)
What changed in this PR
Adds an opt-in image-backed nvxhost lifecycle backend while preserving direct OpenVMM as the default.
Changes:
- Adds native-library bindings and ttrpc lifecycle operations.
- Adds content-addressed image registration, artifact sealing, and crash recovery.
- Adds documentation, an example, and native guest tests.
| File | Description |
|---|---|
aci_edge_sandboxes/Cargo.toml |
Defines the feature, dependencies, and example. |
aci_edge_sandboxes/Cargo.lock |
Locks new dependencies. |
aci_edge_sandboxes/README.md |
Documents configuration, trust, and lifecycle behavior. |
aci_edge_sandboxes/examples/nvxhost_lifecycle.rs |
Demonstrates native lifecycle usage. |
aci_edge_sandboxes/src/client.rs |
Adds the client constructor. |
aci_edge_sandboxes/src/lib.rs |
Gates the native binding module. |
aci_edge_sandboxes/src/nvxhost.rs |
Implements the checked native ABI and ttrpc transport. |
aci_edge_sandboxes/src/openvmm/config.rs |
Generalizes Unix socket-path validation. |
aci_edge_sandboxes/src/openvmm/images.rs |
Implements image registration and file sealing. |
aci_edge_sandboxes/src/openvmm/launch.rs |
Updates state fixtures. |
aci_edge_sandboxes/src/openvmm/mod.rs |
Exports the backend and extends launch recovery. |
aci_edge_sandboxes/src/openvmm/native.rs |
Implements native lifecycle operations. |
aci_edge_sandboxes/src/openvmm/platform/linux.rs |
Adds Linux seals and launch-log claims. |
aci_edge_sandboxes/src/openvmm/platform/mod.rs |
Defines portable file seals. |
aci_edge_sandboxes/src/openvmm/platform/other.rs |
Adds unsupported-platform stubs. |
aci_edge_sandboxes/src/openvmm/platform/windows.rs |
Adds Windows seals and launch-log claims. |
aci_edge_sandboxes/src/openvmm/state.rs |
Adds backend-aware native state. |
aci_edge_sandboxes/tests/nvxhost_guest.rs |
Adds ignored guest lifecycle tests. |
openvmm |
Pins the required scratchless-overlay revision. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+100
to
+115
| let stopped = succeeded.then(|| client.stop(&id)); | ||
| let deprovisioned = if stopped.as_ref().is_none_or(Result::is_ok) { | ||
| Some(client.deprovision(&id)) | ||
| } else { | ||
| None | ||
| }; | ||
| let mut failures = Vec::new(); | ||
| if let Err(error) = &executed { | ||
| failures.push(format!("guest lifecycle: {error}")); | ||
| } | ||
| if let Some(Err(error)) = &stopped { | ||
| failures.push(format!("stop: {error}")); | ||
| } | ||
| if let Some(Err(error)) = &deprovisioned { | ||
| failures.push(format!("deprovision: {error}")); | ||
| } |
Comment on lines
+258
to
+261
| #[prost(string, tag = "2")] | ||
| stdout: String, | ||
| #[prost(string, tag = "3")] | ||
| stderr: String, |
Comment on lines
+1051
to
+1054
| let remaining = deadline.saturating_duration_since(Instant::now()); | ||
| let mut session = self.connect(&runtime, &capability, remaining)?; | ||
| let grace_period_milliseconds = i64::try_from(remaining.as_millis()) | ||
| .map_err(|_| Error::backend_error("guest shutdown grace period is too long"))?; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Replaces #395, which carried this change on a historical base that predates OpenVMM's time ABI and CPU profiles. This PR rebases it onto
dev; see "Changes since #395".Summary
nvxhostbackend to the edge sandbox crate. The caller supplies OpenVMM, a compatible kernel/initramfs and read-only GPT image, an absolute native-library path, and an independently approved SHA-256. The loader verifies ABI v1 and the required scratchless-launch and same-descriptor peer-check exports before use.<state_root>/nvxhost/, own the OpenVMM process and guest boot console, and implement provision/start/exec/guest logs/stop/deprovision through the native ttrpc channel.consoleErrormetadata instead of failing.sha256:<hex>). Registration hashes an image once, or records a digest that the caller's own policy verified; provision and start compare cheap file seals instead of hashing again and fail closed when a file changed. OpenVMM, the kernel, and the initramfs are hashed once per backend, optionally against approved digests. Hashing again before every start remains an opt-in diagnostic.register_image,images,verify_image, andunregister_imagemanage registrations; unregistering refuses while a provisioned sandbox uses the image.--image-sha256optionally requires the image digest.Dependencies
devpins. This branch pins4744ee7ca52fa3c9265402db17f98f6c31ac3da7.nolapic_timerto RAM-overlay guests, which must tick on their LAPIC timer under the time ABI.Changes since #395
dev'slock_and_load, which the native backend shares, instead of its own copy.nvxhostfeature no longer renames itssha2dependency. Cargo refused the renamed copy beside thebundledbuild dependency, so--all-features, which the crate's CI checks use, failed to build.backend_erroron a host that no built-in CPU profile serves.Validation
cargo test --all-featuresand Clippy with-D warningson all targets with--all-features, on Windows with Rust 1.93 (135, 137, 139, 139, and 140 unit tests).5b0a315), on Windows and on Linux with Rust 1.93: the crate's CI checks, which are fmt, Clippy with--all-featuresand with--no-default-features, tests with--all-featuresand with default features, docs with-D warnings,cargo +1.89 check, and, on Linux, the macOS build check. The pinned library test passes against freshly builtnvxhost.dllandlibnvxhost.so.--release --test-threads=1, each checking that no OpenVMM process outlives its sandbox, withdev's Linux 6.18.38 kernel:amd.milan.v1serves: all pass, in about 100 s, and again with a host profile;Notes
NvxHostConfigis#[non_exhaustive]: construct it withNvxHostConfig::newand its builder methods.