]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machined: gate metadata querying behind inspect-machines/images action
authorLuca Boccassi <luca.boccassi@gmail.com>
Tue, 14 Apr 2026 19:22:39 +0000 (20:22 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 16 Apr 2026 11:29:33 +0000 (13:29 +0200)
Ensure only privileged users can call the system scope machined's
APIs that get data out of a machine

Follow-up for 1bd979dddbb6ed3ffe410d78a7ff80cbb1c42a64
Follow-up for 9153b02bb5030e29d6008992fb74b9028d7c392c

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

index c096a012d88f6ff1cb806c4d5137408387ad036c..a9d15ca5f72b1d5d81f74a341caad69d7e2cb446 100644 (file)
@@ -247,6 +247,25 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
 
         assert(message);
 
+        if (m->manager->runtime_scope != RUNTIME_SCOPE_USER) {
+                const char *details[] = {
+                        "machine", m->name,
+                        "verb", "get_os_release",
+                        NULL
+                };
+
+                r = bus_verify_polkit_async(
+                                message,
+                                "org.freedesktop.machine1.inspect-machines",
+                                details,
+                                &m->manager->polkit_registry,
+                                error);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return 1; /* Will call us back */
+        }
+
         r = machine_get_os_release(m, &l);
         if (r == -ENONET)
                 return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Machine does not contain OS release information.");
index 4ab68a77f9e2b57c68703546bf19c3af80bed23a..acc2137f830b80fb9d612cf783ce363055cb49d7 100644 (file)
@@ -535,6 +535,17 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
         if (r != 0)
                 return r;
 
+        if (m->runtime_scope != RUNTIME_SCOPE_USER && should_acquire_metadata(p.acquire_metadata)) {
+                r = varlink_verify_polkit_async(
+                                link,
+                                m->system_bus,
+                                "org.freedesktop.machine1.inspect-machines",
+                                (const char**) STRV_MAKE("name", strna(p.name)),
+                                &m->polkit_registry);
+                if (r <= 0)
+                        return r;
+        }
+
         r = sd_varlink_set_sentinel(link, VARLINK_ERROR_MACHINE_NO_SUCH_MACHINE);
         if (r < 0)
                 return r;
@@ -682,6 +693,17 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters,
         if (r != 0)
                 return r;
 
+        if (m->runtime_scope != RUNTIME_SCOPE_USER && should_acquire_metadata(p.acquire_metadata)) {
+                r = varlink_verify_polkit_async(
+                                link,
+                                m->system_bus,
+                                "org.freedesktop.machine1.inspect-images",
+                                (const char**) STRV_MAKE("name", strna(p.image_name)),
+                                &m->polkit_registry);
+                if (r <= 0)
+                        return r;
+        }
+
         r = sd_varlink_set_sentinel(link, VARLINK_ERROR_MACHINE_IMAGE_NO_SUCH_IMAGE);
         if (r < 0)
                 return r;
index d5b8d83d2aade22c1450b6b4aacda9453d520030..f8f498f8cfc91414c9d6f1ff442a25536e473373 100644 (file)
                         <allow_inactive>auth_admin</allow_inactive>
                         <allow_active>auth_admin_keep</allow_active>
                 </defaults>
-                <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.shell org.freedesktop.login1.login</annotate>
+                <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.shell org.freedesktop.login1.login org.freedesktop.machine1.inspect-machines</annotate>
+        </action>
+
+        <action id="org.freedesktop.machine1.inspect-machines">
+                <description gettext-domain="systemd">Inspect local virtual machines and containers</description>
+                <message gettext-domain="systemd">Authentication is required to inspect local virtual machines and containers.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
         </action>
 
         <action id="org.freedesktop.machine1.create-machine">
                         <allow_inactive>auth_admin</allow_inactive>
                         <allow_active>auth_admin_keep</allow_active>
                 </defaults>
+                <annotate key="org.freedesktop.policykit.imply">org.freedesktop.machine1.inspect-images</annotate>
+        </action>
+
+        <action id="org.freedesktop.machine1.inspect-images">
+                <description gettext-domain="systemd">Inspect local virtual machine and container images</description>
+                <message gettext-domain="systemd">Authentication is required to inspect local virtual machine and container images.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
         </action>
 
 </policyconfig>
index 75a9c1aac070bcda69b43177827b71ab71f70482..e0516449c70b00ce4c1e55ba663c0c2cbf882931 100755 (executable)
@@ -23,6 +23,8 @@ at_exit() {
     rm -rf /home/testuser/.local/state/machines/inodetest2 ||:
     rm -rf /home/testuser/.local/state/machines/mangletest ||:
     machinectl terminate zurps ||:
+    machinectl terminate exfiltrate ||:
+    systemctl --user --machine testuser@ stop exfiltrate.service ||:
     rm -f /etc/polkit-1/rules.d/registermachinetest.rules
     machinectl terminate nurps ||:
     machinectl terminate kurps ||:
@@ -163,6 +165,28 @@ run0 -u testuser  \
 systemctl --user --machine testuser@ stop sleep.service
 test ! -f /shouldnotwork
 
+echo FOO=bar >/tmp/foo
+chmod 600 /tmp/foo
+run0 -u testuser \
+    systemd-run --unit exfiltrate.service --service-type notify --property NotifyAccess=all --user \
+        unshare --map-root-user --user --mount \
+            bash -c 'mount --bind /tmp/foo /usr/lib/os-release; systemd-notify --ready; exec sleep infinity'
+exfiltrate_pid="$(systemctl --machine testuser@.host show --user -P MainPID exfiltrate.service)"
+run0 -u testuser \
+    varlinkctl \
+        call \
+        /run/systemd/machine/io.systemd.Machine \
+        io.systemd.Machine.Register \
+        "{\"name\":\"exfiltrate\", \"class\":\"container\", \"leader\": $exfiltrate_pid}"
+exfiltrate_output="$(run0 -u testuser \
+    varlinkctl \
+        call \
+        /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List \
+        "{\"name\":\"exfiltrate\",\"acquireMetadata\":\"graceful\"}" 2>&1)" || true
+(! echo "$exfiltrate_output" | grep '"name".*"exfiltrate"' >/dev/null)
+(! echo "$exfiltrate_output" | grep "FOO=bar" >/dev/null)
+systemctl --user --machine testuser@ stop exfiltrate.service
+
 run0 -u testuser mkdir /var/tmp/image-tar
 run0 -u testuser importctl --user export-tar zurps /var/tmp/image-tar/kurps.tar.gz -m
 run0 -u testuser importctl --user import-tar /var/tmp/image-tar/kurps.tar.gz -m