[PATCH v2 1/8] host/rootfs: create dbus socket externally
This is the first step towards running dbus as non-root. Signed-off-by: Alyssa Ross <hi@alyssa.is> --- v2: no change .../template/data/service/dbus/notification-fd | 2 +- .../data/service/dbus/notification-fd.license | 2 +- .../vm-services/template/data/service/dbus/run | 13 +++++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/notification-fd b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/notification-fd index 00750edc..b8626c4c 100644 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/notification-fd +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/notification-fd @@ -1 +1 @@ -3 +4 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/notification-fd.license b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/notification-fd.license index 5a406331..0d3d47ca 100644 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/notification-fd.license +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/notification-fd.license @@ -1,2 +1,2 @@ SPDX-License-Identifier: CC0-1.0 -SPDX-FileCopyrightText: 2022 Alyssa Ross <hi@alyssa.is> +SPDX-FileCopyrightText: 2025 Alyssa Ross <hi@alyssa.is> diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run index 40b75355..365e1697 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run @@ -4,10 +4,19 @@ importas -i VM VM +s6-ipcserver-socketbinder -B /run/vm/by-id/${VM}/portal-bus + +fdmove -c 3 0 +redirfd -r 0 /dev/null + nsenter --mount=/run/vm/by-id/${VM}/mount unshare --cgroup --ipc --net --uts + +export LISTEN_FDS 1 +getpid LISTEN_PID + dbus-daemon --config-file /usr/share/dbus-1/session.conf - --print-address 3 - --address unix:path=/run/vm/by-id/${VM}/portal-bus + --print-address 4 + --address systemd: base-commit: e32cdde75ef9ec554c1c40bba7f4a75dcaaa779f -- 2.51.0
This will allow xdg-desktop-portal-spectrum-host to be run as a user without access to the VM directory. Signed-off-by: Alyssa Ross <hi@alyssa.is> --- v2: no change .../template/data/service/xdg-desktop-portal-spectrum-host/run | 3 ++- tools/start-vmm/lib.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run index d2bf78ce..57e893d3 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run @@ -6,7 +6,8 @@ importas -i VM VM export DBUS_SESSION_BUS_ADDRESS unix:path=/run/vm/by-id/${VM}/portal-bus -s6-ipcserver-socketbinder -a 0700 /run/vm/by-id/${VM}/vsock_219 +if { mkdir -p /run/vsock/${VM} } +s6-ipcserver-socketbinder -a 0700 /run/vsock/${VM}/vsock_219 # Notify readiness. if { fdmove 1 3 echo } diff --git a/tools/start-vmm/lib.rs b/tools/start-vmm/lib.rs index b44e0375..52c96c5e 100644 --- a/tools/start-vmm/lib.rs +++ b/tools/start-vmm/lib.rs @@ -154,7 +154,7 @@ pub fn vm_config(vm_dir: &Path) -> Result<VmConfig, String> { }, vsock: VsockConfig { cid: 3, - socket: vm_dir.join("vsock").into_os_string().into_string().unwrap(), + socket: format!("/run/vsock/{vm_name}/vsock"), }, landlock_enable: true, landlock_rules: vec![ -- 2.51.0
This will allow xdg-desktop-portal-spectrum-host to be run as a user without access to the VM directory. Signed-off-by: Alyssa Ross <hi@alyssa.is> --- v2: no change host/rootfs/Makefile | 1 + .../service/vm-services/template/data/service/dbus/run | 2 +- .../template/data/service/xdg-desktop-portal-spectrum-host/run | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 7bec1259..b9e0fdd9 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -14,6 +14,7 @@ DIRS = \ dev \ etc/s6-linux-init/env \ etc/s6-linux-init/run-image/configs \ + etc/s6-linux-init/run-image/portal-bus \ etc/s6-linux-init/run-image/sd-notify-wrapper \ etc/s6-linux-init/run-image/service/serial-getty/instance \ etc/s6-linux-init/run-image/service/serial-getty/instances \ diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run index 365e1697..83e97c65 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run @@ -4,7 +4,7 @@ importas -i VM VM -s6-ipcserver-socketbinder -B /run/vm/by-id/${VM}/portal-bus +s6-ipcserver-socketbinder -B /run/portal-bus/${VM} fdmove -c 3 0 redirfd -r 0 /dev/null diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run index 57e893d3..9e493dff 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run @@ -4,7 +4,7 @@ importas -i VM VM -export DBUS_SESSION_BUS_ADDRESS unix:path=/run/vm/by-id/${VM}/portal-bus +export DBUS_SESSION_BUS_ADDRESS unix:path=/run/portal-bus/${VM} if { mkdir -p /run/vsock/${VM} } s6-ipcserver-socketbinder -a 0700 /run/vsock/${VM}/vsock_219 -- 2.51.0
Signed-off-by: Alyssa Ross <hi@alyssa.is> --- v2: no change host/rootfs/file-list.mk | 1 + host/rootfs/image/etc/dbus-portal.conf.in | 11 +++++++++++ .../template/data/service/dbus/run | 8 +++++++- .../xdg-desktop-portal-spectrum-host/run | 2 ++ host/rootfs/image/usr/bin/run-appimage | 1 + host/rootfs/image/usr/bin/run-flatpak | 1 + host/rootfs/image/usr/bin/vm-import | 1 + host/rootfs/image/usr/bin/vm-start | 19 ++++++++++++++++++- 8 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 host/rootfs/image/etc/dbus-portal.conf.in diff --git a/host/rootfs/file-list.mk b/host/rootfs/file-list.mk index f69775d2..59d83b7e 100644 --- a/host/rootfs/file-list.mk +++ b/host/rootfs/file-list.mk @@ -2,6 +2,7 @@ # SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> FILES = \ + image/etc/dbus-portal.conf.in \ image/etc/fonts/fonts.conf \ image/etc/fstab \ image/etc/init \ diff --git a/host/rootfs/image/etc/dbus-portal.conf.in b/host/rootfs/image/etc/dbus-portal.conf.in new file mode 100644 index 00000000..3e0e6725 --- /dev/null +++ b/host/rootfs/image/etc/dbus-portal.conf.in @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- SPDX-License-Identifier: CC0-1.0 --> +<!-- SPDX-FileCopyrightText: 2025 Alyssa Ross <hi@alyssa.is> --> +<!DOCTYPE busconfig SYSTEM "busconfig.dtd"> +<busconfig> + <include>/usr/share/dbus-1/session.conf</include> + + <policy context="default"> + <allow user="@XDP_SPECTRUM_USER@"/> + </policy> +</busconfig> diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run index 83e97c65..20f1daff 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run @@ -4,11 +4,17 @@ importas -i VM VM +if { + redirfd -w 1 data/dbus.conf + sed "s/@XDP_SPECTRUM_USER@/xdp-spectrum-${VM}/g" /etc/dbus-portal.conf.in +} + s6-ipcserver-socketbinder -B /run/portal-bus/${VM} fdmove -c 3 0 redirfd -r 0 /dev/null +getcwd -E dir nsenter --mount=/run/vm/by-id/${VM}/mount unshare --cgroup --ipc --net --uts @@ -17,6 +23,6 @@ export LISTEN_FDS 1 getpid LISTEN_PID dbus-daemon - --config-file /usr/share/dbus-1/session.conf + --config-file ${dir}/data/dbus.conf --print-address 4 --address systemd: diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run index 9e493dff..b83d23dd 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run @@ -13,4 +13,6 @@ s6-ipcserver-socketbinder -a 0700 /run/vsock/${VM}/vsock_219 if { fdmove 1 3 echo } fdclose 3 +s6-setuidgid xdp-spectrum-${VM} + xdg-desktop-portal-spectrum-host diff --git a/host/rootfs/image/usr/bin/run-appimage b/host/rootfs/image/usr/bin/run-appimage index 36f57b85..47cab4c5 100755 --- a/host/rootfs/image/usr/bin/run-appimage +++ b/host/rootfs/image/usr/bin/run-appimage @@ -5,6 +5,7 @@ backtick -E dir { mktemp -d /run/vm/by-id/XXXXXX } backtick -E id { basename -- $dir } if { useradd -P /run -Urd / -s /bin/nologin gpu-${id} } +if { useradd -P /run -Urd / -s /bin/nologin xdp-spectrum-${id} } if { mkdir -p /run/configs/${id}/fs } diff --git a/host/rootfs/image/usr/bin/run-flatpak b/host/rootfs/image/usr/bin/run-flatpak index 2ef20433..bb366735 100755 --- a/host/rootfs/image/usr/bin/run-flatpak +++ b/host/rootfs/image/usr/bin/run-flatpak @@ -5,6 +5,7 @@ backtick -E dir { mktemp -d /run/vm/by-id/XXXXXX } backtick -E id { basename -- $dir } if { useradd -P /run -Urd / -s /bin/nologin gpu-${id} } +if { useradd -P /run -Urd / -s /bin/nologin xdp-spectrum-${id} } if { elgetpositionals diff --git a/host/rootfs/image/usr/bin/vm-import b/host/rootfs/image/usr/bin/vm-import index 19a0df36..c848fe32 100755 --- a/host/rootfs/image/usr/bin/vm-import +++ b/host/rootfs/image/usr/bin/vm-import @@ -10,6 +10,7 @@ forx -po0 -E name { $names } backtick -E dir { mktemp -d /run/vm/by-id/XXXXXX } backtick -E id { basename -- $dir } if { useradd -P /run -Urd / -s /bin/nologin gpu-${id} } +if { useradd -P /run -Urd / -s /bin/nologin xdp-spectrum-${id} } if { ln -s -- ${dir} /run/vm/by-name/${1}.${name} } if { ln -s -- ${2}/${name} ${dir}/config } diff --git a/host/rootfs/image/usr/bin/vm-start b/host/rootfs/image/usr/bin/vm-start index 67480e52..c8031eec 100755 --- a/host/rootfs/image/usr/bin/vm-start +++ b/host/rootfs/image/usr/bin/vm-start @@ -20,4 +20,21 @@ foreground { redirfd -w 2 /dev/null s6-svwait -U /run/service/vmm/instance/${1} } -ch-remote --api-socket /run/vm/by-id/${1}/vmm boot +foreground { ch-remote --api-socket /run/vm/by-id/${1}/vmm boot } +importas -Siu ? +if { + if -t { test $? -eq 0 } + + # This is technically racy: if somehow we don't get here before the VM boots + # and connects to xdg-desktop-portal-spectrum-host, it won't be able to + # connect. The VM rebooting will also break this, because the socket will be + # re-created with the wrong mode, but VM reboots are broken anyway at the time + # of writing: + # + # https://github.com/cloud-hypervisor/cloud-hypervisor/issues/7547 + # + # Ideally we'd be able to give a listening socket FD to Cloud Hypervisor for + # its VSOCK socket. + chown xdp-spectrum-${1} /run/vsock/${1}/vsock +} +exit $? -- 2.51.0
The document portal has to be root to mount its fuse filesystem. This needs to be a shared namespace because virtiofsd needs to be in the same mount namespace as the document portal so that it sees the fuse filesystem, so we create a per-VM persistent user namespace. Signed-off-by: Alyssa Ross <hi@alyssa.is> --- v2: put nsfs bind mounts into a shared directory, to make unmounting nicer. v1: https://spectrum-os.org/lists/archives/spectrum-devel/20251210124757.1080443... .../vm-services/template/data/service/dbus/run | 2 +- .../template/data/service/vhost-user-fs/run | 2 +- host/rootfs/image/usr/bin/create-vm-dependencies | 13 +++++++++---- host/rootfs/image/usr/bin/run-appimage | 5 ++--- host/rootfs/image/usr/bin/run-flatpak | 5 ++--- host/rootfs/image/usr/bin/spectrum-update | 2 +- 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run index 20f1daff..f4c78f71 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run @@ -15,7 +15,7 @@ fdmove -c 3 0 redirfd -r 0 /dev/null getcwd -E dir -nsenter --mount=/run/vm/by-id/${VM}/mount +nsenter --mount=/run/vm/by-id/${VM}/ns/mnt unshare --cgroup --ipc --net --uts diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run index 79830a00..1936175e 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run @@ -12,7 +12,7 @@ export TMPDIR /run importas -i VM VM -nsenter --mount=/run/vm/by-id/${VM}/mount +nsenter --mount=/run/vm/by-id/${VM}/ns/mnt unshare -U --map-user 1000 --map-group 1000 --uts --ipc --cgroup virtiofsd --fd 3 --shared-dir /run/vm/by-id/${VM}/fs diff --git a/host/rootfs/image/usr/bin/create-vm-dependencies b/host/rootfs/image/usr/bin/create-vm-dependencies index d4a10ab4..34dace4b 100755 --- a/host/rootfs/image/usr/bin/create-vm-dependencies +++ b/host/rootfs/image/usr/bin/create-vm-dependencies @@ -2,18 +2,23 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2024-2025 Alyssa Ross <hi@alyssa.is> -if { touch /run/vm/by-id/${1}/mount } -if { mount --make-private --bind /run/vm/by-id/${1}/mount /run/vm/by-id/${1}/mount } - if { mkdir -p /run/vm/by-id/${1}/doc-run/doc /run/vm/by-id/${1}/fs/config /run/vm/by-id/${1}/fs/doc + /run/vm/by-id/${1}/ns } +if { mount --make-private --rbind /run/vm/by-id/${1}/ns /run/vm/by-id/${1}/ns } +if { touch /run/vm/by-id/${1}/ns/mnt /run/vm/by-id/${1}/ns/user } + if { - unshare --propagation=slave --mount=/run/vm/by-id/${1}/mount + unshare --propagation=slave + --map-users all + --map-groups all + --mount=/run/vm/by-id/${1}/ns/mnt + --user=/run/vm/by-id/${1}/ns/user if { mount --make-shared --rbind /run/vm/by-id/${1} /run/vm/by-id/${1} } diff --git a/host/rootfs/image/usr/bin/run-appimage b/host/rootfs/image/usr/bin/run-appimage index 47cab4c5..44a683c3 100755 --- a/host/rootfs/image/usr/bin/run-appimage +++ b/host/rootfs/image/usr/bin/run-appimage @@ -19,7 +19,7 @@ if { ln -s /run/configs/${id} ${dir}/config } if { create-vm-dependencies $id } if { - nsenter --mount=${dir}/mount + nsenter --mount=${dir}/ns/mnt cd ${dir}/fs/config if { redirfd -w 1 type echo appimage } if { touch run } @@ -42,6 +42,5 @@ fdclose 3 if { s6-instance-delete /run/service/vm-services $id } -if { umount ${dir}/mount } # mount namespace -if { umount ${dir}/mount } # private bind mount +if { umount -R ${dir}/ns } rm -r $dir /run/configs/${id} diff --git a/host/rootfs/image/usr/bin/run-flatpak b/host/rootfs/image/usr/bin/run-flatpak index bb366735..07cfc262 100755 --- a/host/rootfs/image/usr/bin/run-flatpak +++ b/host/rootfs/image/usr/bin/run-flatpak @@ -22,7 +22,7 @@ if { if { create-vm-dependencies $id } if { - nsenter --mount=${dir}/mount + nsenter --mount=${dir}/ns/mnt cd ${dir}/fs/config if { redirfd -w 1 type echo flatpak } mount-flatpak $@ @@ -44,6 +44,5 @@ if { if { s6-instance-delete -- /run/service/vm-services $id } -if { umount ${dir}/mount } # mount namespace -if { umount ${dir}/mount } # private bind mount +if { umount -R ${dir}/ns } rm -r $dir /run/configs/${id} diff --git a/host/rootfs/image/usr/bin/spectrum-update b/host/rootfs/image/usr/bin/spectrum-update index b1517a6c..be99c9da 100755 --- a/host/rootfs/image/usr/bin/spectrum-update +++ b/host/rootfs/image/usr/bin/spectrum-update @@ -50,7 +50,7 @@ foreground { cp -- /etc/systemd/import-pubring.gpg /run/vm/by-id/${update_vm_id}/fs/etc/systemd } - nsenter --mount=/run/vm/by-id/${update_vm_id}/mount + nsenter --mount=/run/vm/by-id/${update_vm_id}/ns/mnt cd $1 # If the directory is already mounted, unmount it. This prevents a -- 2.51.0
On 12/11/25 11:21, Alyssa Ross wrote:
The document portal has to be root to mount its fuse filesystem. This needs to be a shared namespace because virtiofsd needs to be in the same mount namespace as the document portal so that it sees the fuse filesystem, so we create a per-VM persistent user namespace.
Signed-off-by: Alyssa Ross <hi@alyssa.is>
I think it would be cleanest to have a per-VM supervisor process that spawns each process in the correct namespace. This avoids having to manually unmount anything. This is definitely out of scope for now, though. Since a per-VM supervisor is needed for cgroup support, I think this should wait until cgroup support is done. -- Sincerely, Demi Marie Obenour (she/her/hers)
This will enable running D-Bus as a user that does not have access to VM directories. Signed-off-by: Alyssa Ross <hi@alyssa.is> --- v2: add comment explaining --make-shared v1: https://spectrum-os.org/lists/archives/spectrum-devel/20251210124757.1080443... host/rootfs/image/usr/bin/create-vm-dependencies | 8 ++++++-- .../services/org.freedesktop.portal.Documents.service | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/host/rootfs/image/usr/bin/create-vm-dependencies b/host/rootfs/image/usr/bin/create-vm-dependencies index 34dace4b..fc2bec7b 100755 --- a/host/rootfs/image/usr/bin/create-vm-dependencies +++ b/host/rootfs/image/usr/bin/create-vm-dependencies @@ -4,7 +4,7 @@ if { mkdir -p - /run/vm/by-id/${1}/doc-run/doc + /run/doc/${1}/doc /run/vm/by-id/${1}/fs/config /run/vm/by-id/${1}/fs/doc /run/vm/by-id/${1}/ns @@ -27,7 +27,11 @@ if { # can be writable block-based bind mounted subdirectories. if { mount --rbind -o nofail /run/vm/by-id/${1}/config/fs /run/vm/by-id/${1}/fs/config } if { mount --rbind -o ro /run/vm/by-id/${1}/fs /run/vm/by-id/${1}/fs } - mount --rbind /run/vm/by-id/${1}/doc-run/doc /run/vm/by-id/${1}/fs/doc + + # Needs to be shared so that when xdg-document-portal mounts its fuse + # filesystem at /run/doc/${1}/doc, it will propagate to /run/fs/${1}/doc. + if { mount --make-shared --rbind /run/doc/${1} /run/doc/${1} } + mount --rbind /run/doc/${1}/doc /run/vm/by-id/${1}/fs/doc } if { s6-instance-create /run/service/vm-services $1 } diff --git a/host/rootfs/image/usr/share/dbus-1/services/org.freedesktop.portal.Documents.service b/host/rootfs/image/usr/share/dbus-1/services/org.freedesktop.portal.Documents.service index f4dd53e3..be24f080 100644 --- a/host/rootfs/image/usr/share/dbus-1/services/org.freedesktop.portal.Documents.service +++ b/host/rootfs/image/usr/share/dbus-1/services/org.freedesktop.portal.Documents.service @@ -3,4 +3,4 @@ [D-BUS Service] Name=org.freedesktop.portal.Documents -Exec=/bin/importas -Si VM export XDG_RUNTIME_DIR /run/vm/by-id/${VM}/doc-run xdg-document-portal +Exec=/bin/importas -Si VM export XDG_RUNTIME_DIR /run/doc/${VM} xdg-document-portal -- 2.51.0
This will enable running virtiofsd as a user that does not have access to VM directories. Signed-off-by: Alyssa Ross <hi@alyssa.is> --- v2: • update documentation • add comment to explain --make-shared v1: https://spectrum-os.org/lists/archives/spectrum-devel/20251210124757.1080443... .../using-spectrum/creating-custom-vms.adoc | 6 +++--- Documentation/using-spectrum/vm-file-access.adoc | 13 ++++++------- .../template/data/service/vhost-user-fs/run | 2 +- host/rootfs/image/usr/bin/create-vm-dependencies | 15 ++++++++------- host/rootfs/image/usr/bin/run-appimage | 2 +- host/rootfs/image/usr/bin/run-flatpak | 2 +- host/rootfs/image/usr/bin/spectrum-update | 14 +++++++------- 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Documentation/using-spectrum/creating-custom-vms.adoc b/Documentation/using-spectrum/creating-custom-vms.adoc index a397ac50..36603d77 100644 --- a/Documentation/using-spectrum/creating-custom-vms.adoc +++ b/Documentation/using-spectrum/creating-custom-vms.adoc @@ -90,9 +90,9 @@ should configure `eth0` with the IPv4 address `100.64.165.70` (because === Filesystem -Every VM has a virtio-fs device that exposes the /run/vm/by-id/_VM -ID_/fs directory on the host, with the tag "virtiofs0". The VM cannot -write directly into that directory, but it's possible to create a +Every VM has a virtio-fs device that exposes the /run/fs/_VM ID_ +directory on the host, with the tag "virtiofs0". The VM cannot write +directly into that directory, but it's possible to create a subdirectory on the host and bind mount a directory from a writeable filesystem into it to provide the VM with access to shared storage. diff --git a/Documentation/using-spectrum/vm-file-access.adoc b/Documentation/using-spectrum/vm-file-access.adoc index 1b4fe9a5..06bac9f8 100644 --- a/Documentation/using-spectrum/vm-file-access.adoc +++ b/Documentation/using-spectrum/vm-file-access.adoc @@ -36,11 +36,10 @@ the portal. When using an application that doesn't implement the File Chooser API, you can still give it access to files manually. Each VM has -xref:creating-custom-vms.adoc#filesystem[access] to the -/run/vm/by-id/_VM ID_/fs directory on the host (mounted at -/run/virtiofs/virtiofs0 in the default Spectrum VM image). For the -VM, this directory is read-only, but writeable files and directories -can be bind-mounted into it: +xref:creating-custom-vms.adoc#filesystem[access] to the /run/fs/_VM +ID_ directory on the host (mounted at /run/virtiofs/virtiofs0 in the +default Spectrum VM image). For the VM, this directory is read-only, +but writeable files and directories can be bind-mounted into it: [example] ==== @@ -54,11 +53,11 @@ echo "Hello, world!" > /ext/example.txt + [listing] [source,shell] -touch /run/vm/by-name/user.appvm-example/fs/example.txt +touch /run/fs/gGKghi/example.txt 3. Create the bind mount: + [listing] [source,shell] -mount --rbind /ext/example.txt /run/vm/by-name/user.appvm-example/fs/example.txt +mount --rbind /ext/example.txt /run/fs/gGKghi/example.txt ==== diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run index 1936175e..3446dcc2 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run @@ -15,4 +15,4 @@ importas -i VM VM nsenter --mount=/run/vm/by-id/${VM}/ns/mnt unshare -U --map-user 1000 --map-group 1000 --uts --ipc --cgroup -virtiofsd --fd 3 --shared-dir /run/vm/by-id/${VM}/fs +virtiofsd --fd 3 --shared-dir /run/fs/${VM} diff --git a/host/rootfs/image/usr/bin/create-vm-dependencies b/host/rootfs/image/usr/bin/create-vm-dependencies index fc2bec7b..45d7e533 100755 --- a/host/rootfs/image/usr/bin/create-vm-dependencies +++ b/host/rootfs/image/usr/bin/create-vm-dependencies @@ -5,8 +5,8 @@ if { mkdir -p /run/doc/${1}/doc - /run/vm/by-id/${1}/fs/config - /run/vm/by-id/${1}/fs/doc + /run/fs/${1}/config + /run/fs/${1}/doc /run/vm/by-id/${1}/ns } @@ -20,18 +20,19 @@ if { --mount=/run/vm/by-id/${1}/ns/mnt --user=/run/vm/by-id/${1}/ns/user - if { mount --make-shared --rbind /run/vm/by-id/${1} /run/vm/by-id/${1} } - # The VM should not be able to write directly into a tmpfs, and the host # should be able to assume there are no untrusted symlinks there, but there # can be writable block-based bind mounted subdirectories. - if { mount --rbind -o nofail /run/vm/by-id/${1}/config/fs /run/vm/by-id/${1}/fs/config } - if { mount --rbind -o ro /run/vm/by-id/${1}/fs /run/vm/by-id/${1}/fs } + + # Needs to be shared so that additional mounts under config/ (e.g. from + # mount-flatpak) will be propagated into the virtiofsd sandbox. + if { mount --make-shared --rbind -o nofail /run/vm/by-id/${1}/config/fs /run/fs/${1}/config } + if { mount --rbind -o ro /run/fs/${1} /run/fs/${1} } # Needs to be shared so that when xdg-document-portal mounts its fuse # filesystem at /run/doc/${1}/doc, it will propagate to /run/fs/${1}/doc. if { mount --make-shared --rbind /run/doc/${1} /run/doc/${1} } - mount --rbind /run/doc/${1}/doc /run/vm/by-id/${1}/fs/doc + mount --rbind /run/doc/${1}/doc /run/fs/${1}/doc } if { s6-instance-create /run/service/vm-services $1 } diff --git a/host/rootfs/image/usr/bin/run-appimage b/host/rootfs/image/usr/bin/run-appimage index 44a683c3..dba09e19 100755 --- a/host/rootfs/image/usr/bin/run-appimage +++ b/host/rootfs/image/usr/bin/run-appimage @@ -20,7 +20,7 @@ if { create-vm-dependencies $id } if { nsenter --mount=${dir}/ns/mnt - cd ${dir}/fs/config + cd /run/fs/${id}/config if { redirfd -w 1 type echo appimage } if { touch run } mount --bind $1 run diff --git a/host/rootfs/image/usr/bin/run-flatpak b/host/rootfs/image/usr/bin/run-flatpak index 07cfc262..707f3c1c 100755 --- a/host/rootfs/image/usr/bin/run-flatpak +++ b/host/rootfs/image/usr/bin/run-flatpak @@ -23,7 +23,7 @@ if { if { nsenter --mount=${dir}/ns/mnt - cd ${dir}/fs/config + cd /run/fs/${id}/config if { redirfd -w 1 type echo flatpak } mount-flatpak $@ } diff --git a/host/rootfs/image/usr/bin/spectrum-update b/host/rootfs/image/usr/bin/spectrum-update index be99c9da..538e0b16 100755 --- a/host/rootfs/image/usr/bin/spectrum-update +++ b/host/rootfs/image/usr/bin/spectrum-update @@ -43,11 +43,11 @@ foreground { # mounts instead of rm -rf. Once this code is in a separate mount # namespace, the copies should be replaced by bind mounts. if { - if { rm -rf -- /run/vm/by-id/${update_vm_id}/fs/etc } + if { rm -rf -- /run/fs/${update_vm_id}/etc } umask 022 - if { mkdir -p -- /run/vm/by-id/${update_vm_id}/fs/updates /run/vm/by-id/${update_vm_id}/fs/etc/systemd } - if { cp -R -- /etc/vm-sysupdate.d /etc/update-url /run/vm/by-id/${update_vm_id}/fs/etc } - cp -- /etc/systemd/import-pubring.gpg /run/vm/by-id/${update_vm_id}/fs/etc/systemd + if { mkdir -p -- /run/fs/${update_vm_id}/updates /run/fs/${update_vm_id}/etc/systemd } + if { cp -R -- /etc/vm-sysupdate.d /etc/update-url /run/fs/${update_vm_id}/etc } + cp -- /etc/systemd/import-pubring.gpg /run/fs/${update_vm_id}/etc/systemd } nsenter --mount=/run/vm/by-id/${update_vm_id}/ns/mnt @@ -55,10 +55,10 @@ foreground { # If the directory is already mounted, unmount it. This prevents a # confusing error from mount. - foreground { redirfd -w 2 /dev/null umount -- /run/vm/by-id/${update_vm_id}/fs/updates } + foreground { redirfd -w 2 /dev/null umount -- /run/fs/${update_vm_id}/updates } # Share the update directory with the VM. - if { mount --bind -- shared /run/vm/by-id/${update_vm_id}/fs/updates } + if { mount --bind -- shared /run/fs/${update_vm_id}/updates } # Start the update VM. if { vm-start $update_vm_id } @@ -69,7 +69,7 @@ foreground { if { s6-svwait -D /run/service/vmm/instance/${update_vm_id} } # Remove the bind mount. - if { umount -- /run/vm/by-id/${update_vm_id}/fs/updates } + if { umount -- /run/fs/${update_vm_id}/updates } # Ensure that the VM cannot change the directory # while systemd-sysupdate is using it. -- 2.51.0
We'd like these to be non-root, but xdg-document-portal in particular still needs to be root within its namespace so it can mount a fuse filesystem. We therefore map the fs user in the host namespace to root in the new namespace, and pass through every non-root user so non-root users (e.g. for xdg-desktop-portal-spectrum) are still usable within the namespace. Signed-off-by: Alyssa Ross <hi@alyssa.is> --- v2: no change .../image/etc/s6-linux-init/run-image/etc/group | 1 + .../image/etc/s6-linux-init/run-image/etc/passwd | 1 + .../vm-services/template/data/service/dbus/run | 6 +++++- .../template/data/service/vhost-user-fs/run | 7 ++++++- .../service/xdg-desktop-portal-spectrum-host/run | 6 ++++++ host/rootfs/image/usr/bin/create-vm-dependencies | 13 +++++++++---- host/rootfs/image/usr/bin/run-flatpak | 8 ++++++-- 7 files changed, 34 insertions(+), 8 deletions(-) diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/etc/group b/host/rootfs/image/etc/s6-linux-init/run-image/etc/group index 019f5525..6e894d93 100644 --- a/host/rootfs/image/etc/s6-linux-init/run-image/etc/group +++ b/host/rootfs/image/etc/s6-linux-init/run-image/etc/group @@ -14,3 +14,4 @@ cdrom:x:12: tape:x:13: kvm:x:14: wayland:x:15:wayland +fs:x:1000: diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/etc/passwd b/host/rootfs/image/etc/s6-linux-init/run-image/etc/passwd index 50def56d..dc104ec1 100644 --- a/host/rootfs/image/etc/s6-linux-init/run-image/etc/passwd +++ b/host/rootfs/image/etc/s6-linux-init/run-image/etc/passwd @@ -1,2 +1,3 @@ root:x:0:0:System administrator:/:/bin/sh wayland:x:15:15:Wayland compositor:/:/bin/nologin +fs:x:1000:1000:Spectrum files:/:/bin/nologin diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run index f4c78f71..3dffa1f4 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run @@ -14,8 +14,12 @@ s6-ipcserver-socketbinder -B /run/portal-bus/${VM} fdmove -c 3 0 redirfd -r 0 /dev/null +s6-envuidgid fs +s6-applyuidgid -Uzu 0 getcwd -E dir -nsenter --mount=/run/vm/by-id/${VM}/ns/mnt +nsenter --preserve-credentials -S0 + --mount=/run/vm/by-id/${VM}/ns/mnt + --user=/run/vm/by-id/${VM}/ns/user unshare --cgroup --ipc --net --uts diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run index 3446dcc2..aa2b8cc1 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run @@ -10,9 +10,14 @@ redirfd -r 0 /dev/null export TMPDIR /run +s6-envuidgid fs +s6-applyuidgid -Uzu 0 importas -i VM VM +nsenter --preserve-credentials -S0 + --mount=/run/vm/by-id/${VM}/ns/mnt + --user=/run/vm/by-id/${VM}/ns/user -nsenter --mount=/run/vm/by-id/${VM}/ns/mnt +# Show the guest files owned by uid/gid 1000. unshare -U --map-user 1000 --map-group 1000 --uts --ipc --cgroup virtiofsd --fd 3 --shared-dir /run/fs/${VM} diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run index b83d23dd..42c29b3b 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run @@ -13,6 +13,12 @@ s6-ipcserver-socketbinder -a 0700 /run/vsock/${VM}/vsock_219 if { fdmove 1 3 echo } fdclose 3 +s6-envuidgid fs +s6-applyuidgid -Uzu 0 +nsenter --preserve-credentials -S0 + --mount=/run/vm/by-id/${VM}/ns/mnt + --user=/run/vm/by-id/${VM}/ns/user + s6-setuidgid xdp-spectrum-${VM} xdg-desktop-portal-spectrum-host diff --git a/host/rootfs/image/usr/bin/create-vm-dependencies b/host/rootfs/image/usr/bin/create-vm-dependencies index 45d7e533..b56a4bc5 100755 --- a/host/rootfs/image/usr/bin/create-vm-dependencies +++ b/host/rootfs/image/usr/bin/create-vm-dependencies @@ -14,9 +14,14 @@ if { mount --make-private --rbind /run/vm/by-id/${1}/ns /run/vm/by-id/${1}/ns } if { touch /run/vm/by-id/${1}/ns/mnt /run/vm/by-id/${1}/ns/user } if { - unshare --propagation=slave - --map-users all - --map-groups all + redirfd -r 3 /run/vm/by-id/${1}/config + + s6-envuidgid fs + s6-applyuidgid -Uzu 0 + + unshare -S0 --propagation=slave + --map-users 0:1000:1 --map-users 1:1:999 --map-users 1001:1001:4294966294 + --map-groups 0:1000:1 --map-groups 1:1:999 --map-groups 1001:1001:4294966294 --mount=/run/vm/by-id/${1}/ns/mnt --user=/run/vm/by-id/${1}/ns/user @@ -26,7 +31,7 @@ if { # Needs to be shared so that additional mounts under config/ (e.g. from # mount-flatpak) will be propagated into the virtiofsd sandbox. - if { mount --make-shared --rbind -o nofail /run/vm/by-id/${1}/config/fs /run/fs/${1}/config } + if { mount --make-shared --rbind -o nofail /proc/self/fd/3/fs /run/fs/${1}/config } if { mount --rbind -o ro /run/fs/${1} /run/fs/${1} } # Needs to be shared so that when xdg-document-portal mounts its fuse diff --git a/host/rootfs/image/usr/bin/run-flatpak b/host/rootfs/image/usr/bin/run-flatpak index 707f3c1c..d7926ad5 100755 --- a/host/rootfs/image/usr/bin/run-flatpak +++ b/host/rootfs/image/usr/bin/run-flatpak @@ -10,7 +10,7 @@ if { useradd -P /run -Urd / -s /bin/nologin xdp-spectrum-${id} } if { elgetpositionals - if { mkdir -p /run/configs/${id}/fs } + if { install -do fs /run/configs/${id}/fs } if { ln -s /usr/lib/spectrum/img/appvm/blk /usr/lib/spectrum/img/appvm/vmlinux @@ -22,7 +22,11 @@ if { if { create-vm-dependencies $id } if { - nsenter --mount=${dir}/ns/mnt + s6-envuidgid fs + s6-applyuidgid -Uzu 0 + nsenter --preserve-credentials -S0 + --mount=/run/vm/by-id/${id}/ns/mnt + --user=/run/vm/by-id/${id}/ns/user cd /run/fs/${id}/config if { redirfd -w 1 type echo flatpak } mount-flatpak $@ -- 2.51.0
participants (2)
-
Alyssa Ross -
Demi Marie Obenour