From c5e48e3a66b23313cd4931b9dc25a8f48cfb1035 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 24 Sep 2025 15:42:51 +0100 Subject: [PATCH] machined: do not allow unprivileged users to shell into the root namespace We intend to make self-registering machines an unprivileged operation, but currently that would allow an unprivileged user to register a process they own in the root namespace, and then login as any user they like, including root, which is not ideal. Forbid non-root from shelling into a machine that is running in the root user namespace. --- src/machine/machine-dbus.c | 20 ++++++++++++++++++++ test/units/TEST-13-NSPAWN.unpriv.sh | 18 ++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index f903a1371e0..388a584a12e 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -20,6 +20,7 @@ #include "machine-dbus.h" #include "machined.h" #include "mount-util.h" +#include "namespace-util.h" #include "operation.h" #include "path-util.h" #include "signal-util.h" @@ -355,6 +356,25 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; user = isempty(user) ? "root" : user; + + /* Ensure only root can shell into the root namespace, unless it's specifically the host machine, + * which is owned by uid 0 anyway and cannot be self-registered. This is to avoid unprivileged + * users registering a process they own in the root user namespace, and then shelling in as root + * or another user. Note that the shell operation is privileged and requires 'auth_admin', so we + * do not need to check the caller's uid, as that will be checked by polkit, and if they machine's + * and the caller's do not match, authorization will be required. It's only the case where the + * caller owns the machine that will be shortcut and needs to be checked here. */ + if (m->uid != 0 && m->class != MACHINE_HOST) { + r = pidref_in_same_namespace(&PIDREF_MAKE_FROM_PID(1), &m->leader, NAMESPACE_USER); + if (r < 0) + return r; + if (r != 0) + return sd_bus_error_set( + error, + SD_BUS_ERROR_ACCESS_DENIED, + "Only root may shell into the root user namespace"); + } + r = sd_bus_message_read_strv(message, &args_wire); if (r < 0) return r; diff --git a/test/units/TEST-13-NSPAWN.unpriv.sh b/test/units/TEST-13-NSPAWN.unpriv.sh index b9ac5d903b7..d412a7fd9a5 100755 --- a/test/units/TEST-13-NSPAWN.unpriv.sh +++ b/test/units/TEST-13-NSPAWN.unpriv.sh @@ -69,4 +69,22 @@ machinectl terminate zurps "$(systemctl show -p MainPID --value systemd-logind.service)" \ "$PWD") +run0 -u testuser \ + busctl call \ + org.freedesktop.machine1 \ + /org/freedesktop/machine1 \ + org.freedesktop.machine1.Manager \ + RegisterMachine \ + 'sayssus' \ + shouldnotwork2 \ + 16 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 \ + "" \ + container \ + "$(systemctl show -p MainPID --value user@4711.service)" \ + "$PWD" +(! run0 -u testuser machinectl shell shouldnotwork2 /usr/bin/id -u) +(! run0 -u testuser machinectl shell root@shouldnotwork2 /usr/bin/id -u) +(! run0 -u testuser machinectl shell 0@shouldnotwork2 /usr/bin/id -u) +(! run0 -u testuser machinectl shell testuser@shouldnotwork2 /usr/bin/id -u) + loginctl disable-linger testuser -- 2.47.3