mirror of
https://sourceware.org/git/glibc.git
synced 2025-08-07 06:43:00 +03:00
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 <carlos@redhat.com>
This commit is contained in:
@@ -21,7 +21,11 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <scratch_buffer.h>
|
||||||
|
#include <stdio_ext.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <support/check.h>
|
#include <support/check.h>
|
||||||
#include <support/xunistd.h>
|
#include <support/xunistd.h>
|
||||||
#include <support/xsocket.h>
|
#include <support/xsocket.h>
|
||||||
@@ -210,10 +214,48 @@ err:
|
|||||||
return status;
|
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
|
int
|
||||||
support_capture_subprogram_self_sgid (const char *child_id)
|
support_capture_subprogram_self_sgid (const char *child_id)
|
||||||
{
|
{
|
||||||
gid_t target = 0;
|
|
||||||
const int count = 64;
|
const int count = 64;
|
||||||
gid_t groups[count];
|
gid_t groups[count];
|
||||||
|
|
||||||
@@ -225,6 +267,7 @@ support_capture_subprogram_self_sgid (const char *child_id)
|
|||||||
(intmax_t) getuid ());
|
(intmax_t) getuid ());
|
||||||
|
|
||||||
gid_t current = getgid ();
|
gid_t current = getgid ();
|
||||||
|
gid_t target = current;
|
||||||
for (int i = 0; i < ret; ++i)
|
for (int i = 0; i < ret; ++i)
|
||||||
{
|
{
|
||||||
if (groups[i] != current)
|
if (groups[i] != current)
|
||||||
@@ -234,9 +277,16 @@ support_capture_subprogram_self_sgid (const char *child_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target == 0)
|
if (target == current)
|
||||||
FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n",
|
{
|
||||||
(intmax_t) getuid ());
|
/* 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);
|
return copy_and_spawn_sgid (child_id, target);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user