Repository navigation
nvx-rs: run NVX's layered sandbox root from a Rust PID 1 on the guest library #817
Description
Parent: #816. Builds on #535's guest library: bootstrap, root assembly and teardown (#674, #775, #776), descriptor-rooted mappings (#774) and the execution entry (#777, #778). Needs: #822's PR 5 (the export mount) and #860's PR 1 (the resolver bind). Delivers, with #818 and #591's docs: #558.
Goal. NVX's layered sandbox root runs from a Rust PID 1 that calls the guest library, in place of the shell init's two layered branches. Managed and one-shot sandboxes go through the same root and isolation operations as other adapters, in every format and upper that the library assembles. sandbox run keeps its exit status and console output. The blockless root and the other profiles keep the shell init.
Today (dev c5a0dd7):
guest/common/nvx-init-agent(shell) reads the root tokens, mounts one EROFSdistroand an ext4 scratch, assembles the overlay withmetacopy=on,xino=on, checks the workload account withawk, and tears the root down. It refuses a GPTdistro(line 197) andnvx_overlay_upper=ramfs(line 244), which the library already assembles.- A managed sandbox runs
nvx-managed-agent, which maps shares beneath the root after Ready and enters each execution throughnvx::guest::entry. - A one-shot sandbox enters its workload through
nvx-container-launchandnvx-container-enter, shell helpers that build the execution's/proc,/sysand a device-enabled/devtmpfs and change identity withsetpriv. It doesn't get the execution view that nvx-rs: enter guest executions with namespaces, a view, and an identity #777 gives managed executions. - The test adapter's guest already runs the library's bootstrap, assembly and teardown outside PID 1, in all four format and upper combinations, on every backend (
tests/runtime-adapter/tests/vm_layered.rs).
Scope:
- PID 1: a Rust init for the layered root, which the existing boot tokens select.
- NVX's
/initkeeps the boot prelude (pseudo-filesystems, module-loading lockdown, time, networking, DNS and ingress), and stillexecs the layered PID 1 at/sbin/nvx-init-agent. The test adapter's initramfs keeps replacing that file with its own PID 1 (runtime adapter: run cold sandboxes end to end on KVM, MSHV and WHP #822). - The Rust PID 1 supervises daemons, and reaps as the caller that owns reaping.
- NVX's
- Bootstrap and gates:
- The library's bootstrap: sibling agent and workload cgroups, every agent process in the agent cgroup, and user namespaces unavailable.
- A1's cold-time step before Ready.
- A check that port I/O permission is revoked before any workload stage is spawned.
- Root:
- The root tokens are parsed with the host renderer's rules (
nvx::protocol::root). - The root is assembled through
nvx::guest::root: an EROFS or GPTdistro, with the expected filesystem UUID or disk GUID from the token, over an ext4 scratch or a tmpfs. NVX keeps its overlay default and its journal policy. There is no probing fallback.
- The root tokens are parsed with the host renderer's rules (
- Identity and view:
- NVX keeps a non-root workload with no capabilities, in existing-account mode, with the generated machine ID and the
nvx_hostnameit has today. - When the policy allows DNS, the guest's resolver is bound over the root's
/etc/resolv.conf(nvx-rs: give a layered root's workloads the DNS server that their network policy allows #860's PR 1). The runtime's binds are removed before the root's teardown.
- NVX keeps a non-root workload with no capabilities, in existing-account mode, with the generated machine ID and the
- Lifecycles:
- Managed: the managed agent's session, its mappings and its executions, as today. The host export is mounted with
Root::mount_exportand its token parser (runtime adapter: run cold sandboxes end to end on KVM, MSHV and WHP #822's PR 5), in place of the shell'smount_host_export. - One-shot: one execution through
nvx::guest::entry, with the same console streams and exit status as today (NVX-SANDBOX-EXITandnvx-exit).
- Managed: the managed agent's session, its mappings and its executions, as today. The host export is mounted with
- Teardown: at shutdown, or after a fatal preparation failure, admission stops, executions settle, and the library unmounts in order. A failed unmount is reported. The VM ends with today's statuses.
- Removal: the layered branches of the shell init, and the shell helpers and build entries that only the layered root uses.
Behavior changes:
- A one-shot sandbox gets the execution view that managed executions have: a private procfs with masked paths, a read-only sysfs, an allowlisted
/dev, the root moved over/, and no inherited descriptors. - A GPT
distroand the tmpfs upper boot.nvx-rs sandboxrequests them in nvx-rs: GPT images, the RAM upper and protected paths innvx-rs sandbox#818. - Workloads resolve names through the gateway when the policy allows DNS.
Not in scope: the CLI's options and records (#818); NVXC v2 and Ready's identities (#821); whether layered launches keep choosing their lifecycle from nvx_lifecycle (#861); the blockless root and other PID 1 profiles; template mode for platform clones (the snapshot/restore workstream, #833).
Acceptance:
- NVX's managed and one-shot layered scenarios pass on KVM, MSHV and WHP, with only the intended changes above.
sandbox run's exit statuses and output keep their goldens. - With nvx-rs: GPT images, the RAM upper and protected paths in
nvx-rs sandbox#818, all four format and upper combinations boot throughsandbox run,provisionandstarton all three backends. Tests assert the mounted filesystem and upper, the expected identities, and no scratch in RAM mode. - Fault tests fail closed with the documented status, and start no workload, for each of these: malformed or duplicate root tokens, a wrong identity, a full upper, a failed assembly stage, and a busy root at teardown.
- Tests show that port I/O is revoked before a workload stage, and that the cold-time step runs before Ready.
- With DNS allowed, a workload resolves a name through the gateway; with it denied, the root keeps the image's resolver file.
- Guest binary and initramfs sizes are recorded; budgets belong to the performance workstream.
Carries over: #621's PR 5 and NVX's part of A3.5.
Activity