From: Chris Down Date: Wed, 5 Nov 2025 10:41:17 +0000 (+0800) Subject: core: Only apply unprivileged userns logic to user managers X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=666cd35be493e2d796c5424eed9a3deeddc9b0fe;p=thirdparty%2Fsystemd.git core: Only apply unprivileged userns logic to user managers Commit 38748596f078 ("core: Make DelegateNamespaces= work for user managers with CAP_SYS_ADMIN") refactored the logic for when an unprivileged process should create a new user namespace for sandboxing. This refactor inadvertently removed a check (`params->runtime_scope != RUNTIME_SCOPE_USER`) that differentiated between system services and user services. This causes a regression in rootless containers where systemd runs unprivileged. When starting a system service (like `dbus-broker`) that uses sandboxing features (eg. with `PrivateTmp=yes`), systemd now incorrectly creates a new, minimal `PRIVATE_USERS_SELF` namespace. This new namespace only maps UID/GID 0. When dbus-broker attempts to drop privileges to the `dbus` user (GID 81), the `setresgid(81, 81, 81)` call fails because GID 81 is not mapped. Restore the check to ensure that the special unprivileged sandboxing logic is only applied to user services, as was the original intent. System services in a rootless context will now correctly run in the container's main user namespace, where all necessary UIDs/GIDs are mapped. Fixes: https://github.com/systemd/systemd/issues/39563 Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2391343 --- diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index b748be50859..d9b976b432d 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -4468,6 +4468,12 @@ static void log_command_line( static bool exec_needs_cap_sys_admin(const ExecContext *context, const ExecParameters *params) { assert(context); + assert(params); + + /* We only want to ever imply PrivateUsers= for user managers, as they're not expected to setuid() to + * other users, unlike the system manager which needs all users to be around. */ + if (params->runtime_scope != RUNTIME_SCOPE_USER) + return false; return context->private_users != PRIVATE_USERS_NO || context->private_tmp != PRIVATE_TMP_NO ||