* [PATCH 2/8] host/rootfs: move vsock sockets out of VM dir
2025-12-10 12:47 [PATCH 1/8] host/rootfs: create dbus socket externally Alyssa Ross
@ 2025-12-10 12:47 ` Alyssa Ross
2025-12-10 12:47 ` [PATCH 3/8] host/rootfs: move portal bus socket " Alyssa Ross
` (5 subsequent siblings)
6 siblings, 0 replies; 21+ messages in thread
From: Alyssa Ross @ 2025-12-10 12:47 UTC (permalink / raw)
To: devel
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>
---
.../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
^ permalink raw reply related [flat|nested] 21+ messages in thread* [PATCH 3/8] host/rootfs: move portal bus socket out of VM dir
2025-12-10 12:47 [PATCH 1/8] host/rootfs: create dbus socket externally Alyssa Ross
2025-12-10 12:47 ` [PATCH 2/8] host/rootfs: move vsock sockets out of VM dir Alyssa Ross
@ 2025-12-10 12:47 ` Alyssa Ross
2025-12-10 12:47 ` [PATCH 4/8] host/rootfs: run xdg-desktop-portal-spectrum-host as non-root Alyssa Ross
` (4 subsequent siblings)
6 siblings, 0 replies; 21+ messages in thread
From: Alyssa Ross @ 2025-12-10 12:47 UTC (permalink / raw)
To: devel
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>
---
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
^ permalink raw reply related [flat|nested] 21+ messages in thread* [PATCH 4/8] host/rootfs: run xdg-desktop-portal-spectrum-host as non-root
2025-12-10 12:47 [PATCH 1/8] host/rootfs: create dbus socket externally Alyssa Ross
2025-12-10 12:47 ` [PATCH 2/8] host/rootfs: move vsock sockets out of VM dir Alyssa Ross
2025-12-10 12:47 ` [PATCH 3/8] host/rootfs: move portal bus socket " Alyssa Ross
@ 2025-12-10 12:47 ` Alyssa Ross
2025-12-10 17:26 ` Demi Marie Obenour
2025-12-10 12:47 ` [PATCH 5/8] host/rootfs: create a per-VM user namespace Alyssa Ross
` (3 subsequent siblings)
6 siblings, 1 reply; 21+ messages in thread
From: Alyssa Ross @ 2025-12-10 12:47 UTC (permalink / raw)
To: devel
Signed-off-by: Alyssa Ross <hi@alyssa.is>
---
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
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 4/8] host/rootfs: run xdg-desktop-portal-spectrum-host as non-root
2025-12-10 12:47 ` [PATCH 4/8] host/rootfs: run xdg-desktop-portal-spectrum-host as non-root Alyssa Ross
@ 2025-12-10 17:26 ` Demi Marie Obenour
2025-12-11 12:19 ` Alyssa Ross
0 siblings, 1 reply; 21+ messages in thread
From: Demi Marie Obenour @ 2025-12-10 17:26 UTC (permalink / raw)
To: Alyssa Ross, devel
[-- Attachment #1.1.1: Type: text/plain, Size: 4312 bytes --]
On 12/10/25 07:47, Alyssa Ross wrote:
> Signed-off-by: Alyssa Ross <hi@alyssa.is>
> ---
> 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
> +}
This makes me nervous. I know that $VM is trusted, but I'd feel
better if this was validated with a case command. There's a bug in
case that makes this not work properly, but that's fixed in execline
git right now.
> 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:
(snip)
> 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
It's possible to avoid the race using extended ACLs.
> +}
> +exit $?
--
Sincerely,
Demi Marie Obenour (she/her/hers)
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 7253 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH 4/8] host/rootfs: run xdg-desktop-portal-spectrum-host as non-root
2025-12-10 17:26 ` Demi Marie Obenour
@ 2025-12-11 12:19 ` Alyssa Ross
2025-12-11 14:05 ` Alyssa Ross
2025-12-12 17:54 ` Demi Marie Obenour
0 siblings, 2 replies; 21+ messages in thread
From: Alyssa Ross @ 2025-12-11 12:19 UTC (permalink / raw)
To: Demi Marie Obenour; +Cc: devel
[-- Attachment #1: Type: text/plain, Size: 4186 bytes --]
Demi Marie Obenour <demiobenour@gmail.com> writes:
> On 12/10/25 07:47, Alyssa Ross wrote:
>> Signed-off-by: Alyssa Ross <hi@alyssa.is>
>> ---
>> 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
>> +}
>
> This makes me nervous. I know that $VM is trusted, but I'd feel
> better if this was validated with a case command. There's a bug in
> case that makes this not work properly, but that's fixed in execline
> git right now.
I don't think this is necessary, because as you say it's trusted. There
shouldn't be any way to invoke this script with elevated permissions
anyway, so it's not doing anything that whatever is invoking it couldn't
just do themself.
>> 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
>
> It's possible to avoid the race using extended ACLs.
Nice idea!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH 4/8] host/rootfs: run xdg-desktop-portal-spectrum-host as non-root
2025-12-11 12:19 ` Alyssa Ross
@ 2025-12-11 14:05 ` Alyssa Ross
2025-12-12 17:54 ` Demi Marie Obenour
1 sibling, 0 replies; 21+ messages in thread
From: Alyssa Ross @ 2025-12-11 14:05 UTC (permalink / raw)
To: Demi Marie Obenour; +Cc: devel
[-- Attachment #1: Type: text/plain, Size: 2128 bytes --]
Alyssa Ross <hi@alyssa.is> writes:
> Demi Marie Obenour <demiobenour@gmail.com> writes:
>
>> On 12/10/25 07:47, Alyssa Ross wrote:
>>> 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
>>
>> It's possible to avoid the race using extended ACLs.
>
> Nice idea!
Actually I don't think it is, sadly. Even with acls like the following,
when Cloud Hypervisor creates its socket, the mask ends up getting set
to ---, so xdp-spectrum-host still can't connect. See also[1].
# file: run/vsock/GeOkfl
# owner: root
# group: root
user::rwx
group::r-x
other::r-x
default:user::rwx
default:user:xdp-spectrum-GeOkfl:rwx
default:group::r-x
default:mask::rwx
default:other::r-x
Even making the directory setgid wouldn't help, because the effective
mask applies to /all/ groups. I don't think there's a way to do this at
the moment without either setting a less restrictive umask on Cloud
Hypervisor, or the approach I sent here.
[1]: https://serverfault.com/questions/833349/why-is-my-unix-socket-created-with-a-different-acl-mask-to-other-files
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH 4/8] host/rootfs: run xdg-desktop-portal-spectrum-host as non-root
2025-12-11 12:19 ` Alyssa Ross
2025-12-11 14:05 ` Alyssa Ross
@ 2025-12-12 17:54 ` Demi Marie Obenour
1 sibling, 0 replies; 21+ messages in thread
From: Demi Marie Obenour @ 2025-12-12 17:54 UTC (permalink / raw)
To: Alyssa Ross; +Cc: devel
[-- Attachment #1.1.1: Type: text/plain, Size: 3281 bytes --]
On 12/11/25 07:19, Alyssa Ross wrote:
> Demi Marie Obenour <demiobenour@gmail.com> writes:
>
>> On 12/10/25 07:47, Alyssa Ross wrote:
>>> Signed-off-by: Alyssa Ross <hi@alyssa.is>
>>> ---
>>> 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
>>> +}
>>
>> This makes me nervous. I know that $VM is trusted, but I'd feel
>> better if this was validated with a case command. There's a bug in
>> case that makes this not work properly, but that's fixed in execline
>> git right now.
>
> I don't think this is necessary, because as you say it's trusted. There
> shouldn't be any way to invoke this script with elevated permissions
> anyway, so it's not doing anything that whatever is invoking it couldn't
> just do themself.
It's more that I prefer to avoid unnecessary places where bad input
can lead to code execution. Using awk to substitute would also make
this easy.
--
Sincerely,
Demi Marie Obenour (she/her/hers)
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 7253 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 5/8] host/rootfs: create a per-VM user namespace
2025-12-10 12:47 [PATCH 1/8] host/rootfs: create dbus socket externally Alyssa Ross
` (2 preceding siblings ...)
2025-12-10 12:47 ` [PATCH 4/8] host/rootfs: run xdg-desktop-portal-spectrum-host as non-root Alyssa Ross
@ 2025-12-10 12:47 ` Alyssa Ross
2025-12-10 17:39 ` Demi Marie Obenour
2025-12-10 12:47 ` [PATCH 6/8] host/rootfs: move xdp runtime dir out of VM dir Alyssa Ross
` (2 subsequent siblings)
6 siblings, 1 reply; 21+ messages in thread
From: Alyssa Ross @ 2025-12-10 12:47 UTC (permalink / raw)
To: devel
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>
---
host/rootfs/image/usr/bin/create-vm-dependencies | 9 +++++++--
host/rootfs/image/usr/bin/run-appimage | 2 ++
host/rootfs/image/usr/bin/run-flatpak | 2 ++
3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/host/rootfs/image/usr/bin/create-vm-dependencies b/host/rootfs/image/usr/bin/create-vm-dependencies
index d4a10ab4..7ce19ed2 100755
--- a/host/rootfs/image/usr/bin/create-vm-dependencies
+++ b/host/rootfs/image/usr/bin/create-vm-dependencies
@@ -2,8 +2,9 @@
# SPDX-License-Identifier: EUPL-1.2+
# SPDX-FileCopyrightText: 2024-2025 Alyssa Ross <hi@alyssa.is>
-if { touch /run/vm/by-id/${1}/mount }
+if { touch /run/vm/by-id/${1}/mount /run/vm/by-id/${1}/user }
if { mount --make-private --bind /run/vm/by-id/${1}/mount /run/vm/by-id/${1}/mount }
+if { mount --make-private --bind /run/vm/by-id/${1}/user /run/vm/by-id/${1}/user }
if {
mkdir -p
@@ -13,7 +14,11 @@ if {
}
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}/mount
+ --user=/run/vm/by-id/${1}/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..5e8e29fa 100755
--- a/host/rootfs/image/usr/bin/run-appimage
+++ b/host/rootfs/image/usr/bin/run-appimage
@@ -44,4 +44,6 @@ if { s6-instance-delete /run/service/vm-services $id }
if { umount ${dir}/mount } # mount namespace
if { umount ${dir}/mount } # private bind mount
+if { umount ${dir}/user } # user namespace
+if { umount ${dir}/user } # private bind mount
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..86ccc12a 100755
--- a/host/rootfs/image/usr/bin/run-flatpak
+++ b/host/rootfs/image/usr/bin/run-flatpak
@@ -46,4 +46,6 @@ if { s6-instance-delete -- /run/service/vm-services $id }
if { umount ${dir}/mount } # mount namespace
if { umount ${dir}/mount } # private bind mount
+if { umount ${dir}/user } # user namespace
+if { umount ${dir}/user } # private bind mount
rm -r $dir /run/configs/${id}
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 5/8] host/rootfs: create a per-VM user namespace
2025-12-10 12:47 ` [PATCH 5/8] host/rootfs: create a per-VM user namespace Alyssa Ross
@ 2025-12-10 17:39 ` Demi Marie Obenour
2025-12-11 12:41 ` Alyssa Ross
0 siblings, 1 reply; 21+ messages in thread
From: Demi Marie Obenour @ 2025-12-10 17:39 UTC (permalink / raw)
To: Alyssa Ross, devel
[-- Attachment #1.1.1: Type: text/plain, Size: 1558 bytes --]
On 12/10/25 07:47, 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>
(snip)
> diff --git a/host/rootfs/image/usr/bin/run-appimage b/host/rootfs/image/usr/bin/run-appimage
> index 47cab4c5..5e8e29fa 100755
> --- a/host/rootfs/image/usr/bin/run-appimage
> +++ b/host/rootfs/image/usr/bin/run-appimage
> @@ -44,4 +44,6 @@ if { s6-instance-delete /run/service/vm-services $id }
>
> if { umount ${dir}/mount } # mount namespace
> if { umount ${dir}/mount } # private bind mount
> +if { umount ${dir}/user } # user namespace
> +if { umount ${dir}/user } # private bind mount
> 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..86ccc12a 100755
> --- a/host/rootfs/image/usr/bin/run-flatpak
> +++ b/host/rootfs/image/usr/bin/run-flatpak
> @@ -46,4 +46,6 @@ if { s6-instance-delete -- /run/service/vm-services $id }
>
> if { umount ${dir}/mount } # mount namespace
> if { umount ${dir}/mount } # private bind mount
> +if { umount ${dir}/user } # user namespace
> +if { umount ${dir}/user } # private bind mount
> rm -r $dir /run/configs/${id}
Why is it necessary to unmount twice here?
--
Sincerely,
Demi Marie Obenour (she/her/hers)
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 7253 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH 5/8] host/rootfs: create a per-VM user namespace
2025-12-10 17:39 ` Demi Marie Obenour
@ 2025-12-11 12:41 ` Alyssa Ross
2025-12-12 17:51 ` Demi Marie Obenour
0 siblings, 1 reply; 21+ messages in thread
From: Alyssa Ross @ 2025-12-11 12:41 UTC (permalink / raw)
To: Demi Marie Obenour; +Cc: devel
[-- Attachment #1: Type: text/plain, Size: 2205 bytes --]
Demi Marie Obenour <demiobenour@gmail.com> writes:
> On 12/10/25 07:47, 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>
>
> (snip)
>
>> diff --git a/host/rootfs/image/usr/bin/run-appimage b/host/rootfs/image/usr/bin/run-appimage
>> index 47cab4c5..5e8e29fa 100755
>> --- a/host/rootfs/image/usr/bin/run-appimage
>> +++ b/host/rootfs/image/usr/bin/run-appimage
>> @@ -44,4 +44,6 @@ if { s6-instance-delete /run/service/vm-services $id }
>>
>> if { umount ${dir}/mount } # mount namespace
>> if { umount ${dir}/mount } # private bind mount
>> +if { umount ${dir}/user } # user namespace
>> +if { umount ${dir}/user } # private bind mount
>> 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..86ccc12a 100755
>> --- a/host/rootfs/image/usr/bin/run-flatpak
>> +++ b/host/rootfs/image/usr/bin/run-flatpak
>> @@ -46,4 +46,6 @@ if { s6-instance-delete -- /run/service/vm-services $id }
>>
>> if { umount ${dir}/mount } # mount namespace
>> if { umount ${dir}/mount } # private bind mount
>> +if { umount ${dir}/user } # user namespace
>> +if { umount ${dir}/user } # private bind mount
>> rm -r $dir /run/configs/${id}
>
> Why is it necessary to unmount twice here?
Because we mount twice, just like the comments say. It is a bit
counterintuitive though. Namespaces can only be mounted onto a
mountpoint that itself has private propagation. This is why we create a
private bind mount at the start of create-vm-dependencies before unshare
bind mounts the namespaces. You can also see this in an example in
unshare(1).
Perhaps it would be better and clearer to have /run/vm/by-id/${VM}/ns as
a private mountpoint, with the nsfs files inside? That way, each of
them only needs to be unmounted once, and then the ns directory also has
to be unmounted once.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH 5/8] host/rootfs: create a per-VM user namespace
2025-12-11 12:41 ` Alyssa Ross
@ 2025-12-12 17:51 ` Demi Marie Obenour
2025-12-12 17:56 ` Alyssa Ross
0 siblings, 1 reply; 21+ messages in thread
From: Demi Marie Obenour @ 2025-12-12 17:51 UTC (permalink / raw)
To: Alyssa Ross; +Cc: devel
[-- Attachment #1.1.1: Type: text/plain, Size: 2400 bytes --]
On 12/11/25 07:41, Alyssa Ross wrote:
> Demi Marie Obenour <demiobenour@gmail.com> writes:
>
>> On 12/10/25 07:47, 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>
>>
>> (snip)
>>
>>> diff --git a/host/rootfs/image/usr/bin/run-appimage b/host/rootfs/image/usr/bin/run-appimage
>>> index 47cab4c5..5e8e29fa 100755
>>> --- a/host/rootfs/image/usr/bin/run-appimage
>>> +++ b/host/rootfs/image/usr/bin/run-appimage
>>> @@ -44,4 +44,6 @@ if { s6-instance-delete /run/service/vm-services $id }
>>>
>>> if { umount ${dir}/mount } # mount namespace
>>> if { umount ${dir}/mount } # private bind mount
>>> +if { umount ${dir}/user } # user namespace
>>> +if { umount ${dir}/user } # private bind mount
>>> 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..86ccc12a 100755
>>> --- a/host/rootfs/image/usr/bin/run-flatpak
>>> +++ b/host/rootfs/image/usr/bin/run-flatpak
>>> @@ -46,4 +46,6 @@ if { s6-instance-delete -- /run/service/vm-services $id }
>>>
>>> if { umount ${dir}/mount } # mount namespace
>>> if { umount ${dir}/mount } # private bind mount
>>> +if { umount ${dir}/user } # user namespace
>>> +if { umount ${dir}/user } # private bind mount
>>> rm -r $dir /run/configs/${id}
>>
>> Why is it necessary to unmount twice here?
>
> Because we mount twice, just like the comments say. It is a bit
> counterintuitive though. Namespaces can only be mounted onto a
> mountpoint that itself has private propagation. This is why we create a
> private bind mount at the start of create-vm-dependencies before unshare
> bind mounts the namespaces. You can also see this in an example in
> unshare(1).
>
> Perhaps it would be better and clearer to have /run/vm/by-id/${VM}/ns as
> a private mountpoint, with the nsfs files inside? That way, each of
> them only needs to be unmounted once, and then the ns directory also has
> to be unmounted once.
I think it would be easier to understand.
--
Sincerely,
Demi Marie Obenour (she/her/hers)
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 7253 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH 5/8] host/rootfs: create a per-VM user namespace
2025-12-12 17:51 ` Demi Marie Obenour
@ 2025-12-12 17:56 ` Alyssa Ross
0 siblings, 0 replies; 21+ messages in thread
From: Alyssa Ross @ 2025-12-12 17:56 UTC (permalink / raw)
To: Demi Marie Obenour; +Cc: devel
[-- Attachment #1: Type: text/plain, Size: 2579 bytes --]
Demi Marie Obenour <demiobenour@gmail.com> writes:
> On 12/11/25 07:41, Alyssa Ross wrote:
>> Demi Marie Obenour <demiobenour@gmail.com> writes:
>>
>>> On 12/10/25 07:47, 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>
>>>
>>> (snip)
>>>
>>>> diff --git a/host/rootfs/image/usr/bin/run-appimage b/host/rootfs/image/usr/bin/run-appimage
>>>> index 47cab4c5..5e8e29fa 100755
>>>> --- a/host/rootfs/image/usr/bin/run-appimage
>>>> +++ b/host/rootfs/image/usr/bin/run-appimage
>>>> @@ -44,4 +44,6 @@ if { s6-instance-delete /run/service/vm-services $id }
>>>>
>>>> if { umount ${dir}/mount } # mount namespace
>>>> if { umount ${dir}/mount } # private bind mount
>>>> +if { umount ${dir}/user } # user namespace
>>>> +if { umount ${dir}/user } # private bind mount
>>>> 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..86ccc12a 100755
>>>> --- a/host/rootfs/image/usr/bin/run-flatpak
>>>> +++ b/host/rootfs/image/usr/bin/run-flatpak
>>>> @@ -46,4 +46,6 @@ if { s6-instance-delete -- /run/service/vm-services $id }
>>>>
>>>> if { umount ${dir}/mount } # mount namespace
>>>> if { umount ${dir}/mount } # private bind mount
>>>> +if { umount ${dir}/user } # user namespace
>>>> +if { umount ${dir}/user } # private bind mount
>>>> rm -r $dir /run/configs/${id}
>>>
>>> Why is it necessary to unmount twice here?
>>
>> Because we mount twice, just like the comments say. It is a bit
>> counterintuitive though. Namespaces can only be mounted onto a
>> mountpoint that itself has private propagation. This is why we create a
>> private bind mount at the start of create-vm-dependencies before unshare
>> bind mounts the namespaces. You can also see this in an example in
>> unshare(1).
>>
>> Perhaps it would be better and clearer to have /run/vm/by-id/${VM}/ns as
>> a private mountpoint, with the nsfs files inside? That way, each of
>> them only needs to be unmounted once, and then the ns directory also has
>> to be unmounted once.
>
> I think it would be easier to understand.
Then you will like v2!
https://spectrum-os.org/lists/archives/spectrum-devel/20251211162145.124509-10-hi@alyssa.is/
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 6/8] host/rootfs: move xdp runtime dir out of VM dir
2025-12-10 12:47 [PATCH 1/8] host/rootfs: create dbus socket externally Alyssa Ross
` (3 preceding siblings ...)
2025-12-10 12:47 ` [PATCH 5/8] host/rootfs: create a per-VM user namespace Alyssa Ross
@ 2025-12-10 12:47 ` Alyssa Ross
2025-12-10 17:43 ` Demi Marie Obenour
2025-12-10 12:47 ` [PATCH 7/8] host/rootfs: move fs directory out of VM directory Alyssa Ross
2025-12-10 12:47 ` [PATCH 8/8] host/rootfs: run filesystem daemons as non-root Alyssa Ross
6 siblings, 1 reply; 21+ messages in thread
From: Alyssa Ross @ 2025-12-10 12:47 UTC (permalink / raw)
To: devel
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>
---
host/rootfs/image/usr/bin/create-vm-dependencies | 6 ++++--
.../services/org.freedesktop.portal.Documents.service | 2 +-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/host/rootfs/image/usr/bin/create-vm-dependencies b/host/rootfs/image/usr/bin/create-vm-dependencies
index 7ce19ed2..98f10489 100755
--- a/host/rootfs/image/usr/bin/create-vm-dependencies
+++ b/host/rootfs/image/usr/bin/create-vm-dependencies
@@ -8,7 +8,7 @@ if { mount --make-private --bind /run/vm/by-id/${1}/user /run/vm/by-id/${1}/user
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
}
@@ -27,7 +27,9 @@ 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
+
+ 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
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 6/8] host/rootfs: move xdp runtime dir out of VM dir
2025-12-10 12:47 ` [PATCH 6/8] host/rootfs: move xdp runtime dir out of VM dir Alyssa Ross
@ 2025-12-10 17:43 ` Demi Marie Obenour
2025-12-11 12:47 ` Alyssa Ross
0 siblings, 1 reply; 21+ messages in thread
From: Demi Marie Obenour @ 2025-12-10 17:43 UTC (permalink / raw)
To: Alyssa Ross, devel
[-- Attachment #1.1.1: Type: text/plain, Size: 1343 bytes --]
On 12/10/25 07:47, Alyssa Ross wrote:
> 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>
> ---
> host/rootfs/image/usr/bin/create-vm-dependencies | 6 ++++--
> .../services/org.freedesktop.portal.Documents.service | 2 +-
> 2 files changed, 5 insertions(+), 3 deletions(-)
>
(snip)
> @@ -27,7 +27,9 @@ 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
> +
> + if { mount --make-shared --rbind /run/doc/${1} /run/doc/${1} }
> + mount --rbind /run/doc/${1}/doc /run/vm/by-id/${1}/fs/doc
> }
This could definitely use a lot more comments. For instance, why is
--make-shared needed? What about --rbind?
I trust that you tested this code and it works, but it isn't obvious
*why* it works or why it must be written this way.
It would be best to have a document explaining what all of the mount
points and namespaces are, why they are as they are, and what mount
propagation is involved.
--
Sincerely,
Demi Marie Obenour (she/her/hers)
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 7253 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH 6/8] host/rootfs: move xdp runtime dir out of VM dir
2025-12-10 17:43 ` Demi Marie Obenour
@ 2025-12-11 12:47 ` Alyssa Ross
2025-12-11 13:06 ` Alyssa Ross
0 siblings, 1 reply; 21+ messages in thread
From: Alyssa Ross @ 2025-12-11 12:47 UTC (permalink / raw)
To: Demi Marie Obenour, devel
[-- Attachment #1: Type: text/plain, Size: 1493 bytes --]
Demi Marie Obenour <demiobenour@gmail.com> writes:
> On 12/10/25 07:47, Alyssa Ross wrote:
>> 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>
>> ---
>> host/rootfs/image/usr/bin/create-vm-dependencies | 6 ++++--
>> .../services/org.freedesktop.portal.Documents.service | 2 +-
>> 2 files changed, 5 insertions(+), 3 deletions(-)
>>
>
> (snip)
>
>> @@ -27,7 +27,9 @@ 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
>> +
>> + if { mount --make-shared --rbind /run/doc/${1} /run/doc/${1} }
>> + mount --rbind /run/doc/${1}/doc /run/vm/by-id/${1}/fs/doc
>> }
>
> This could definitely use a lot more comments. For instance, why is
> --make-shared needed? What about --rbind?
>
> I trust that you tested this code and it works, but it isn't obvious
> *why* it works or why it must be written this way.
>
> It would be best to have a document explaining what all of the mount
> points and namespaces are, why they are as they are, and what mount
> propagation is involved.
I think a separate document would quickly go out of date, but I'm happy
to add some comments inline.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH 6/8] host/rootfs: move xdp runtime dir out of VM dir
2025-12-11 12:47 ` Alyssa Ross
@ 2025-12-11 13:06 ` Alyssa Ross
0 siblings, 0 replies; 21+ messages in thread
From: Alyssa Ross @ 2025-12-11 13:06 UTC (permalink / raw)
To: Demi Marie Obenour; +Cc: devel
[-- Attachment #1: Type: text/plain, Size: 2384 bytes --]
Alyssa Ross <hi@alyssa.is> writes:
> Demi Marie Obenour <demiobenour@gmail.com> writes:
>
>> On 12/10/25 07:47, Alyssa Ross wrote:
>>> 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>
>>> ---
>>> host/rootfs/image/usr/bin/create-vm-dependencies | 6 ++++--
>>> .../services/org.freedesktop.portal.Documents.service | 2 +-
>>> 2 files changed, 5 insertions(+), 3 deletions(-)
>>>
>>
>> (snip)
>>
>>> @@ -27,7 +27,9 @@ 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
>>> +
>>> + if { mount --make-shared --rbind /run/doc/${1} /run/doc/${1} }
>>> + mount --rbind /run/doc/${1}/doc /run/vm/by-id/${1}/fs/doc
>>> }
>>
>> This could definitely use a lot more comments. For instance, why is
>> --make-shared needed? What about --rbind?
>>
>> I trust that you tested this code and it works, but it isn't obvious
>> *why* it works or why it must be written this way.
>>
>> It would be best to have a document explaining what all of the mount
>> points and namespaces are, why they are as they are, and what mount
>> propagation is involved.
>
> I think a separate document would quickly go out of date, but I'm happy
> to add some comments inline.
--rbind is perhaps worth discussing. I consider it best practice to
always use --rbind over --bind, because generally the idea with a bind
mount is to copy a whole hierarchy from one place to another. With
--bind you have to know the internal structure of that hierarchy and be
sure you only want the top-level mount; with --rbind you just think in
terms of the hierarchy. There are also some situations where it's
mandatory to use --rbind: where a --bind would reveal hierarchies in the
mountpoint that have been hidden by extra bind mounts being placed over
the top.
(I won't put this in a comment here because we use --rbind all over the
place, but it's something that would make sense to put into developer
guidelines once we have a documentation structure that accomodates such
a thing.)
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 7/8] host/rootfs: move fs directory out of VM directory
2025-12-10 12:47 [PATCH 1/8] host/rootfs: create dbus socket externally Alyssa Ross
` (4 preceding siblings ...)
2025-12-10 12:47 ` [PATCH 6/8] host/rootfs: move xdp runtime dir out of VM dir Alyssa Ross
@ 2025-12-10 12:47 ` Alyssa Ross
2025-12-10 12:47 ` [PATCH 8/8] host/rootfs: run filesystem daemons as non-root Alyssa Ross
6 siblings, 0 replies; 21+ messages in thread
From: Alyssa Ross @ 2025-12-10 12:47 UTC (permalink / raw)
To: devel
This will enable running virtiofsd as a user that does not have access
to VM directories.
Signed-off-by: Alyssa Ross <hi@alyssa.is>
---
.../template/data/service/vhost-user-fs/run | 2 +-
host/rootfs/image/usr/bin/create-vm-dependencies | 12 +++++-------
host/rootfs/image/usr/bin/run-appimage | 2 +-
host/rootfs/image/usr/bin/run-flatpak | 2 +-
host/rootfs/image/usr/bin/spectrum-update | 14 +++++++-------
5 files changed, 15 insertions(+), 17 deletions(-)
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..116570c3 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}/mount
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 98f10489..344e7778 100755
--- a/host/rootfs/image/usr/bin/create-vm-dependencies
+++ b/host/rootfs/image/usr/bin/create-vm-dependencies
@@ -9,8 +9,8 @@ if { mount --make-private --bind /run/vm/by-id/${1}/user /run/vm/by-id/${1}/user
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
}
if {
@@ -20,16 +20,14 @@ if {
--mount=/run/vm/by-id/${1}/mount
--user=/run/vm/by-id/${1}/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 }
+ 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} }
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 5e8e29fa..f0fe8311 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}/mount
- 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 86ccc12a..f9179819 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}/mount
- 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 b1517a6c..10a9f197 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}/mount
@@ -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
^ permalink raw reply related [flat|nested] 21+ messages in thread* [PATCH 8/8] host/rootfs: run filesystem daemons as non-root
2025-12-10 12:47 [PATCH 1/8] host/rootfs: create dbus socket externally Alyssa Ross
` (5 preceding siblings ...)
2025-12-10 12:47 ` [PATCH 7/8] host/rootfs: move fs directory out of VM directory Alyssa Ross
@ 2025-12-10 12:47 ` Alyssa Ross
2025-12-10 18:29 ` Demi Marie Obenour
6 siblings, 1 reply; 21+ messages in thread
From: Alyssa Ross @ 2025-12-10 12:47 UTC (permalink / raw)
To: devel
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>
---
.../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 20f1daff..7330ab4c 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}/mount
+nsenter --preserve-credentials -S0
+ --mount=/run/vm/by-id/${VM}/mount
+ --user=/run/vm/by-id/${VM}/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 116570c3..525940d1 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}/mount
+ --user=/run/vm/by-id/${VM}/user
-nsenter --mount=/run/vm/by-id/${VM}/mount
+# 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..cb2195d1 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}/mount
+ --user=/run/vm/by-id/${VM}/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 344e7778..6f9d0a60 100755
--- a/host/rootfs/image/usr/bin/create-vm-dependencies
+++ b/host/rootfs/image/usr/bin/create-vm-dependencies
@@ -14,16 +14,21 @@ if {
}
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}/mount
--user=/run/vm/by-id/${1}/user
# 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 --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} }
if { mount --make-shared --rbind /run/doc/${1} /run/doc/${1} }
diff --git a/host/rootfs/image/usr/bin/run-flatpak b/host/rootfs/image/usr/bin/run-flatpak
index f9179819..695df21f 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}/mount
+ s6-envuidgid fs
+ s6-applyuidgid -Uzu 0
+ nsenter --preserve-credentials -S0
+ --mount=/run/vm/by-id/${id}/mount
+ --user=/run/vm/by-id/${id}/user
cd /run/fs/${id}/config
if { redirfd -w 1 type echo flatpak }
mount-flatpak $@
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 8/8] host/rootfs: run filesystem daemons as non-root
2025-12-10 12:47 ` [PATCH 8/8] host/rootfs: run filesystem daemons as non-root Alyssa Ross
@ 2025-12-10 18:29 ` Demi Marie Obenour
2025-12-11 12:46 ` Alyssa Ross
0 siblings, 1 reply; 21+ messages in thread
From: Demi Marie Obenour @ 2025-12-10 18:29 UTC (permalink / raw)
To: Alyssa Ross, devel
[-- Attachment #1.1.1: Type: text/plain, Size: 7149 bytes --]
On 12/10/25 07:47, Alyssa Ross wrote:
> 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>
> ---
> .../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:
Would it be better to run each VM's daemons as dedicated users?
> 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 20f1daff..7330ab4c 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}/mount
> +nsenter --preserve-credentials -S0
> + --mount=/run/vm/by-id/${VM}/mount
> + --user=/run/vm/by-id/${VM}/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 116570c3..525940d1 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}/mount
> + --user=/run/vm/by-id/${VM}/user
>
> -nsenter --mount=/run/vm/by-id/${VM}/mount
> +# 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..cb2195d1 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}/mount
> + --user=/run/vm/by-id/${VM}/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 344e7778..6f9d0a60 100755
> --- a/host/rootfs/image/usr/bin/create-vm-dependencies
> +++ b/host/rootfs/image/usr/bin/create-vm-dependencies
> @@ -14,16 +14,21 @@ if {
> }
>
> 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}/mount
> --user=/run/vm/by-id/${1}/user
>
> # 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 --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 }
Why is this -o nofail? Also, file descriptor 3 should be closed afterwards.
> if { mount --rbind -o ro /run/fs/${1} /run/fs/${1} }
>
> if { mount --make-shared --rbind /run/doc/${1} /run/doc/${1} }
> diff --git a/host/rootfs/image/usr/bin/run-flatpak b/host/rootfs/image/usr/bin/run-flatpak
> index f9179819..695df21f 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}/mount
> + s6-envuidgid fs
> + s6-applyuidgid -Uzu 0
> + nsenter --preserve-credentials -S0
> + --mount=/run/vm/by-id/${id}/mount
> + --user=/run/vm/by-id/${id}/user
> cd /run/fs/${id}/config
> if { redirfd -w 1 type echo flatpak }
> mount-flatpak $@
--
Sincerely,
Demi Marie Obenour (she/her/hers)
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 7253 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH 8/8] host/rootfs: run filesystem daemons as non-root
2025-12-10 18:29 ` Demi Marie Obenour
@ 2025-12-11 12:46 ` Alyssa Ross
0 siblings, 0 replies; 21+ messages in thread
From: Alyssa Ross @ 2025-12-11 12:46 UTC (permalink / raw)
To: Demi Marie Obenour; +Cc: devel
[-- Attachment #1: Type: text/plain, Size: 6676 bytes --]
Demi Marie Obenour <demiobenour@gmail.com> writes:
> On 12/10/25 07:47, Alyssa Ross wrote:
>> 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>
>> ---
>> .../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:
>
> Would it be better to run each VM's daemons as dedicated users?
Not really, because they all need to have access to the same files on
the filesystem anyway. The separate namespaces stop them from doing
things like ptracing each other, but at the end of the day they need to
all be able to access the same set of user files.
>> 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 20f1daff..7330ab4c 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}/mount
>> +nsenter --preserve-credentials -S0
>> + --mount=/run/vm/by-id/${VM}/mount
>> + --user=/run/vm/by-id/${VM}/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 116570c3..525940d1 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}/mount
>> + --user=/run/vm/by-id/${VM}/user
>>
>> -nsenter --mount=/run/vm/by-id/${VM}/mount
>> +# 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..cb2195d1 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}/mount
>> + --user=/run/vm/by-id/${VM}/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 344e7778..6f9d0a60 100755
>> --- a/host/rootfs/image/usr/bin/create-vm-dependencies
>> +++ b/host/rootfs/image/usr/bin/create-vm-dependencies
>> @@ -14,16 +14,21 @@ if {
>> }
>>
>> 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}/mount
>> --user=/run/vm/by-id/${1}/user
>>
>> # 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 --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 }
>
> Why is this -o nofail? Also, file descriptor 3 should be closed afterwards.
Same reason as always. Not all VMs have an fs directory in config,
notably netvm.
Descriptor 3 will be closed at the end of this block in a few lines
anyway. It does no harm to keep it open until then.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread