]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machine: do not allow unprivileged users to register other users' processes as machines
authorLuca Boccassi <luca.boccassi@gmail.com>
Fri, 12 Sep 2025 18:59:26 +0000 (19:59 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Tue, 16 Sep 2025 14:58:28 +0000 (15:58 +0100)
Registering a process as a machine means a caller can get machined
to send sigterm to it, and more. If an unpriv user is registering,
ensure the registered process is actually owned by the user.

Follow-up for adaff8eb35d9c471af81fddaa4403bc5843a256f

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

index 776654b51d14332b3f7543abca35e44dec1f954c..b2b2f1f2db069cd09b1631b3fde6788366d8c1d5 100644 (file)
@@ -15,6 +15,7 @@
 #include "machine-varlink.h"
 #include "machined.h"
 #include "mount-util.h"
+#include "namespace-util.h"
 #include "operation.h"
 #include "pidref.h"
 #include "socket-util.h"
@@ -186,6 +187,15 @@ int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink
         if (r < 0)
                 return r;
 
+        /* Ensure an unprivileged user cannot claim any process they don't control as their own machine */
+        if (machine->uid != 0) {
+                r = process_is_owned_by_uid(&machine->leader, machine->uid);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return sd_varlink_error(link, SD_VARLINK_ERROR_PERMISSION_DENIED, NULL);
+        }
+
         r = machine_link(manager, machine);
         if (r == -EEXIST)
                 return sd_varlink_error(link, VARLINK_ERROR_MACHINE_EXISTS, NULL);
index 883c8c1338c04c5d2d6f955c8f8fcc5c849b7680..91e5e218698b38df2052c6cce75e250305fcf38e 100644 (file)
@@ -29,6 +29,7 @@
 #include "machine-dbus.h"
 #include "machine-pool.h"
 #include "machined.h"
+#include "namespace-util.h"
 #include "operation.h"
 #include "os-util.h"
 #include "path-util.h"
@@ -321,6 +322,15 @@ static int method_create_or_register_machine(
         if (r < 0)
                 return r;
 
+        /* Ensure an unprivileged user cannot claim any process they don't control as their own machine */
+        if (uid != 0) {
+                r = process_is_owned_by_uid(&leader_pidref, uid);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only root may register machines for other users");
+        }
+
         const char *details[] = {
                 "name",  name,
                 "class", machine_class_to_string(c),
index 03af7ebc9cc02fa5c9cf552a4704520530cb87b8..17ccb19c8ebc3aad1bfb5b1256f45d375c0e93d8 100755 (executable)
@@ -15,7 +15,7 @@ fi
 at_exit() {
     rm -rf /home/testuser/.local/state/machines/zurps ||:
     machinectl terminate zurps ||:
-    rm -f /usr/share/polkit-1/rules.d/registermachinetest.rules
+    rm -f /etc/polkit-1/rules.d/registermachinetest.rules
 }
 
 trap at_exit EXIT
@@ -33,7 +33,8 @@ systemd-dissect --shift /home/testuser/.local/state/machines/zurps foreign
 
 # Install a PK rule that allows 'testuser' user to register a machine even
 # though they are not on an fg console, just for testing
-cat >/usr/share/polkit-1/rules.d/registermachinetest.rules <<'EOF'
+mkdir -p /etc/polkit-1/rules.d
+cat >/etc/polkit-1/rules.d/registermachinetest.rules <<'EOF'
 polkit.addRule(function(action, subject) {
     if (action.id == "org.freedesktop.machine1.register-machine" &&
         subject.user == "testuser") {
@@ -54,4 +55,18 @@ machinectl terminate zurps
 
 (! run0 -u testuser systemctl is-active --user systemd-nspawn@zurps.service)
 
+(! run0 -u testuser \
+    busctl call \
+        org.freedesktop.machine1 \
+        /org/freedesktop/machine1 \
+        org.freedesktop.machine1.Manager \
+        RegisterMachine \
+        'sayssus' \
+        shouldnotwork1 \
+        16 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 \
+        "" \
+        container \
+        "$(systemctl show -p MainPID --value systemd-logind.service)" \
+        "$PWD")
+
 loginctl disable-linger testuser