]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machined: do not allow unprivileged users to shell into the root namespace
authorLuca Boccassi <luca.boccassi@gmail.com>
Wed, 24 Sep 2025 14:42:51 +0000 (15:42 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 10 Oct 2025 08:36:47 +0000 (10:36 +0200)
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.

(cherry picked from commit c5e48e3a66b23313cd4931b9dc25a8f48cfb1035)

src/machine/machine-dbus.c
test/units/TEST-13-NSPAWN.unpriv.sh

index f903a1371e0e9da66c1cc2f1ee572126d9b51ec2..388a584a12e2b967a3e0be56bdfa622ef4350e02 100644 (file)
@@ -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;
index 17ccb19c8ebc3aad1bfb5b1256f45d375c0e93d8..aa5edd24611dc5bbf5c6c29151ace505ec79fa0d 100755 (executable)
@@ -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