Repository navigation
nvx-rs: check guest-path containment with one function - #634
Open
Pedro Henrique Penna (ppenna) wants to merge 1 commit into
Open
Pedro Henrique Penna (ppenna) wants to merge 1 commit into
Pedro Henrique Penna (ppenna) wants to merge 1 commit into
Conversation
Four checks asked whether a guest path is a directory or lies below it, comparing whole components, so that /runner is not inside /run. filesystem::within answered it for the guest directories that a host mapping must not cover, and the sandbox's share checks wrote the same expression out three more times: validate_mount_target for the reserved mount targets, targets_overlap as an `inside` closure applied both ways, and validate_run_share_targets with a second copy of that closure and of targets_overlap's condition instead of a call to targets_overlap. - within is pub(crate), and its documentation states the rule, which its callers rely on. - validate_mount_target calls within for each reserved target. - targets_overlap is within applied in either direction. - validate_run_share_targets calls targets_overlap, as validate_mounts already does. The rule now has one definition, so the checks cannot drift apart, and each call names the rule that it applies. Each replaced expression is the body of the function that replaces it, or the disjunction of two such bodies, and none has side effects, so every check accepts and refuses the same targets, in the same order, with the same messages. The golden fixtures of the sandbox shares and options, sandbox.json and sandbox_options.json, pin those messages, and a new filesystem test pins the whole-component rule. A throwaway differential test compared the old expressions with within and targets_overlap on all 1,863,225 ordered pairs of the 1,365 strings of up to five characters from `/`, `a`, `.`, and `é`, and found no difference. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The refactor preserves the existing predicates, validation order, and diagnostics, with no unresolved findings.
No open issues 🎉
What changed in this PR
Centralizes guest-path containment checks in nvx-rs, removing duplicated logic while preserving validation behavior and diagnostics.
Changes:
- Reuses
withinandtargets_overlapacross filesystem and sandbox checks. - Documents and directly tests whole-component containment.
| File | Description |
|---|---|
nvx-rs/src/host/sandbox/options.rs |
Reuses targets_overlap for run-share validation. |
nvx-rs/src/host/sandbox/mount.rs |
Uses within for reserved targets and overlap checks. |
nvx-rs/src/host/filesystem.rs |
Makes within crate-visible and adds documentation and tests. |
Review effort: Balanced
This was referenced Oct 20, 2026
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.
Summary
Four checks ask whether a guest path is a directory or lies below it, comparing whole components, so that
/runneris not inside/run.filesystem::withinanswers that question for the guest directories that a host mapping must not cover, but the sandbox's share checks wrote the same expression out three more times:validate_mount_targetfor the reserved mount targets,targets_overlapas aninsideclosure applied both ways, andvalidate_run_share_targetswith a second copy of that closure and oftargets_overlap's condition. This change makeswithinvisible to the crate, and has the three checks call it, directly or throughtargets_overlap. The rule now has one definition, so the copies cannot drift apart, for example if one is "simplified" to a plainstarts_with, and each call names the rule that it applies.Changes
All of the code changes are in
nvx-rs/src/host/filesystem.rs,nvx-rs/src/host/sandbox/mount.rs, andnvx-rs/src/host/sandbox/options.rs.within(host::filesystem) is nowpub(crate)instead of private. Its documentation states the whole-component rule that its callers rely on. These sites now share it:filesystem::plan, forRESERVED_TARGETS, as before.sandbox::mount::validate_mount_target, for each ofRESERVED_MOUNT_TARGETS, in place of the expression that it spelled out.sandbox::mount::targets_overlap, which is nowwithin(left, right) || within(right, left), in place of itsinsideclosure.targets_overlap(host::sandbox::mount) is unchanged in signature and visibility. These sites now share it:validate_mounts, as before.sandbox::options::validate_run_share_targets, in place of its own copy of the closure and the condition.guest_paths_are_within_themselves_and_their_ancestors(new test infilesystem.rs) pins the rule directly. A path is within itself and its ancestors./runneris not within/run,/runis not within/run/nvx, and/srv/runis not within/run.Behavior
validate_mount_targetstill checks the reserved trees in order, after the form of the target and before the exact reservations.validate_run_share_targetsstill compares each target with the aggregate target and then with the earlier targets, and still names them as--mount targets {other} and {target} overlap; a share cannot hide another.withinstays private to the crate, andhost::filesystemandhost::sandboxare compiled under the same features, so nothing is added to the--no-default-featuresor guest builds. The public API, the protocol bytes, the golden fixtures, and the guest binaries' command lines, statuses, and output are all unchanged.tests/fixtures/sandbox.jsonandtests/fixtures/sandbox_options.jsonpin the messages ofvalidate_mount_target,validate_mounts, andvalidate_run_share_targets, including their seeded random corpora. The unit testsmount_target_validation_rejects_unsafe_and_reserved_targets,launch_rejects_invalid_share_sets, andrun_share_targets_bind_from_an_aggregatecover them as well.withinandtargets_overlapon all 1,863,225 ordered pairs of the 1,365 strings of up to five characters from/,a,., andé. Of these pairs, 4,551 overlap. The results were identical for every pair.Follow-ups
mainfunctions callsys::restore_sigpipe()and then returnExitStatus::from(run(&sys::args(), ...)).into(). Four of them pass the same three arguments:time,time_probe,ingress, andconsole_pending. A helper inguest/status.rsthat takes therunfunction could serve them all.device_io.rsandmanaged_agent/mod.rs, which hold two of the nine, are changed by open pull requests (nvx-rs: print the nvx-device-io result line once for both benchmarks #633 and nvx-rs: add a neutral guest spawn API and launch managed workloads through it #629), so this run left the helper to a later one.MountAccess::from_name,MountOwner::from_name, andMountKind::from_nameinsandbox/mount.rsdiffer only in their names and in the noun of their message,unsupported sandbox mount {mode|owner|kind} ...; choose A or B. A private generic helper could share them, keeping each message.sandbox/tests.rsandsandbox/mount/tests.rseach define the samepolicy(denied, allowed, writable)builder of aMountPolicy.tests/cli.rsrepeats its stop-and-deprovision loop in both Ctrl-C tests.Validation
4a6c3b6d21ccddbbf8f5c78d997adc3bb687b228(origin/devwhen the run started). nvx-rs: make the guest failure reporters return their CommandError #614 and a performance-baseline update have merged since; neither changes these files.d4aff861e52aecb73327f306a15fa71569244377, the tree of this pull request's commit58bd8756848477c75dd2491aa5c0e98e1d2c1dc0.v0.1.0-dev.3ddd1ea9e603withnvx.py download --hypervisor BACKEND. Its OpenVMM provenance isd0bdbed8f6e3b86271277dc22658109e2e633b2d, which matches the pinned gitlink.build-guest-binaries --outputandtest-guest-binaries --binaries(34 passed). The Alpine initramfs was then built withNVX_GUEST_BINARIES=… build-initramfs. The initramfs (54364e73…), its package manifest (2f04a9fa…), and its provenance (c8ae99f2…) were copied to the other two hosts with matching SHA-256 digests.nvx-rsCLI: each host rebuilt it from TREE withcargo build --release --locked --features cliand recorded its provenance withnvx.py record-nvx-rs-provenance, so the microVM scenarios ran this change rather than the release's binary.-D warnings(all features, and the library without default features), the--all-featuresand default tests, and rustdoc with-D warnings.checkfornvx-rsandaci_edge_sandboxes, on behalf of the WHP host, which has no 1.89 toolchain.aarch64-apple-darwincheck for both crates, on behalf of the KVM host, which lacks that target.test-aci-edge-sandboxestest-microvm(default suite)check-guest-binaries(320 passed); tests 876 passed, 2 ignoredunshare --useris denied)The macOS checks for the KVM host's steps and the MSRV checks for the WHP host's steps ran locally, as listed above.
test-microvmran the 35 scenarios of its default suite, 41 runs with the processor counts ofconsole-exitandsmp.Left to CI:
test-openvmm-unitandtest-openvmm.test-microvmscenarios that run only when named:smp-lapic,managed-exec-config, andsandbox-lifecycle.