]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
user-util: Don't setgroups() if /proc/self/gid_map is empty
authorDaan De Meyer <daan@amutable.com>
Fri, 13 Feb 2026 11:24:49 +0000 (12:24 +0100)
committerDaan De Meyer <daan@amutable.com>
Mon, 16 Feb 2026 08:37:32 +0000 (09:37 +0100)
If /proc/self/gid_map is empty, the kernel will refuse setgroups(),
so don't attempt it if that's the case on top of the /proc/self/setgroups
check we already have.

src/basic/user-util.c

index 6f5b597694f9080cc6cf6c1cb949a0417b4d5d15..e434fbec8f98508f73ea3001ab8d161806bcdcb2 100644 (file)
@@ -920,19 +920,28 @@ int maybe_setgroups(size_t size, const gid_t *list) {
 
         /* Check if setgroups is allowed before we try to drop all the auxiliary groups */
         if (size == 0) { /* Dropping all aux groups? */
-                _cleanup_free_ char *setgroups_content = NULL;
-                bool can_setgroups;
 
+                /* The kernel refuses setgroups() if there are no GID mappings in the current
+                 * user namespace, so check that beforehand and don't try to setgroups() if
+                 * there are no GID mappings. */
+                _cleanup_fclose_ FILE *f = fopen("/proc/self/gid_map", "re");
+                if (!f && errno != ENOENT)
+                        return -errno;
+                if (f) {
+                        r = safe_fgetc(f, /* ret= */ NULL);
+                        if (r < 0)
+                                return r;
+                        if (r == 0) {
+                                log_debug("Skipping setgroups(), /proc/self/gid_map is empty");
+                                return 0;
+                        }
+                }
+
+                _cleanup_free_ char *setgroups_content = NULL;
                 r = read_one_line_file("/proc/self/setgroups", &setgroups_content);
-                if (r == -ENOENT)
-                        /* Old kernels don't have /proc/self/setgroups, so assume we can use setgroups */
-                        can_setgroups = true;
-                else if (r < 0)
+                if (r < 0 && r != -ENOENT)
                         return r;
-                else
-                        can_setgroups = streq(setgroups_content, "allow");
-
-                if (!can_setgroups) {
+                if (r > 0 && streq(setgroups_content, "deny")) {
                         log_debug("Skipping setgroups(), /proc/self/setgroups is set to 'deny'");
                         return 0;
                 }