#945

virtio/fs: add a fixed-owner mode for shared directories

Openjansavwants to merge intofrom

Problem

An embedder often shares a host directory, owned by the host user, with a guest that runs as some other user: a project folder mounted into a sandbox that runs as node or nobody. The guest user must see the files as its own, or it cannot write to them.

On a macOS host the only way to get that today is LinuxSimplified, which reports every file as owned by the process that asks. It works, but it is very slow. On a 63,224-file node_modules, unpacking takes 168 s and find takes 17 s, against 36 s and 1.4 s on Apple's Virtualization.framework.

Cause

Under LinuxSimplified the owner depends on the caller, so attributes cannot be cached, and the device sets the attribute timeout to 0. Every stat in the guest becomes a round trip to the host.

Fix

Let the embedder fix the owner instead. A fixed owner is the same for every caller, so attributes keep the default 5 s timeout.

Two commits:

  1. virtio/fs: add a fixed-owner variant of the simplified semantics.
    • PermissionSemantics::LinuxSimplifiedOwnedBy(uid, gid) behaves as LinuxSimplified, but stat, lstat and mknod report uid:gid as the owner.
    • Fs::set_fixed_owner selects it before the device activates.
    • Linux declares the variant next to LinuxSimplified, which it does not act on either.
  2. lib: add FsDevice::set_fixed_owner.
    • Exposes it as FsDevice::set_fixed_owner(uid, gid) and krun_fs_device_set_fixed_owner.
    • The bindings are regenerated with make gen-libkrun-bindings; the C header diff is only the new function.
    • Adds the virtiofs-fixed-owner test.

On the host, files are still created and changed as the user running libkrun. A chown from the guest is accepted and not kept, as under LinuxSimplified.

With a fixed owner of 0, the guest sees every set-user-ID file on the share as owned by root, so such a file runs as root in the guest. LinuxSimplified does not have this, because the owner is always the caller. The doc comment of set_fixed_owner (and so the C header) says to mount such a share with nosuid.

Evidence

Setup: M4 Pro, macOS 26.7, aarch64 Linux guest with 2 vCPUs and 2 GiB, a 63,224-file node_modules tarball on a virtio-fs share, used by a guest user other than root; medians of 3.

StepLinuxSimplifiedFixed ownerVirtualization.framework
Unpack168 s38 s36 s
find -type f17 s3.1 s1.4 s
du -s16 s1.5 s1.3 s
rm -rf39 s14 s8.6 s

The remaining gap on find and rm -rf is the per-request round trip, which #943 and #944 address.

The new virtiofs-fixed-owner test runs on macOS. It checks that these report the fixed owner:

  • a host file and the root directory;
  • a file, a directory, a FIFO (mknod) and a symlink the guest creates;
  • a file after a chown from the guest, which is accepted without changing it.

It also checks that the guest's write reaches the host directory. With the fixed owner ignored (the caller reported instead), the test fails.

Tests

make test, M4 Pro, macOS 26.7, dynamic linking:

RefResult
upstream main15/16 pass; virtiofs-misc fails in uid_gid_mapping_preexisting
this branch16/17 pass; the same failure, nothing new; virtiofs-fixed-owner passes

The 17 skipped tests need FreeBSD assets, pjdfstest, iperf, TAP or passt, none of which this Mac has.

Related work

  • #759 added LinuxSimplified and left it out of the 2.0 API on purpose, while that API settles. This PR adds the first 2.0 setter for a permission semantics. If a general setter is preferred, set_fixed_owner can become one variant of it.
  • #933 (experimental) restructures fs/device.rs. Fs::set_fixed_owner is small and rebases onto it either way.

Activity

3
slp1d ago

@jansav thanks for the PR! This new mode looks like a good idea to me. Please rebase this on #954, extend PermissionSemantics with your new mode and set_fixed_owner with an API just for setting the uid/gid (this one should fail if the configured mode isn't the new mode).