Repository navigation
Mount the live virtio-fs share inside sandbox workloads - #222
Closed
Pedro Henrique Penna (ppenna) wants to merge 2 commits into
Closed
Pedro Henrique Penna (ppenna) wants to merge 2 commits into
Pedro Henrique Penna (ppenna) wants to merge 2 commits into
Conversation
Promote the `openvmm` submodule from `c9f659c36` to `65cc1c2a5`, the head of nanvix/openvmm#97. That pull request adds `--mount-owner process|caller` for the microVM `--mount` attachment: - `lxutil: add scoped per-thread filesystem credentials` adds a guard that makes the calling thread perform filesystem operations exactly as another UID and GID. It switches the filesystem UID and GID, clears the supplementary groups, drops the effective capabilities, verifies every step, and restores the previous credentials when dropped. - `virtiofs: perform microVM HostFs requests as the guest caller` runs each FUSE request under that guard when `caller` is selected. Guest root is squashed to the export owner, and a request that cannot switch identity fails with `EPERM`. `process` remains the default. The sandbox agent and CLI changes that use the new option follow in the next commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 85d0240d-2f5e-4169-ae5d-540b7edc3b7b
In sandbox mode (`nvx_sandbox=1`), OpenVMM attaches the `--mount` share and passes `virtfs_dir`, `virtfs_tag`, and `virtfs_mode` on the kernel command line, but nothing ever mounts it. The initramfs hook runs only outside sandbox mode, and `nvx-init-agent` ignores the tokens. The capability-stripped workload cannot mount the share itself, so a host directory exported with `--mount` never reaches the sandbox (#216). Guest agent: - After assembling the overlay, and before it resolves the workload identity or starts any workload, `nvx-init-agent` mounts the `microvm` tag at `virtfs_dir` inside the container root, with the requested mode plus `nosuid,nodev`. The mount lives below the overlay, so it survives the workload's private mount namespace and `chroot`. The one-shot agent unmounts it before the overlay, and the managed agent inherits it for every exec. - The agent fails closed with `NVX-SANDBOX-ERROR` and status 125 if the tag or mode is unexpected, or if the target is not canonical. It also fails closed if the target is `/etc`, `/etc/machine-id`, or lies under `/proc`, `/sys`, `/dev`, or `/.nvx-agent`, all of which the container launcher manages or rewrites. The same applies when a component of the target in the image is a symbolic link or a non-directory, or when the mount fails. Components are checked and created one at a time before any workload exists, so an image symlink cannot redirect the mount outside the container root. Missing components are created as root-owned `0755` directories in scratch. - Without `--mount`, sandbox behavior is unchanged. CLI: - `sandbox run` and `sandbox provision` accept `--mount`, `--mount-deny`, and `--mount-owner {process,caller}`. The defaults are `caller` on Linux, so workload-created files are owned by the export owner when the workload identity owns the export, and `process` on Windows. Managed state records the share with an absolute export root. Configurations provisioned before this change still load without a share. - The launch contract rejects the reserved targets before boot, and counts the bootstrap tokens that OpenVMM appends against the sandbox's 1024-byte command-line budget. - `run` forwards an optional `--mount-owner`. Tests: - A new `sandbox-filesystem` microVM scenario boots the real sandbox agent over the Ubuntu EROFS layer. It shares `/workspace` read-write, hides `secrets/` with `--mount-deny`, and verifies what the issue asks for. The workload sees a host file. Its writes, nested directory, and `chmod` appear on the host while it still runs, with no copy-back. A host edit made during the run is visible to the workload. The denied path is absent. The outcome report records a clean virtio-fs teardown. - On Linux the workload identity owns the export and the share uses `--mount-owner caller`, so the scenario also checks the host owner of every file the workload creates. When the tests run as root they export a dedicated owner, and the scenario formats its scratch image with an upper `/etc/passwd` that defines that identity. - The scenario then verifies that a read-only share rejects workload writes with `EROFS`, and that the agent rejects a reserved target and a target that traverses the image's `/bin` symlink before any workload starts. - Unit tests cover the launch contract, CLI forwarding and validation, managed-state round-tripping, and the scenario's command construction and failure handling. Documentation: - `doc/run.md` documents the share's caching, the fact that host files are shown as-is with `--mount-deny` for credentials, the unchanged egress policy, the single-share contract, `ENOTSUP` for guest symlink creation, host ownership with `--mount-owner`, and the sandbox mount behavior. - `doc/design/current-limits.md`, the sandbox design, validation, and usage references follow. - Runner provisioning installs `e2fsprogs` for the scenario's scratch image. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 85d0240d-2f5e-4169-ae5d-540b7edc3b7b
Copilot started reviewing on behalf of
Pedro Henrique Penna (ppenna)
September 27, 2026 15:39
View session
Contributor
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
It combines guest mount isolation with an unmerged security-sensitive OpenVMM credential-switching change whose exact-head checks remain in progress.
Review effort: Balanced
Findings: None
What changed in this PR
Enables live virtio-fs shares inside sandbox workloads, including caller-based host ownership, validation, lifecycle persistence, documentation, and cross-platform tests.
Changes:
- Mounts validated shares inside the sandbox root with fail-closed behavior.
- Adds CLI/state support for mount denial and ownership policy.
- Adds end-to-end filesystem scenarios and required Linux tooling.
| File | Description |
|---|---|
doc/design/current-limits.md |
Documents remaining virtio-fs limitations. |
doc/design/sandbox-filesystem-and-agent-architecture.md |
Updates sandbox mount architecture. |
doc/design/validation.md |
Documents live-share coverage. |
doc/run.md |
Explains ownership, security, and sandbox usage. |
doc/usage.md |
Adds CLI options and test prerequisites. |
guest/common/init |
Clarifies sandbox-specific mounting. |
guest/common/nvx-init-agent |
Validates, mounts, and unmounts sandbox shares. |
openvmm |
Repins OpenVMM for caller-owned requests. |
scripts/nvx.py |
Adds mount options and forwarding. |
scripts/nvx_tools/microvm_test_scripts/sandbox-filesystem-read-only.sh.in |
Tests read-only enforcement. |
scripts/nvx_tools/microvm_test_scripts/sandbox-filesystem.sh.in |
Exercises live read-write sharing. |
scripts/nvx_tools/microvm_tests.py |
Implements the end-to-end scenario. |
scripts/nvx_tools/sandbox.py |
Defines and validates the mount contract. |
scripts/nvx_tools/sandbox_lifecycle.py |
Persists mounts in managed state. |
scripts/setup/README.md |
Documents the new tooling prerequisite. |
scripts/setup/setup-linux-mshv.sh |
Installs e2fsprogs on MSHV hosts. |
scripts/setup/setup-linux-runner.sh |
Installs e2fsprogs on Linux runners. |
scripts/test_microvm_tests.py |
Tests scenario orchestration and failures. |
scripts/test_nvx_tools.py |
Tests CLI, validation, and state handling. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Pedro Henrique Penna (ppenna)
deleted the
fix/sandbox-virtiofs-mount
branch
September 28, 2026 16:48
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.
Fixes #216.
In sandbox mode (
nvx_sandbox=1), OpenVMM attaches the--mountshare and passesvirtfs_dir,virtfs_tag, andvirtfs_modeon the kernel command line, but nothing ever mounted it. The initramfs hook runs only outside sandbox mode, andnvx-init-agentignored the tokens. The capability-stripped workload cannot mount the share itself. This PR mounts the share inside the workload root, and makes files that the workload creates owned by the host user who owns the export.Commits
c9f659c36→65cc1c2a5, the head of virtiofs: perform microVM HostFs requests as the guest caller nanvix/openvmm#97 (open), which adds--mount-owner process|caller.callermode, each FUSE request runs as the guest caller's UID and GID. The worker thread's supplementary groups and effective capabilities are dropped for the request.EPERM.processstays the default.Guest agent (
guest/common/nvx-init-agent)microvmatvirtfs_dirinside$rootfs, using the requested mode plusnosuid,nodev. The mount lives below the overlay, so it survives--make-rprivate,unshare --mount, andchroot. The one-shot agent unmounts it before the overlay, and the managed agent inherits it for every exec.NVX-SANDBOX-ERRORand status 125 on any of the following:/etcor/etc/machine-id, or a path under/proc,/sys,/dev, or/.nvx-agent, since the launcher manages or rewrites all of these;--mount, behavior is unchanged.CLI
nvx.py sandbox run|provisiongains--mount,--mount-deny, and--mount-owner {process,caller}. The default iscalleron Linux andprocesson Windows.nvx.py runforwards an optional--mount-owner.Tests
A new
sandbox-filesystemmicroVM scenario boots the real sandbox agent over the Ubuntu EROFS layer with--mount /workspace,<dir>,rw --mount-deny <dir>/secretsand covers the issue's acceptance criteria:chmod, appear on the host while the VM is still running, with no copy-back;successwithvirtiofs_released: true;roshare rejects writes withEROFS;/dev/...) and a target through the image's/binsymlink before any workload starts.On Linux, the workload identity owns the export and the share uses
caller, so the scenario also asserts the host owner of every file the workload creates. When run as root, it exports a dedicated12345:12345owner. The scenario formats its scratch image withmkfs.ext4 -dto define that identity, so runner provisioning now installse2fsprogs. On Windows, it copiesbuild/ubuntu-smoke-scratch.ext4.Unit tests cover the launch contract, CLI forwarding and validation, state round-tripping, and the scenario's command construction and failure paths.
Answers to the questions in #216
doc/run.md. By default OpenVMM performs requests as its own identity. With--mount-owner caller, workload-created files are owned by the workload identity; choosing the identity that owns the export, as AWF does with 1001, makes them owned by that host user. Caller mode requires OpenVMM to run as the export owner, or to holdCAP_SETUIDandCAP_SETGID.--mount-denyfor secrets (option a).microvmslot, with a single access mode. A second share, such as a read-only tool cache next to a read-write workspace, needs a new ABI version. Documented indoc/design/current-limits.md.ENOTSUP. Link-creating tools such asnpm cimust run in scratch. Left for a follow-up, and documented as a current limit.Validation
Validated on baremetal hosts with the pinned OpenVMM
65cc1c2a5and the NVX tree222787f. The current head450c548differs from that tree only by the doc-only #220 change todoc/usage.mdfrom the rebase ontodev.test-openvmm-unittest-openvmmtest-microvm(full, incl.sandbox-filesystem)sudo):lxutilcredential tests and thevirtiofsidentity tests pass as root, including the loss ofCAP_SETFCAPfor a file that the switched identity owns;sandbox-filesystempasses with a root OpenVMM switching every request to the12345:12345export owner.ruff check/format,pyrightfor Linux and Windows, all NVX unit suites, the pinnedshellcheck/shfmt, andnvx.py verify. On the OpenVMM side,clippy -D warningson Linux and Windows,rustdoc -D warnings, andxtask fmt.A new
v0.1.0-dev.*release will come from thedevpush after merge.