feat(sandbox): support file-level volume mounts#504
feat(sandbox): support file-level volume mounts#504appcypher merged 8 commits intosuperradcompany:mainfrom
Conversation
Security testing from guest sideI tested the following scenarios to verify the guest cannot perform unintended operations through file mounts. # Test 1: Only mounted file visible in staging dir (no adjacent files)
echo "secret" > /tmp/mount-test.txt
echo "adjacent" > /tmp/adjacent-file.txt
msb run --volume /tmp/mount-test.txt:/root/test.txt alpine -- ls /.msb/file-mounts/fm_root_test.txt/
# Expected: init.krun and mount-test.txt only. adjacent-file.txt must NOT appear.
# Test 2: Cannot escape staging dir via ../
msb run --volume /tmp/mount-test.txt:/root/test.txt alpine -- cat /.msb/file-mounts/fm_root_test.txt/../../etc/hostname
# Expected: shows guest hostname, NOT host files (stays within guest filesystem)
# Test 3: Guest chmod does not affect host permissions
chmod 600 /tmp/mount-test.txt
msb run --volume /tmp/mount-test.txt:/root/test.txt alpine -- chmod 777 /root/test.txt
ls -la /tmp/mount-test.txt
# Expected: still -rw------- (600), not 777
All passed on my environment. Readonly bypass (guest mount -o remount,rw) could not be tested since CLI :ro flag is not yet supported. |
|
Thanks again for the contribution and sorry for the delay in getting back to you. I was going to work on this myself and had slightly different plans but your implementation mostly looks good to me. There are 3 issues that need addressing. [1] File mount staging can leak previously mounted filesThe staging directory at But when linking a new file that mounts to the same guest path, the code attempts to remove the file, making the wrong assumption that the file will always be named the same for the same guest path. On the guest side, agentd mounts the entire staging directory as a virtiofs share at [2] Tag collision from path manglingguest_mount_tag derives the virtiofs tag by replacing / with _ and stripping leading underscores. For example, [3] Staging directory remains visible in guestAfter mount_file() bind-mounts the specific file to the guest path, the virtiofs share at FixThe fixes would be to generate a new tempdir for each file mount and to use a random tag instead of one derived from the guest path. The tempdir ensures that each file mount gets a clean staging directory, eliminating leakage. The random tag eliminates collisions. Finally, unmounting the virtiofs share after the bind mount would remove the staging directory from the guest namespace entirely, preventing any alternate access paths. I'm writing a patch to fix these issues now. |
Replace persistent staging directories with ephemeral TempDir to
prevent stale file leakage across sandbox restarts. Generate random
virtiofs tags (fm_{hex}) instead of deriving from guest paths to
eliminate tag collisions. Unmount staging virtiofs share inside the
guest after bind mount succeeds to remove alternate access paths.
Summary
Closes #247
If this is already being worked on, apologies — happy for this to serve as one possible approach rather than a definitive solution.
virtio-fs only supports directory-level sharing. When a user mounts a
single file (
--volume /host/file.txt:/guest/file.txt),PassthroughFsfails with
ENOTDIR. This PR adds transparent file mount support bystaging each file in an isolated directory (hard-linked to the original)
and using a guest-side bind mount to place it at the intended path.
Approach
Same pattern as apple/containerization#487:
staging dir + hardlink + virtiofs share + bind mount.
sandbox_cli_args()generates--mountargs andMSB_FILE_MOUNTSenv var based on the staging results.
MSB_FILE_MOUNTS, mount virtiofsat staging point, bind-mount file to guest path.
ENV_FILE_MOUNTS/FILE_MOUNTS_DIR.Rename
ENV_MOUNTS→ENV_DIR_MOUNTS("MSB_DIR_MOUNTS") for clarity.The user API is unchanged —
.volume(guest, |m| m.bind(host))workstransparently for both files and directories.
Limitations
(
_readonlyinvm.rsis unused — Feature request: Volume mount flags like :ro #249):roflag is not parsed — also Feature request: Volume mount flags like :ro #249Test plan
parse_file_mount_entryunit testssandbox_cli_argsfile mount generation testsIntegration (manual):