machined: do not allow unprivileged users to shell into the root namespace via varlink

Forbid non-root from shelling into a machine that is running in
the root user namespace.

Follow-up for adaff8eb35
This commit is contained in:
Luca Boccassi
2026-03-04 13:03:44 +00:00
parent acf00ba7b5
commit e5a5656b55
2 changed files with 37 additions and 0 deletions
+18
View File
@@ -552,6 +552,24 @@ int vl_method_open(sd_varlink *link, sd_json_variant *parameters, sd_varlink_met
return r;
if (manager->runtime_scope != RUNTIME_SCOPE_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 (machine->uid != 0 && machine->class != MACHINE_HOST) {
r = pidref_in_same_namespace(&PIDREF_MAKE_FROM_PID(1), &machine->leader, NAMESPACE_USER);
if (r < 0)
return log_debug_errno(
r,
"Failed to check if machine '%s' is running in the root user namespace: %m",
machine->name);
if (r > 0)
return sd_varlink_error(link, SD_VARLINK_ERROR_PERMISSION_DENIED, NULL);
}
_cleanup_strv_free_ char **polkit_details = NULL;
polkit_details = machine_open_polkit_details(p.mode, machine->name, user, path, command_line);
+19
View File
@@ -31,6 +31,7 @@ at_exit() {
rm -f /usr/share/polkit-1/rules.d/registermachinetest.rules
rm -rf /var/tmp/mangletest
rm -f /var/tmp/mangletest.tar.gz
rm -f /shouldnotwork
}
trap at_exit EXIT
@@ -104,6 +105,24 @@ run0 -u testuser \
(! run0 -u testuser machinectl shell 0@shouldnotwork2 /usr/bin/id -u)
(! run0 -u testuser machinectl shell testuser@shouldnotwork2 /usr/bin/id -u)
run0 -u testuser \
systemd-run --unit sleep.service --user sleep infinity
sleep_pid="$(run0 -u testuser systemctl show --user -P MainPID sleep.service)"
run0 -u testuser \
varlinkctl \
call \
/run/systemd/machine/io.systemd.Machine \
io.systemd.Machine.Register \
"{\"name\":\"shouldnotwork3\", \"class\":\"container\", \"leader\": $sleep_pid}"
(! run0 -u testuser \
varlinkctl \
call \
/run/systemd/machine/io.systemd.Machine \
io.systemd.Machine.Open \
'{"name":"shouldnotwork3", "mode": "shell", "user":"root","path":"/usr/bin/bash","args":["bash","-c","''touch /shouldnotwork; sleep 20''"]}')
systemctl --user --machine testuser@ stop sleep.service
test ! -f /shouldnotwork
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