Skip to content

nvx-rs: mount the host export as a source of a root's mappings - #864

Merged
Pedro Henrique Penna (ppenna) merged 2 commits into
devfrom
esaurez/822-pr05-export-mapping-source-20261023
Oct 25, 2026
Merged

Pedro Henrique Penna (ppenna) merged 2 commits into
devfrom
esaurez/822-pr05-export-mapping-source-20261023

Conversation

@esaurez

@esaurez Enrique Saurez (esaurez) commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Part of #822: PR 5 of 11, the export as a mapping source, in nvx::guest. It follows #822's PRs 1 to 4, #863, #867, #869, and #865, in that order, which have merged. This PR is rebased onto dev at 8c678005, #865's merge, and holds only its own two commits, which need nothing from those PRs.

A guest that maps host paths into a layered root from the host's mapping table needs the host export, the aggregate virtio-fs device that OpenVMM attaches for those paths, mounted outside the root. NVX's shell init mounts it for its own agent (mount_host_export in guest/common/nvx-init-agent), but a guest built on nvx::guest had no way to mount it as the source of Root::map. This is #822's one library addition.

Changes

nvx::protocol::export, a new module: HostExport::parse, a strict parser of the tokens that OpenVMM appends for an aggregate export.

  • All four tokens or none, each once and in its form: virtfs_dir=/run/nvx/hostfs/root (EXPORT_DIRECTORY), virtfs_tag= a name of letters, digits, _, and -, virtfs_mode=ro or rw (ExportMode), and virtfs_aggregate=1.
  • The checks of the shell's mount_host_export, including its refusal of nvx_share= tokens, which bind live shares.
  • Stricter than the shell where the shell is lenient: a repeated token, such as a second virtfs_aggregate=1, another aggregate value, or a token without a value is refused.
  • tests/fixtures/export-tokens.json holds its vectors.
  • nvx::host::filesystem::GUEST_EXPORT now names EXPORT_DIRECTORY, so that the host's plan and the guest's parser share the directory. Its value does not change.

Root::mount_export(tag, access), in nvx::guest::root:

  • mounts the export's device nosuid,nodev, read-only or read-write, at hostfs/root in the runtime directory, outside the root, below a hostfs directory that only root may enter (mode 0700, whatever the umask), as the shell does. A hostfs that is there already, such as one that an earlier root left, must be as private: owned by the process's effective user, with no permission for its group or others. Another is refused, and stays unchanged;
  • owns the mount, and unmounts it after the live shares and mappings at teardown;
  • returns the export's root, the SourceRoot for Root::map.

A refused tag creates and mounts nothing, and a root mounts one export. A later failure latches the root, as a share's does, and an assembly refuses a runtime directory where an export is still mounted. From<ExportMode> for Access gives the mount's access from the parsed mode.

NVX's own guest does not change, so the boot contract version stays. #817 can replace the shell's export mount with these, and #845's PR 3 mounts a clone's export with them.

Validation

At this head, b6849761, rebased onto dev at 8c678005 once #865 merged. The rebase applied without conflicts, and git range-diff shows both commits unchanged. Of their files, dev changed only nvx-rs/README.md, in rows that this PR does not touch. CI passed on this head, the KVM, MSHV, and WHP jobs included.

Windows, x86_64, at this head: nvx.py verify; nvx-rs fmt, Clippy in the three configurations, the tests in the three configurations, rustdoc, and the 1.89 MSRV check; tests/runtime-adapter in its protocol-only and host-only configurations: fmt, Clippy, the build, the tests, and the MSRV check; aci_edge_sandboxes fmt, Clippy, the tests, rustdoc, and the MSRV check; and scripts/check_markdown_links.py.

At the previous head, 1a46abac, on #865's branch:

Linux, x86_64:

  • nvx-rs: cargo fmt --check; Clippy with -D warnings, with all targets and features and for the library without default features; the tests with all features, with the default features, and of the library without default features; the bundled-artifacts test; rustdoc with -D warnings; the 1.89 MSRV check; and the aarch64-apple-darwin check.
  • The guest binaries: nvx.py check-guest-binaries, build-guest-binaries, and test-guest-binaries.
  • tests/runtime-adapter, in its protocol-only, host-only, and musl guest-only configurations: fmt, Clippy, the build, the tests, and the MSRV check.
  • aci_edge_sandboxes: fmt, Clippy, the tests, nvx.py test-agent-bundling, rustdoc, the MSRV check, and the macOS check.
  • scripts/check_markdown_links.py.

Windows, x86_64: nvx-rs fmt, Clippy, the tests in the three configurations, rustdoc, and the MSRV check.

WHP: the runtime adapter's VM scenarios, the ignored tests of tests/vm_layered.rs, tests/vm_restart.rs, and tests/vm_steps.rs, 30 in all, with cargo test --locked --features host -- --ignored.

The change adds no behavior that a VM shows by itself: the adapter mounts the export in VMs from #822's PR 6 on.

Copilot AI balanced review requested due to automatic review settings October 24, 2026 07:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The privileged export-mount path has an unresolved access-control concern and needs human review.

1 open issue
What changed in this PR

Adds the guest-library support needed for #822’s runtime adapter to use the host export as a mapping source, without changing NVX’s current guest behavior.

Changes:

  • Adds strict parsing of aggregate-export boot tokens and shares the export-directory constant with host planning.
  • Adds Root::mount_export, including mount ownership, failure latching, and teardown integration.
  • Adds parser fixtures, mount-lifecycle tests, and API documentation.
File Description
nvx-rs/​tests/​fixtures/​export-tokens.json Defines accepted and rejected export-token cases.
nvx-rs/​src/​protocol/​mod.rs Exposes and documents the export module.
nvx-rs/​src/​protocol/​export/​tests.rs Tests parsing, validation, and fixture coverage.
nvx-rs/​src/​protocol/​export.rs Defines export types, constants, and strict parsing.
nvx-rs/​src/​host/​filesystem.rs Reuses the protocol’s export-directory constant.
nvx-rs/​src/​guest/​root/​tests.rs Tests export mounting, mappings, refusals, and teardown.
nvx-rs/​src/​guest/​root/​share.rs Implements export mounting and private-directory preparation.
nvx-rs/​src/​guest/​root.rs Integrates export ownership, stale-mount checks, and documentation.
nvx-rs/​README.md Documents the new protocol and guest APIs.

Review effort: Balanced

Comment thread nvx-rs/src/guest/root/share.rs Outdated
@esaurez
Enrique Saurez (esaurez) marked this pull request as ready for review October 24, 2026 07:30
Copilot AI balanced review requested due to automatic review settings October 24, 2026 07:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Privileged filesystem isolation and mount-lifecycle changes warrant final human review despite no concrete blocking defect being identified.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@esaurez
Enrique Saurez (esaurez) changed the base branch from dev to esaurez/822-pr04-framing-20261023 October 24, 2026 17:32
@esaurez
Enrique Saurez (esaurez) force-pushed the esaurez/822-pr05-export-mapping-source-20261023 branch from fe1ed2d to 1a46aba Compare October 24, 2026 17:32
@esaurez
Enrique Saurez (esaurez) requested a balanced review from Copilot October 24, 2026 17:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No unresolved issues remain, and focused tests cover token validation, directory privacy, mount failures, and teardown ordering.

No open issues 🎉

Review effort: Balanced

Enrique Saurez and others added 2 commits October 25, 2026 10:25
A guest that maps host paths into a layered root from the host's mapping
table needs the host export, the aggregate virtio-fs device that OpenVMM
attaches for those paths, mounted outside the root. NVX's shell init
mounts it for its own agent, but a guest built on nvx::guest had no way
to mount it as the source of Root::map.

- nvx::protocol::export: HostExport::parse, a strict parser of the
  virtfs_dir=, virtfs_tag=, virtfs_mode=, and virtfs_aggregate=1 tokens
  that OpenVMM appends for the export: all four or none, each once and
  in its form, with the checks of the shell init's mount_host_export,
  and no nvx_share= token. EXPORT_DIRECTORY is the export's guest
  directory, which nvx::host::filesystem::GUEST_EXPORT now names, so
  the host's plan and the guest's parser share it.
  tests/fixtures/export-tokens.json holds the parser's cases.
- Root::mount_export mounts the export nosuid,nodev, read-only or
  read-write, at hostfs/root in the runtime directory, below a
  directory that only root may enter, owns the mount, unmounts it after
  the mappings at teardown, and returns its SourceRoot for Root::map.
  A root mounts one export; a failure latches the root, and an assembly
  refuses a runtime directory where an export is mounted already.

Part of #822.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3d31a6be-a0f8-4952-8667-0ebdc440d08d
Root::mount_export mounts the host export below hostfs in the runtime
directory, a directory that only root may enter, so that a workload reaches
host paths only through their mappings. A hostfs that was there already kept
its owner and mode, so one that another user owned, or that its group or
others could enter, would expose the export's children directly.

Accept a hostfs that is there already only if it is private to the
process's effective user: owned by that user, with no permission for its
group or others, as the one that an earlier root leaves. Refuse any other,
and leave it unchanged. NVX's shell init refuses any hostfs that is there
already, since it mounts the export once per boot, while a root may be
assembled again in a runtime directory where an earlier root left hostfs.

Part of #822

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3d31a6be-a0f8-4952-8667-0ebdc440d08d
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the esaurez/822-pr05-export-mapping-source-20261023 branch from 1a46aba to b684976 Compare October 25, 2026 15:36
Copilot AI balanced review requested due to automatic review settings October 25, 2026 15:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The security-sensitive export isolation and privileged mount lifecycle warrant final human review despite the focused regression coverage.

No open issues 🎉

Review effort: Balanced

@ppenna
Pedro Henrique Penna (ppenna) merged commit b69f40b into dev Oct 25, 2026
51 checks passed
@ppenna
Pedro Henrique Penna (ppenna) deleted the esaurez/822-pr05-export-mapping-source-20261023 branch October 25, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants