A read-only map is mounted read-only in the guest and follows the host's files - #1045
Conversation
A --map HOST:GUEST:ro volume was mounted in the guest like a read-write one: writable, and with FUSE_WRITEBACK_CACHE unless the VM-wide FCVM_NO_WRITEBACK_CACHE switch was set. VolumeMount.read_only reached fc-agent in the boot plan and was used only for podman's -v ...:ro. With the writeback cache the guest kernel keeps the size and mtime it first cached for a regular file and drops the server's. A file the host rewrote longer in place was read cut off at the old length (8 of 92 bytes in a running VM, 8 of 134 in a clone restored from a snapshot taken before the rewrite). One rewritten shorter kept its old length, padded with zero bytes. With --portable-volumes a file replaced by rename kept its old size and mtime in the clone (#1041). A write from the guest OS (fcvm exec --vm) succeeded and changed the host directory; only the container's bind mount was read-only (#1042). What changes: - fuse_pipe::MountSettings::for_volume(read_only, no_writeback_cache) is the one decision. A read-only volume is mounted with MS_RDONLY and never asks for FUSE_WRITEBACK_CACHE, whatever the VM-wide switch says. A read-write volume is mounted as before. The fields are private, so no other combination can be built. - fuse-pipe's mount API takes the settings as an argument: MountConfig::new, mount_vsock, mount_vsock_with_readers, mount_vsock_with_options, mount_vsock_with_reconnect and the FuseClient constructors. The Unix socket path and the vsock path share one session setup (mount_fuse_session), so a local mount is made by the code the guest runs. FuseClient::init no longer reads FCVM_NO_WRITEBACK_CACHE itself. - fc-agent passes each volume's read_only to the mount and mounts volumes in groups, an outer volume before a volume inside it. Every mount used to be started at once in plan order, and whether an outer mount covered an inner one was a race between their threads. - fcvm podman run refuses, before boot, a mount point (another --map, or a --disk, --disk-dir or --nfs) that lies inside a read-only map and is not already a directory of that map's host directory. fc-agent cannot create it in a read-only mount. The error names both arguments. There is no fallback to a read-write mount. - README.md and DESIGN.md say what :ro means in the guest, what the host may change under a read-write map, and what a snapshot keeps. DESIGN.md said snapshots are disabled with --map volumes, which is no longer true; that paragraph is replaced. The TODO in src/volume/mod.rs is replaced with what is true and a pointer to #1042. Plain volumes and --portable-volumes go through the same guest mount. Only the host's server differs. Snapshots. The mounts live in the guest's memory, so a snapshot made by an older fc-agent keeps its old mounts until it is made again. The snapshot cache key already separates old from new: it hashes FirecrackerConfig.boot_source.initrd_path, and the initrd is named after the hash of the fc-agent binary (fc-agent-bfcd8a448162.initrd before, fc-agent-f214cb9799e7.initrd after, on the host that ran the tests). No key ingredient is added. Why no test caught it. test_remap_fs_host_file_changes and test_remap_fs_snapshot_file_replace each replace a file with one of the same length (version-1 and version-2, original-v1 and replaced-v2), so a size the guest never refreshed still fit the new content. No test wrote to a :ro map from the guest OS or read the guest's mount table. Red, on f7fe35c plus tests/test_read_only_map.rs: make test-all FILTER="-p fcvm --test test_read_only_map" Summary [ 102.022s] 3 tests run: 0 passed, 3 failed, 0 skipped test_read_only_map_follows_host_in_vm_and_clone running VM, 10s after the host changed the files: grows.txt: host size=92 read 92 bytes; guest size=8 read 8 bytes shrinks.txt: host size=20; guest size=200 read 200 bytes starting "s1:.................\0\0\0\0" clone restored from a snapshot taken before the host changed them again: grows.txt: host size=134; guest size=8 read 8 bytes shrinks.txt: host size=5; guest size=200 read 200 bytes replaced.txt: host size=301; guest size=57, with the mtime of the file it replaced test_read_only_map_refuses_guest_writes the guest's mount table has /mnt/ro as rw,relatime (superblock rw,user_id=0,group_id=0,default_permissions,allow_other), not ro creating a file from the guest OS did not fail with EROFS: "status=0" the host directory holds ["created-by-guest", "existing.txt"] existing.txt on the host now reads "overwritten by the guest\n" test_map_inside_read_only_map_is_mounted_over_it try 1: the outer map is writable from the guest OS: "status=0" try 2: /mnt/outer/inner in the guest OS does not list the inner map's one file: "under-the-inner-map.txt\nstatus=0" Red, with the new API in place and its three decisions returning what f7fe35c does (for_volume ignoring read_only, one mount group, no check of mount points): make test-unit FILTER="-E 'test(a_read_only_volume_is_mounted_read_only_and_without_the_writeback_cache) | test(only_a_read_only_volume_adds_the_ro_mount_option) | binary(test_read_only_mount) | test(a_volume_inside_another_is_mounted_after_it) | test(a_mount_point_missing_from_a_read_only_map_fails_and_names_both_maps) | test(only_a_read_only_innermost_map_needs_the_mount_point_on_the_host)'" Summary [ 25.225s] 8 tests run: 1 passed, 7 failed, 1384 skipped The pass is the fixture's own read-write mount test. The failures: a_read_only_volume_is_mounted_read_only_and_without_the_writeback_cache volume read_only=true, VM-wide no_writeback_cache=false: left: (false, true) right: (true, false) only_a_read_only_volume_adds_the_ro_mount_option left: [FSName("fuse-pipe"), Suid, Dev, DefaultPermissions] right: [FSName("fuse-pipe"), Suid, Dev, DefaultPermissions, RO] a_read_only_mount_follows_a_file_rewritten_longer_in_place left: (8, SystemTime { tv_sec: 1000000000, tv_nsec: 0 }, "xxxxxxxx") right: (92, <the rewrite's mtime>, <92 bytes>) a_read_only_mount_refuses_writes_with_erofs the mount table has it as rw,nosuid,nodev,relatime, not ro creating a file did not fail with EROFS: Ok(()) a_volume_inside_another_is_mounted_after_it the groups ["/a", "/a/b"] are mounted in left: [[0, 1]] right: [[0], [1]] a_mount_point_missing_from_a_read_only_map_fails_and_names_both_maps a mount point the read-only outer map does not have was accepted only_a_read_only_innermost_map_needs_the_mount_point_on_the_host --disk-dir x:/a/disk with 1 map(s): Ok(()) Green: the same make test-unit FILTER: Summary [ 6.110s] 8 tests run: 8 passed, 1384 skipped make test-all FILTER="-p fcvm --test test_read_only_map" Summary [ 44.030s] 3 tests run: 3 passed, 0 skipped make build: exit 0 make test-unit Summary [ 72.551s] 1392 tests run: 1392 passed (1 slow, 2 flaky), 0 skipped The two flaky tests are in src/uffd/server.rs, which this change does not touch: a_fault_parked_during_replay_resolves_while_the_balloon_ keeps_inflating and faults_served_while_the_balloon_keeps_inflating_ resolve_far_inside_the_bound. Each measured a fault blocked for 375 ms and 611 ms on its first try and passed its second. Out of scope: - The host VolumeServer still accepts writes on a read-only volume, so a guest that remounts the volume read-write can write to the host directory (#1042, second item). - A read-write volume keeps the writeback cache, and with it the guest's own size and mtime for a file it has cached (#1041). The host must not change such a file unless the VM was booted with FCVM_NO_WRITEBACK_CACHE=1. Not run: - make lint past clippy. cargo fmt --check and cargo clippy --all-targets -- -D warnings passed. cargo audit could not fetch the advisory database from github.com, so it and cargo deny check did not run. - make test-root, the bridged tests and the arm64 nested tests. tests/test_kvm.rs and nested.sh map the fcvm config directory :ro into the outer VM and run fcvm there from the guest OS. fcvm writes that directory only in setup --generate-config, which they do not run.
… dormant key ingredient Repairs to 67d53ad (mount a read-only map read-only and without the FUSE writeback cache) from two reviews. The host check covers the image store. For a localhost/ image in overlay image mode fc-agent creates and mounts /mnt/image-store after the FUSE volumes are mounted (fc-agent/src/container.rs, mount_overlay_image). The host check knew only the mount points of the arguments, so --map DIR:/mnt:ro with such an image booted and failed in the guest on mkdir with EROFS, where f7fe35c booted. The check now gets that mount point when the boot attaches an image disk and the image mode is overlay, and the error says fcvm mounts the image store there. The path is IMAGE_STORE_MOUNT_POINT in src/commands/podman/types.rs. A unit test reads the fc-agent source and fails when fc-agent mounts the store elsewhere, or when agent.rs, container.rs or mounts.rs gains another create_dir_all whose failure fails the boot. Those are, today, the mount points of the plan's volumes, disks and NFS shares, and the image store. Every other directory fc-agent creates discards its error. The check runs on every boot. It ran once, after the kernel, rootfs and initrd were ensured and after the snapshot-cache branch had returned, so a cache hit was never checked and neither relaunch after a guest reboot was. types::checked_volume_mappings parses the maps and checks them, and is the only way the three callers of configure_and_boot_vm get their maps: - fcvm podman run and podman prepare call it before any asset, the image, the snapshot cache or the VM is touched. Everything the check needs is in the arguments, so nothing of it waits for a later step. fcvm snapshot run of a disk-only snapshot goes through the same code. - The relaunch of a podman run VM calls it before the new VMM is spawned. A refusal ends the run with the named error. - The relaunch of a restored clone calls it in build_clone_reboot_plan, which runs when the guest reboots. A refusal is logged and the reboot is treated as the VM's exit, as for any plan that cannot be built. fcvm snapshot run of a memory snapshot is not checked: its mounts are in the guest's memory. The check does not follow a symlink on the way to a mount point and cannot see a directory removed after it ran. There fc-agent fails to create the mount point and the container exits 1. DESIGN.md says which runs are checked and what happens where the check does not reach. fc-agent's fatal error is one line. main printed the error with {:?}: only the outermost context was on the [fc-agent] line, and the causes went to DEBUG on the host. The line now carries the chain in anyhow's {:#} form, with a multi-line cause joined. The order of nested mounts has a unit test. mount_fuse_volumes passes the start and the readiness wait into mount_in_levels, and a test records the events. Before, only a VM test whose red depended on which mount thread won covered that a group is ready before the next starts. FCVM_NO_WRITEBACK_CACHE no longer changes a run with no read-write map. A read-only volume is never mounted with the writeback cache, but the switch still changed the snapshot key and put no_writeback_cache=1 on the kernel command line of a run whose maps are all :ro. GuestBootInputs::for_launch now takes the parsed maps and drops the switch unless one of them is read-write. build_firecracker_config and build_launch_config pass the maps they are given. Smaller items: - FuseClient::with_destroyed_flag lost its only caller in 67d53ad and is removed. - The --map help says what :ro means. - DESIGN.md states that the host must not replace or remove a directory another mount sits on: the guest drops the inner mount within the entry timeout. It also says disks and NFS shares are mounted after every map and cover a map below them. - tests/test_read_only_map.rs runs the fcvm binary for both refusals and asserts a non-zero exit, the named error, untouched host directories and no VM in fcvm's state. A unit test parses real command lines with clap and asserts the list of mount points. Red, each test on the tree with that item's change taken back (the check knowing only the arguments' mount points, the clone's relaunch plan and the first boot parsing the maps without checking, every volume started before any wait, {:?} on the error line, for_launch dropping the switch only for a run with no volume): make test-unit FILTER="-E 'test(a_group_of_volumes_is_ready_before_the_next_group_starts) | ...'" Summary [ 5.033s] 12 tests run: 7 passed, 5 failed, 1387 skipped a_group_of_volumes_is_ready_before_the_next_group_starts left: ["start /a", "start /a/b", "ready /a", "ready /a/b"] right: ["start /a", "ready /a", "start /a/b", "ready /a/b"] the_fatal_error_line_carries_the_whole_cause_chain left: "[fc-agent] Error: mounting FUSE volumes" a_read_only_map_around_the_image_store_is_refused_when_the_run_mounts_one a run that mounts the image store inside a read-only map was accepted no_writeback_cache_does_not_fragment_keys_of_runs_with_only_read_only_maps the switch changed the key of a run whose maps are all read-only left: "b2d1de61b5e3" right: "ca6444070a5c" every_boot_has_its_maps_checked_first build_clone_reboot_plan does not check the maps make test-all FILTER="-p fcvm --test test_read_only_map -E 'test(/refused_before_boot/)'" test_read_only_map_around_image_store_is_refused_before_boot, with the image store left out of the check: stderr does not name --map <dir>:/mnt:ro stderr does not name /mnt/image-store test_mount_point_missing_from_read_only_map_is_refused_before_boot, with the first boot's check removed: the VM booted and the container exited 1 stderr does not name --map <inner>:/mnt/outer/inner stderr does not name --map <outer>:/mnt/outer:ro Green at this commit: the same make test-unit FILTER: Summary [ 0.024s] 12 tests run: 12 passed, 1387 skipped make build: exit 0 make lint: exit 0 (fmt, clippy, advisories ok, bans ok, licenses ok, sources ok) make test-unit, run before a clippy allow was added to build_launch_config, which now takes eight arguments: Summary [ 71.318s] 1399 tests run: 1399 passed (1 slow, 2 flaky), 0 skipped The two flaky tests are the two in src/uffd/server.rs that the first commit names. Each failed its first try and passed its second. make test-all, one file at a time: -p fcvm --test test_read_only_map Summary [ 35.247s] 5 tests run: 5 passed, 0 skipped -p fcvm --test test_portable_volumes Summary [ 100.872s] 8 tests run: 8 passed, 0 skipped -p fcvm --test test_volume_coherency Summary [ 41.715s] 2 tests run: 2 passed, 0 skipped -p fcvm --test test_fuse_snapshot_matrix Summary [ 118.654s] 8 tests run: 8 passed, 0 skipped -p fcvm --test test_sanity -E 'test(test_rootless_map_nonroot_reader)' Summary [ 22.289s] 1 test run: 1 passed, 9 skipped -p fcvm --test test_snapshot_clone -E 'test(test_async_pf_inside_nmi_does_not_panic_a_restored_guest)' Summary [ 65.421s] 1 test run: 1 passed, 22 skipped Not in this commit: - Keeping an inner mount when the host replaces the directory it sits on (#1043). DESIGN.md states the constraint. - A map inside a --disk, --disk-dir or --nfs guest path is mounted first and then covered, as on main (#1044). Not run: make test-root, the bridged tests and the arm64 nested tests.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (21)
Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe change adds per-volume read-only FUSE settings, validates volume mount points before VM launch, and orders nested guest mounts. Read-only maps reject guest writes and reflect host file changes. Snapshot and launch configuration now use the parsed volume mappings. ChangesRead-only volume maps
Startup diagnostics
Priority: ⬇️ Low Estimated code review effort: 4 (Complex) | ~60 minutes Change: Bug fix Sequence Diagram(s)sequenceDiagram
participant fc-agent
participant start_fuse_mount
participant mount_vsock_reconnectable
participant FUSE_session
participant mountinfo
fc-agent->>start_fuse_mount: start volumes in the current mount level
start_fuse_mount->>mount_vsock_reconnectable: pass mount point and read_only setting
mount_vsock_reconnectable->>FUSE_session: create session with MountSettings
fc-agent->>mountinfo: check mount entry and directory readiness
mountinfo-->>fc-agent: report readiness before the next level
Merge Risk: ⚪ Minimal · up to Read-only maps are now mounted read-only in the guest, without writeback caching, so guests see host file changes. Read-write maps keep their existing behavior. fcvm now refuses to start when a needed mount point is missing inside a read-only map. No concrete merge-blocking issue was found. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The change strengthens normal read-only behavior without showing increased host access. Protection still depends on the guest honoring its mount settings, and older saved machines retain their previous writable settings until recreated. Retained concerns Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 539d633e4b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
check_mount_points_inside_read_only_maps compared guest paths as they
were typed and stopped its walk at the first component that is not a
plain name. With a read-only map at /data whose host directory has no
cache, --map IN:/data/../data/cache passed the check, and
/other/../data/cache was not seen as inside the map at all. The guest's
kernel resolves both to /data/cache, so fc-agent booted and failed to
create the mount point with EROFS, which is what the check exists to
refuse before boot.
The check now folds . and .. in the mount point and in each map's guest
path before it compares them. It still looks at no filesystem for that
and still leaves a symlink on the way to the guest.
Found by the Codex review of this pull request.
Red, the test on the tree before the fix:
make test-unit FILTER="-E 'test(a_mount_point_written_with_parent_components_is_checked_where_it_resolves)'"
FAIL commands::podman::types::tests::a_mount_point_written_with_parent_components_is_checked_where_it_resolves
/data/../data/cache was accepted with no cache directory in the map
Green:
the same FILTER:
Summary [ 0.014s] 1 test run: 1 passed, 1399 skipped
make test-unit FILTER="-E 'test(/commands::podman::types::tests/) | test(/commands::podman::tests::/)'"
Summary [ 0.149s] 51 tests run: 51 passed, 1349 skipped
make lint: exit 0
fc-agent orders nested mounts by the paths as typed (mount_levels), so
two maps of which one is written with .. are still started together.
That is the race main has for every nested pair, and this change does
not touch it.
ejc3
left a comment
There was a problem hiding this comment.
RED-VERIFIED: commands::podman::types::tests::a_mount_point_written_with_parent_components_is_checked_where_it_resolves
This answers the Codex review of 539d633, whose one finding is the inline thread on src/commands/podman/types.rs: a mount point written with .. passed the check. The test fails on 539d633 (/data/../data/cache was accepted with no cache directory in the map) and passes on 4d39a47, which folds . and .. before comparing guest paths.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4d39a470db
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The check before boot folded `.` and `..` in guest paths without the
guest's filesystem. Where `..` leads depends on the symlinks before it:
with /var/run a link to /run, /var/run/../actual/inner is /actual/inner in
the guest, and the fold read it as /var/actual/inner, outside a read-only
map at /actual. The run then passed the check and fc-agent failed in the
guest with EROFS.
A run with a read-only map now refuses a mount point or a map guest path
that has a `..` component, and names the argument. `lexically_normal` is
gone: comparing paths by component already ignores `.` and repeated
slashes. A run with no read-only map is unchanged.
Tested:
make test-unit FILTER="-E 'test(a_guest_path_with_a_parent_component_is_refused_beside_a_read_only_map)'"
on 4d39a47 with the test alone: 0 passed, 1 failed,
"/var/run/../actual/inner was accepted beside a read-only map"
with the change: 1 passed
make test-unit FILTER="-E 'test(/commands::podman::types::tests/) | test(/commands::podman::tests::/)'"
51 passed
make lint: exit 0
ejc3
left a comment
There was a problem hiding this comment.
RED-VERIFIED: commands::podman::types::tests::a_guest_path_with_a_parent_component_is_refused_beside_a_read_only_map
This answers the Codex review of 4d39a47, whose one finding is the inline thread on src/commands/podman/types.rs: folding .. is wrong when a symlink precedes it in the guest. The test fails on 4d39a47 (/var/run/../actual/inner was accepted beside a read-only map) and passes on 6c5f1bb, which refuses a guest path with .. in a run that has a read-only map.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6c5f1bbe31
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
ejc3
left a comment
There was a problem hiding this comment.
DISAGREE: this answers the Codex review of 6c5f1bb, whose two findings are the inline threads, and each thread has the detail.
The check-to-mount window ends in a refused boot whose error names the path, and no lock binds another process that removes a directory of the user's own tree. The unchanged-metadata rewrite reads the same through a read-write map mounted as on main, a new open reads the new bytes, and #1049 tracks the documentation and the test.
ejc3
left a comment
There was a problem hiding this comment.
NOT-A-DEFECT: this answers CodeRabbit's review summary, which reports no actionable comments and no merge-blocking issue. It names no defect.
A
--map HOST:GUEST:rovolume is now mounted read-only in the guest and without the FUSE writeback cache, so the guest follows the host's files. This closes the read-only half of #1041 and the first item of #1042.Stacked on: main (f7fe35c). Four commits: the change, the repairs from its review, and two for the check before boot: 4d39a47 folded
..in a guest path, and 6c5f1bb replaces that with refusing such a path in a run that has a read-only map, because where..leads depends on symlinks in the guest.The problem
Measured on main at f7fe35c (the issues hold the probes):
--portable-volumesa file replaced by rename kept its old size and mtime in the clone.:romap was mountedrwin the guest.fcvm exec --vm -- sh -c 'echo x > /mapro/f'exited 0 and created the file on the host. Only the container's bind mount was read-only.test_remap_fs_host_file_changesandtest_remap_fs_snapshot_file_replaceeach replace a file with one of the same length, and no test wrote to a:romap from the guest OS.The change
fuse_pipe::MountSettings::for_volume(read_only, no_writeback_cache)is the one decision. A read-only volume getsMS_RDONLYand never asks forFUSE_WRITEBACK_CACHE. A read-write volume is mounted as before. The Unix socket path and the vsock path share one session setup.read_onlyto the mount, and mounts an outer volume before a volume inside it. Before, every mount started at once and an outer mount that landed second covered the inner one.podman runandpodman preparebefore anything is set up and before the snapshot cache is consulted, and before each relaunch after a guest reboot. The image store of alocalhost/image in overlay mode (/mnt/image-store) counts as a mount point. The error names both arguments and the missing directory.FCVM_NO_WRITEBACK_CACHEno longer changes the snapshot key or the kernel command line of a run with no read-write map, where it now changes nothing.:romeans in the guest, which runs are checked, what the host may change under a read-write map, and that the host must not replace a directory another mount sits on.Contract and downstream impact
A consumer that maps host directories
:roand restores clones hours later (the www VM maps eleven) reads the host's current files in a running VM and in a clone. A snapshot made by an older fc-agent keeps its old mounts until it is made again; the snapshot cache key already separates them through the initrd path, so no key ingredient is added. Read-write maps are unchanged.Evidence
Red on f7fe35c plus the new VM tests:
Red for the repairs, each test with its item taken back:
Green at the head:
The two flaky tests are in
src/uffd/server.rs, which this change does not touch. Each failed its first try and passed its second on a host whose load average was above 200. The unit run predates a clippy allow on one function.Not in this PR
Not run locally:
make test-root, the bridged tests, the arm64 nested tests.Summary by CodeRabbit
:rovolume maps are mounted read-only in the guest, and host file updates—including replacements—become visible while VMs are running and after snapshot restoration.