]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
support: Pick group in support_capture_subprogram_self_sgid if UID == 0
authorFlorian Weimer <fweimer@redhat.com>
Wed, 21 May 2025 14:47:34 +0000 (16:47 +0200)
committerFlorian Weimer <fweimer@redhat.com>
Fri, 20 Jun 2025 08:55:26 +0000 (10:55 +0200)
When running as root, it is likely that we can run under any group.
Pick a harmless group from /etc/group in this case.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 2f769cec448d84a62b7dd0d4ff56978fe22c0cd6)

support/support_capture_subprocess.c

index eb72a2c21cf99ee291865f15bd95bbb266f80fca..1a30ae3f31f041d4757718249c9f30d8bda191eb 100644 (file)
 
 #include <errno.h>
 #include <fcntl.h>
+#include <grp.h>
+#include <scratch_buffer.h>
+#include <stdio_ext.h>
 #include <stdlib.h>
+#include <string.h>
 #include <support/check.h>
 #include <support/xunistd.h>
 #include <support/xsocket.h>
@@ -209,10 +213,48 @@ err:
   return status;
 }
 
+/* Returns true if a group with NAME has been found, and writes its
+   GID to *TARGET.  */
+static bool
+find_sgid_group (gid_t *target, const char *name)
+{
+  /* Do not use getgrname_r because it does not work in statically
+     linked binaries if the system libc is different.  */
+  FILE *fp = fopen ("/etc/group", "rce");
+  if (fp == NULL)
+    return false;
+  __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+  bool ok = false;
+  struct scratch_buffer buf;
+  scratch_buffer_init (&buf);
+  while (true)
+    {
+      struct group grp;
+      struct group *result = NULL;
+      int status = fgetgrent_r (fp, &grp, buf.data, buf.length, &result);
+      if (status == 0 && result != NULL)
+       {
+         if (strcmp (result->gr_name, name) == 0)
+           {
+             *target = result->gr_gid;
+             ok = true;
+             break;
+           }
+       }
+      else if (errno != ERANGE)
+       break;
+      else if (!scratch_buffer_grow (&buf))
+       break;
+    }
+  scratch_buffer_free (&buf);
+  fclose (fp);
+  return ok;
+}
+
 int
 support_capture_subprogram_self_sgid (const char *child_id)
 {
-  gid_t target = 0;
   const int count = 64;
   gid_t groups[count];
 
@@ -224,6 +266,7 @@ support_capture_subprogram_self_sgid (const char *child_id)
                     (intmax_t) getuid ());
 
   gid_t current = getgid ();
+  gid_t target = current;
   for (int i = 0; i < ret; ++i)
     {
       if (groups[i] != current)
@@ -233,9 +276,16 @@ support_capture_subprogram_self_sgid (const char *child_id)
        }
     }
 
-  if (target == 0)
-    FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n",
-                    (intmax_t) getuid ());
+  if (target == current)
+    {
+      /* If running as root, try to find a harmless group for SGID.  */
+      if (getuid () != 0
+         || (!find_sgid_group (&target, "nogroup")
+             && !find_sgid_group (&target, "bin")
+             && !find_sgid_group (&target, "daemon")))
+       FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n",
+                        (intmax_t) getuid ());
+    }
 
   return copy_and_spawn_sgid (child_id, target);
 }