Skip to content

Commit

Permalink
libselinux: support huge passwd/group entries
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: James Carter <[email protected]>
  • Loading branch information
cgzones authored and jwcart2 committed Jan 25, 2024
1 parent 846550d commit ebf4168
Showing 1 changed file with 25 additions and 8 deletions.
33 changes: 25 additions & 8 deletions libselinux/src/seusers.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <stdio_ext.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>

#include <selinux/selinux.h>
#include <selinux/context.h>

Expand Down Expand Up @@ -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;

for (;;) {
int rc;

rbuf = malloc(rbuflen);
if (rbuf == NULL)
break;

int retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent);
if (retval == 0 && pwent) {
gid = pwent->pw_gid;
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;
}
Expand All @@ -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) {
Expand All @@ -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;
Expand Down

0 comments on commit ebf4168

Please sign in to comment.