Skip to content

Bug: allowWrite paths under /run/user/<uid>/ not accessible in bwrap sandbox #49

@tito

Description

@tito

Problem

When a profile includes allowWrite paths under /run/user/<uid>/ (e.g. /run/user/1000/libvirt/*), the directory is not actually writable inside the sandbox because bwrap creates a fresh tmpfs at /run/user with only an empty /run/user/1000/ directory.

The Landlock layer correctly adds write rules for the specified paths, but the bwrap mount structure doesn't include --dir or --bind entries for subdirectories that need to exist, so programs like virsh fail with:

error: failed to connect to the hypervisor
error: Cannot create user runtime directory '/run/user/1000/libvirt': Permission denied

Reproduction

  1. Create a profile with:
{
  "allowRead": ["/run/user/1000/libvirt/*", "/dev/kvm"],
  "allowWrite": ["/run/user/1000/libvirt/*", "/dev/kvm"]
}
  1. Run: greywall --profile libvirt -- virsh -c qemu:///session list

  2. Observe the "Permission denied" error when virsh tries to create /run/user/1000/libvirt/.

Root cause

In the bwrap argument construction, /run/user is mounted as a tmpfs and /run/user/1000 is created with --dir. However, no --dir or --bind entries are added for subdirectories that appear in allowWrite.

The relevant bwrap args:

--tmpfs /run/user --dir /run/user/1000

Expected behavior

When allowWrite includes paths under /run/user/<uid>/, greywall should either:

  • Add --dir entries in bwrap for the parent directories (e.g. --dir /run/user/1000/libvirt)
  • Or --bind the host directory if it already exists (e.g. --bind /run/user/1000/libvirt /run/user/1000/libvirt)

The second option is probably better since it preserves existing sockets/state from the host (like the libvirt daemon socket).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions