Repository navigation
openvmm: let a platform restore attach an aggregate to a dormant filesystem slot - #948
Open
Pedro Henrique Penna (ppenna) wants to merge 4 commits into
Open
Pedro Henrique Penna (ppenna) wants to merge 4 commits into
Pedro Henrique Penna (ppenna) wants to merge 4 commits into
Conversation
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The refused-restore integrity check omits the workspace, allowing token overwrites to go undetected; workspace comparison and a regression case for mutation during refusal are needed.
1 open issue
What changed in this PR
This PR integrates OpenVMM support for attaching aggregate filesystem exports to dormant slots during platform snapshot restore, addressing #540 and enabling clone exports planned in #857.
Changes:
- Advances the OpenVMM pin and documents platform-only aggregate attachment rules.
- Adds a default-suite scenario covering mixed directory/file exports, access policies, invalid attachments, and snapshot integrity.
- Adds unit coverage and rebalances the KVM, MSHV, and WHP test shards.
| File | Description |
|---|---|
scripts/test_microvm_tests.py |
Tests scenario arguments, refusals, guest reports, and integrity checks. |
scripts/nvx_tools/microvm_tests.py |
Adds the aggregate restore scenario and untiered-snapshot refusal check. |
scripts/nvx_tools/microvm_test_scripts/platform-aggregate-export.sh |
Checks guest mounts, child types, access policies, and bind mounts. |
scripts/nvx_tools/microvm_shards.json |
Includes the scenario and rebalances platform shards. |
doc/usage.md |
Lists the scenario’s sandbox-control guest requirement. |
doc/run.md |
Documents direct OpenVMM platform aggregate restores. |
doc/openvmm-upstream-roadmap.md |
Records the new pin and its two OpenVMM commits. |
doc/ci.md |
Describes aggregate restore coverage and rejection cases. |
Review effort: Balanced
Pin microsoft/openvmm#4775 at d7892ffa857d4b01aef0ee309969dda3e95fee44, two commits on d2338ea22, the previous pin, which is the head of feature/microvm/dev. A platform snapshot captured without a filesystem keeps the fixed virtio-fs slot dormant, and its restore could bind only one directory to it with --mount, although a cold boot attaches several host directories and files as the children of one aggregate. A template could therefore give its clones only part of what cold boots export. The first commit tests that the device takes a dormant slot's state, whose FUSE session the guest never initialized, into the device of an aggregate, which then saves the aggregate. The second lets the restore of a platform snapshot whose slot is dormant attach an aggregate with --mount-aggregate and its --mount-child options, and their --mount-deny, --mount-allow, --mount-write, and --mount-owner policy. The restore builds it with a cold boot's code, so it validates the children, the policy, and the owner as a cold boot does, and refuses what a cold boot refuses, before any vCPU runs. The slot's device and the captured command line, which names no filesystem, do not change, so OpenVMM exposes no layout and the guest learns of the export from its host. The dormant slot of a workload-start, instance-checkpoint, or untiered snapshot still binds only a --mount, a snapshot that predates the dormant slot binds nothing, and a snapshot that captured a filesystem still requires exactly that filesystem. Part of #540 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Record the two commits that the previous commit pins as positions 350 and 351 of the microVM chain, and move the NVX pin to d7892ffa8. Position 350 tests that the virtio-fs device takes the state of a dormant filesystem slot into the device of an aggregate. Position 351 lets a platform restore bind an aggregate to the slot that the snapshot left dormant, with its children, policy paths, and owner, validated as at a cold boot. They add behavior rather than fix a mapped commit, and position 351 changes the dormant-slot restore of PR18's position 113, which position 293 limited to one --mount when it added aggregates, so they stay unassigned, like positions 346-349. Note in the table's remarks that assigning them means revisiting that work. The pin is now 194 commits past the mapped tip. Positions 348 and 349 are no longer only a proposal: microsoft/openvmm#4769 merged them, so position 349, d2338ea22, is the head of feature/microvm/dev. Say so in the scope, and name microsoft/openvmm#4775 as the proposal of positions 350 and 351. Part of #540 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
OpenVMM now lets the restore of a platform snapshot bind an aggregate of host directories and files to the filesystem slot that the capture left dormant, and Run documented only that a snapshot captured without a mapping restores with one new --mount. Add a Platform filesystem exports section beside Platform NIC templates for direct OpenVMM restores. It shows a template's restore with --mount-aggregate, --mount-child options of directories and a file, and a --mount-deny path, and says that OpenVMM validates them as a cold boot's before any vCPU runs; that the slot's device and the guest's command line stay as captured, so the guest learns of the export from its host and mounts and binds it itself; and that other tiers, and snapshots captured with an export, keep their rules. The virtio-fs host mapping section's rule for nvx-rs run still holds, since nvx-rs run restores only snapshots without sandbox blocks, whose dormant slot takes no aggregate; say so, and link the new section. Part of #540 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
No test covered a platform restore that binds an aggregate to the filesystem slot that the capture left dormant, which OpenVMM refused until the pinned change. Add the platform-aggregate-export microVM scenario to the default suite. The scenario captures a platform snapshot with sandbox blocks and without a filesystem, and restores it with the aggregate of the filesystem-shares scenario: a read-write workspace and a read-only tool cache, each with a denied path, a read-write data directory whose root exposes only its allowed paths and whose notes alone are writable, and a read-only and a read-write file, each without its directory. The clone keeps its captured command line, which discovers the slot but names no filesystem, so its guest checks that no virtfs_ or nvx_share= token appeared, mounts the aggregate itself, and finds its five children in the read-only root that only root can enter. It checks each child's kind, mode, and policy through that root, and binds a directory and a file child where it needs them, and the host then requires exactly the writes that the policy admits. Before the guest runs, OpenVMM must refuse the restores whose aggregates a cold boot refuses: overlapping directories, a file inside a directory child, a directory as a file and a file as a directory, a repeated name, a policy path of a file child, one outside every child, and a relative one, and on a Windows host caller ownership. A refused restore must print none of the guest's lines, and no restore may change the snapshot or the shared trees. filesystem-snapshot also requires OpenVMM to refuse an aggregate for the dormant slot of its untiered snapshot, which still binds a --mount, since only a platform snapshot's dormant slot binds an aggregate. The scenario shares the filesystem-shares scenario's trees, so their creation moves into _create_shared_trees. It needs sandbox blocks, so it runs only with the Alpine sandbox-control guest, like platform-filesystem. In the default suite, it took 3.4 s on bare-metal KVM, 4.5 s on MSHV, and 9.1 s on WHP, so each backend's shards are planned again with its time, which CI's duration reports replace once CI has run it. It joins shard 2 on KVM and MSHV and shard 1 on WHP, and the planner moves command-line-limit on KVM, swaps platform-zero-fill and restore-memory on MSHV, and moves virtio-net on WHP. The default suite passed on each of those hosts. With the unpatched OpenVMM of the latest development release, d2338ea22, the capture succeeds and the clone's restore fails at "a dormant-slot snapshot can attach only a --mount on restore". Unit tests cover the guest's checks, the capture and the restore's arguments, each refusal's aggregate against the host's trees, the Windows-only refusal, a missing report, a guest failure, writes beyond the policy, and the snapshot's and trees' integrity. doc/ci.md describes the scenario, and doc/usage.md lists it among the scenarios that need the sandbox-control guest. Part of #540 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/issue-540-logical-commits-pr-guidelines
branch
from
October 28, 2026 02:06
7c9bcb6 to
4cf5d4a
Compare
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
The OpenVMM pin changes snapshot-restore admission and pre-vCPU filesystem-policy enforcement across KVM, MSHV, and WHP, requiring human confirmation of the restore boundary and exact-head platform CI evidence.
No open issues 🎉
1 resolved since last review
Review effort: Balanced
This branch has not been deployed
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 #540. Pins microsoft/openvmm#4775 at
d7892ffa857d4b01aef0ee309969dda3e95fee44, which lets the restore of a microVM platform snapshot attach an aggregate of host directories and files, with its access policy and owner, to the filesystem slot that the capture left dormant, validated as at a cold boot, before any vCPU runs. It adds a microVM scenario that restores one platform snapshot with such an aggregate on KVM, MSHV, and WHP.Based on
devatdce536f1d. microsoft/openvmm#4775 is two commits directly ond2338ea22, the head offeature/microvm/devand the revision thatdevpins, so this branch's four commits are its whole diff.Change
0ba6a0a8dopenvmmopenvmmd2338ea22→d7892ffa8: the two commits of microsoft/openvmm#4775e6a86186fdocdoc/openvmm-upstream-roadmap.md--mount; moves the NVX pin; and records that microsoft/openvmm#4769 merged positions 348 and 349 intofeature/microvm/devb11d20ce5docdoc/run.mdnvx-rs runrule still holds, links it4cf5d4afescriptsscripts/nvx_tools/microvm_tests.py,scripts/nvx_tools/microvm_test_scripts/platform-aggregate-export.sh,scripts/test_microvm_tests.py,scripts/nvx_tools/microvm_shards.json,doc/ci.md,doc/usage.mdplatform-aggregate-export;filesystem-snapshotalso refuses an aggregate on its untiered dormant slot; shards replannedOpenVMM changes
5ab722b73). A capture that leaves the slot dormant saves a dormant device state, without an attachment, a policy, objects, or an initialized FUSE session, which the device restores into any attached device. A new unit test checks it for an aggregate of a read-write directory and a read-only file, and that the device then saves the aggregate rather than the dormant slot. Only a test changes.d7892ffa8). At the restore of a platform snapshot whose slot is dormant,--mount-aggregatewith its--mount-childoptions, and their--mount-deny,--mount-allow,--mount-write, and--mount-ownerpolicy, attach an aggregate. The restore builds it with a cold boot's code, so it validates the children's kinds, modes, names, overlaps, and limits, the policy paths, and the owner as a cold boot does, and refuses what a cold boot refuses, before any vCPU runs. The slot's device keeps the stable ID, tag, MMIO range, interrupt, features, and queues that the snapshot recorded, and the guest keeps its captured command line, which names no filesystem: OpenVMM exposes no layout, and the guest learns of the export over its own control channel (nvx-rs: aggregate exports for clones #857). The restore contract still records the dormant slot. Only the platform tier changes: the dormant slot of a workload-start, instance-checkpoint, or untiered snapshot still binds only a--mount, a snapshot that predates the dormant slot binds nothing, and a snapshot that captured a filesystem still requires exactly that filesystem.--mount, and a restore without an attachment, behave as before.Tests
platform-aggregate-exportcaptures a platform snapshot with sandbox blocks and without a filesystem, and restores it with the aggregate of thefilesystem-sharesscenario: a read-write workspace and a read-only tool cache, each with a denied path, a read-write data directory whose root exposes only its allowed paths and whose notes alone are writable, and a read-only and a read-write file, each without its directory. The clone keeps its captured command line, so its guest checks that novirtfs_ornvx_share=token appeared, mounts the aggregate itself, finds the five children in the read-only root that only root can enter, checks each child's kind, mode, and policy, and binds a directory and a file child; the host then requires exactly the writes that the policy admits. Before the guest runs, OpenVMM must refuse the restores whose aggregates a cold boot refuses: overlapping directories, a file inside a directory child, a directory as a file and a file as a directory, a repeated name, a policy path of a file child, one outside every child, and a relative one, and on a Windows host caller ownership. A refused restore must print none of the guest's lines, and no restore may change the snapshot or the shared trees. It runs with the Alpine sandbox-control guest only, likeplatform-filesystem, and joins shard 2 on KVM and MSHV and shard 1 on WHP, each planned with the scenario's time in the bare-metal default suite below.filesystem-snapshotalso requires OpenVMM to refuse an aggregate for the dormant slot of its untiered snapshot, which still binds a--mount.--mount-owner; for snapshots without the dormant slot and of a single directory; and for the tier rule at every tier.Of #540's acceptance cases, the scenario covers a restore of a dormant slot with an aggregate of directory and file children, with mixed modes and policies, and the refusal of invalid aggregates, on every backend. Snapshots with a captured attachment keep their exact-match rules:
filesystem-sharesandfilesystem-snapshot, which restore captured aggregates and directories, pass unchanged in the default suite, as do OpenVMM's exact-match unit tests. A current OpenVMM cannot capture a snapshot without the dormant slot's version, so OpenVMM's unit tests cover that refusal, and the tier rule's unit test covers workload and instance snapshots, asfilesystem-snapshotdoes for an untiered one.Evidence
On the bare-metal hosts prometheus32 (Linux/KVM), prometheus30 (Linux/MSHV), and prometheus28 (Windows/WHP), each in a separate worktree at
02838f0aewith OpenVMM built there fromd7892ffa8and the guest of development releasev0.1.0-dev.1ee6489241a8:platform-aggregate-exportwith the fixfilesystem-snapshotwith the fixplatform-aggregate-exportin the default suiteWith that release's unpatched OpenVMM
d2338ea22on MSHV, the capture succeeds and the clone's restore fails ata dormant-slot snapshot can attach only a --mount on restore.Every clone reported
NVX-POST-RESTORE-OK: tier=platformandNVX-PLATFORM-AGGREGATE-OK, and every refusal failed before the guest ran, with:microVM filesystem host paths must not overlap(overlapping directories, and a file inside a directory child);invalid --mount-child 0, caused by the root's not being a regular file or a plain directory;invalid --mount-aggregate or --mount-child options, caused by a child name that is not unique;--mount-child 4 exposes the file ...;microVM denied path resolves outside the filesystem export roots;with --mount-aggregate, --mount-deny requires an absolute host path: secrets; on WHP,--mount-owner caller requires a Linux host; and forfilesystem-snapshot's untiered snapshot,--mount-aggregate on a dormant filesystem slot requires a platform snapshot.On prometheus28,
nvx-rs downloadfails withcurl: (43) A libcurl function was given a bad argumentunder the host's curl 8.8.0, so its guest artifacts came from the same release throughnvx-rs downloadon another Windows machine, with curl 8.21.0, and their SHA-256 digests matched after the copy.Equivalence and validation
02838f0ae, ondevatd77908efc, andplatform-aggregate-exportandfilesystem-snapshotagain at this head, where the scenario passes in 3.4 s on KVM, 4.0 s on MSHV, and 8.8 s on WHP. This head differs from02838f0aein the scenario only by the review fix: the integrity check after the refused restores also compares the workspace. It also differs in the shard partition, which the hosts' unsharded runs don't read and which is planned with their in-suite times, in the scenario commit's message, and in its base:devgained nvx-rs: capture templates into their store, and publish them #887 and tests: capture templates in VMs through the runtime adapter #933, which changenvx-rs's template store and the runtime adapter and none of this branch's files, andgit range-diffshows each rebase left the four commits' patches unchanged.cargo clippy --all-targetsandcargo doc --no-depsforvirtiofsandopenvmm_entry,cargo nextest run --profile agentfor both (339 passed), andcargo xtask fmt --fix(clean). The protocol vectors and CPU profiles thatnvx-rscopies are unchanged:openvmm_vectorsandopenvmm_cpu_profilespass with--ignored.nvx.py verify, the Markdown link check,ruff check,ruff format --check,pyrightfor Linux and Windows, andtest_microvm_tests.py,test_nvx_tools.py,test_module_diagrams.py, andtest_markdown_links.py(913 tests, 45 skipped). At321888b05, before the review fix and the latest rebases:compileall, the wholevalidate-nvxunittest list (1,359 tests, 53 skipped; the 18 shell cases oftest_setup_azure.py, which need a Linuxbash, fail the same way ondevhere),test_adversarial.py,test_hosts.py, and the CLI--helpchecks.shellcheckandshfmt, which run in Docker, although no checked shell script changed;check-nvx-rs, sincenvx-rsdoesn't change; and the OpenVMM VMM tests, which cannot reach an aggregate through the management RPC. CI runs all of them.Notes
doc/designisn't edited: draft doc: describe the managed layered root and platform-clone activation #591 rewrites those files, and nvx-rs: aggregate exports for clones #857, which this unblocks, makesnvx-rsattach a clone's aggregate at its restore.--restore-network-policyis.Exact NVX head submitted to CI:
4cf5d4afefe4bce1d0dd1b52ca354519ff9deb3b.