From: Mike Yuan Date: Thu, 26 Mar 2026 11:16:36 +0000 (+0100) Subject: machine: never ever allow non-root-owned host machine X-Git-Tag: v261-rc1~708 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=771800a403c7e21c88fff917321fd3f290bdc80c;p=thirdparty%2Fsystemd.git machine: never ever allow non-root-owned host machine We really should lock this down _hard_, as evidenced by recent security fallouts. --- diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index d567cd6d503..2dab827d41c 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -366,14 +366,15 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu 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->manager->runtime_scope != RUNTIME_SCOPE_USER && m->uid != 0 && m->class != MACHINE_HOST) { + /* Ensure only root can shell into the root namespace. 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 the 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->manager->runtime_scope != RUNTIME_SCOPE_USER && m->uid != 0) { + assert(m->class != MACHINE_HOST); + r = pidref_in_same_namespace(&PIDREF_MAKE_FROM_PID(1), &m->leader, NAMESPACE_USER); if (r < 0) return log_debug_errno( diff --git a/src/machine/machine-varlink.c b/src/machine/machine-varlink.c index 40e9136b270..dfc7020fc95 100644 --- a/src/machine/machine-varlink.c +++ b/src/machine/machine-varlink.c @@ -555,14 +555,15 @@ 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 + /* Ensure only root can shell into the root namespace. 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 + * do not need to check the caller's uid, as that will be checked by polkit, and if the 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) { + if (machine->uid != 0) { + assert(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(