From ebf4168577f612db10f52b3d3bf1125272ad07aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 19 Dec 2023 17:09:30 +0100 Subject: [PATCH] libselinux: support huge passwd/group entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit getpwnam_r(3) and getgrnam_r(3) might return ERANGE in case the supplied buffer was too short for the passwd/group entry. Retry with a bigger buffer. Also use a fallback buffer size in case the libc returns -1 for sysconf(3) of _SC_GETPW_R_SIZE_MAX or _SC_GETGR_R_SIZE_MAX, like musl. Signed-off-by: Christian Göttsche Acked-by: James Carter --- libselinux/src/seusers.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/libselinux/src/seusers.c b/libselinux/src/seusers.c index e5cfd510..16d69347 100644 --- a/libselinux/src/seusers.c +++ b/libselinux/src/seusers.c @@ -6,6 +6,8 @@ #include #include #include +#include + #include #include @@ -99,15 +101,30 @@ static gid_t get_default_gid(const char *name) { struct passwd pwstorage, *pwent = NULL; gid_t gid = -1; /* Allocate space for the getpwnam_r buffer */ + char *rbuf = NULL; long rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); - if (rbuflen <= 0) return -1; - char *rbuf = malloc(rbuflen); - if (rbuf == NULL) return -1; + if (rbuflen <= 0) + rbuflen = 1024; - int retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent); - if (retval == 0 && pwent) { - gid = pwent->pw_gid; + for (;;) { + int rc; + + rbuf = malloc(rbuflen); + if (rbuf == NULL) + break; + + rc = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent); + if (rc == ERANGE && rbuflen < LONG_MAX / 2) { + free(rbuf); + rbuflen *= 2; + continue; + } + if (rc == 0 && pwent) + gid = pwent->pw_gid; + + break; } + free(rbuf); return gid; } @@ -120,7 +137,7 @@ static int check_group(const char *group, const char *name, const gid_t gid) { long rbuflen = sysconf(_SC_GETGR_R_SIZE_MAX); if (rbuflen <= 0) - return 0; + rbuflen = 1024; char *rbuf; while(1) { @@ -129,7 +146,7 @@ static int check_group(const char *group, const char *name, const gid_t gid) { return 0; int retval = getgrnam_r(group, &gbuf, rbuf, rbuflen, &grent); - if ( retval == ERANGE ) + if (retval == ERANGE && rbuflen < LONG_MAX / 2) { free(rbuf); rbuflen = rbuflen * 2;