commit 2f769cec448d84a62b7dd0d4ff56978fe22c0cd6 Author: Florian Weimer Date: Wed May 21 16:47:34 2025 +0200 support: Pick group in support_capture_subprogram_self_sgid if UID == 0 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 diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c index 48c2ab839dca33ea..774deacd5fe2b6cc 100644 --- a/support/support_capture_subprocess.c +++ b/support/support_capture_subprocess.c @@ -21,7 +21,11 @@ #include #include +#include +#include +#include #include +#include #include #include #include @@ -208,10 +212,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]; @@ -223,6 +265,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) @@ -232,9 +275,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); }