* sunrpc/svcauth_des.c (authdes_getucred): Removed fixed limit on
	number of groups in the cache.  Relax the disconnect between the
	interface of authdes_getucred and netname2user a bit.
	* sunrpc/auth_unix.c (authunix_create_default): Don't allocate
	huge arrays on the stack.
This commit is contained in:
Ulrich Drepper 2004-02-26 19:22:02 +00:00
parent 5db7adc49d
commit 773640b4f5
3 changed files with 97 additions and 25 deletions

View File

@ -1,5 +1,11 @@
2004-02-26 Ulrich Drepper <drepper@redhat.com> 2004-02-26 Ulrich Drepper <drepper@redhat.com>
* sunrpc/svcauth_des.c (authdes_getucred): Removed fixed limit on
number of groups in the cache. Relax the disconnect between the
interface of authdes_getucred and netname2user a bit.
* sunrpc/auth_unix.c (authunix_create_default): Don't allocate
huge arrays on the stack.
* sysdeps/unix/sysv/linux/sysconf.c (__sysconf): Use the official * sysdeps/unix/sysv/linux/sysconf.c (__sysconf): Use the official
not cancelable interfaces. not cancelable interfaces.

View File

@ -38,7 +38,9 @@
* for the credentials. * for the credentials.
*/ */
#include <errno.h>
#include <limits.h> #include <limits.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -165,25 +167,61 @@ INTDEF (authunix_create)
AUTH * AUTH *
authunix_create_default (void) authunix_create_default (void)
{ {
int len;
char machname[MAX_MACHINE_NAME + 1]; char machname[MAX_MACHINE_NAME + 1];
uid_t uid;
gid_t gid;
int max_nr_groups = __sysconf (_SC_NGROUPS_MAX);
gid_t gids[max_nr_groups];
if (__gethostname (machname, MAX_MACHINE_NAME) == -1) if (__gethostname (machname, MAX_MACHINE_NAME) == -1)
abort (); abort ();
machname[MAX_MACHINE_NAME] = 0; machname[MAX_MACHINE_NAME] = 0;
uid = __geteuid (); uid_t uid = __geteuid ();
gid = __getegid (); gid_t gid = __getegid ();
if ((len = __getgroups (max_nr_groups, gids)) < 0) int max_nr_groups;
/* When we have to try a second time, do not use alloca() again. We
might have reached the stack limit already. */
bool retry = false;
again:
/* Ask the kernel how many groups there are exactly. Note that we
might have to redo all this if the number of groups has changed
between the two calls. */
max_nr_groups = __getgroups (0, NULL);
/* Just some random reasonable stack limit. */
#define ALLOCA_LIMIT (1024 / sizeof (gid_t))
gid_t *gids = NULL;
if (max_nr_groups < ALLOCA_LIMIT && ! retry)
gids = (gid_t *) alloca (max_nr_groups * sizeof (gid_t));
else
{
gids = (gid_t *) malloc (max_nr_groups * sizeof (gid_t));
if (gids == NULL)
return NULL;
}
int len = __getgroups (max_nr_groups, gids);
if (len == -1)
{
if (errno == EINVAL)
{
/* New groups added in the meantime. Try again. */
if (max_nr_groups >= ALLOCA_LIMIT || retry)
free (gids);
retry = true;
goto again;
}
/* No other error can happen. */
abort (); abort ();
}
/* This braindamaged Sun code forces us here to truncate the /* This braindamaged Sun code forces us here to truncate the
list of groups to NGRPS members since the code in list of groups to NGRPS members since the code in
authuxprot.c transforms a fixed array. Grrr. */ authuxprot.c transforms a fixed array. Grrr. */
return INTUSE(authunix_create) (machname, uid, gid, MIN (NGRPS, len), gids); AUTH *result = INTUSE(authunix_create) (machname, uid, gid, MIN (NGRPS, len),
gids);
if (max_nr_groups >= ALLOCA_LIMIT || retry)
free (gids);
return result;
} }
INTDEF (authunix_create_default) INTDEF (authunix_create_default)

View File

@ -43,6 +43,7 @@
* *
*/ */
#include <limits.h>
#include <string.h> #include <string.h>
#include <sys/param.h> #include <sys/param.h>
#include <netinet/in.h> #include <netinet/in.h>
@ -487,8 +488,9 @@ struct bsdcred
{ {
uid_t uid; /* cached uid */ uid_t uid; /* cached uid */
gid_t gid; /* cached gid */ gid_t gid; /* cached gid */
short grouplen; /* length of cached groups */ int grouplen; /* length of cached groups */
gid_t groups[NGROUPS]; /* cached groups */ int grouplen_max; /* length of allocated cached groups */
gid_t groups[0]; /* cached groups */
}; };
/* /*
@ -515,13 +517,7 @@ authdes_getucred (const struct authdes_cred *adc, uid_t * uid, gid_t * gid,
return 0; return 0;
} }
cred = (struct bsdcred *) authdes_cache[sid].localcred; cred = (struct bsdcred *) authdes_cache[sid].localcred;
if (cred == NULL) if (cred == NULL || cred->grouplen == INVALID)
{
cred = (struct bsdcred *) mem_alloc (sizeof (struct bsdcred));
authdes_cache[sid].localcred = (char *) cred;
cred->grouplen = INVALID;
}
if (cred->grouplen == INVALID)
{ {
/* /*
* not in cache: lookup * not in cache: lookup
@ -530,15 +526,43 @@ authdes_getucred (const struct authdes_cred *adc, uid_t * uid, gid_t * gid,
&i_grouplen, groups)) &i_grouplen, groups))
{ {
debug ("unknown netname"); debug ("unknown netname");
if (cred != NULL)
cred->grouplen = UNKNOWN; /* mark as lookup up, but not found */ cred->grouplen = UNKNOWN; /* mark as lookup up, but not found */
return 0; return 0;
} }
if (cred != NULL && cred->grouplen_max < i_grouplen)
{
/* We already have an allocated data structure. But it is
too small. */
free (cred);
authdes_cache[sid].localcred = NULL;
cred = NULL;
}
if (cred == NULL)
{
/* We should allocate room for at least NGROUPS groups. */
int ngroups_max = MAX (i_grouplen, NGROUPS);
cred = (struct bsdcred *) mem_alloc (sizeof (struct bsdcred)
+ ngroups_max * sizeof (gid_t));
if (cred == NULL)
return 0;
authdes_cache[sid].localcred = (char *) cred;
cred->grouplen = INVALID;
cred->grouplen_max = ngroups_max;
}
debug ("missed ucred cache"); debug ("missed ucred cache");
*uid = cred->uid = i_uid; *uid = cred->uid = i_uid;
*gid = cred->gid = i_gid; *gid = cred->gid = i_gid;
*grouplen = cred->grouplen = i_grouplen; cred->grouplen = i_grouplen;
for (i = i_grouplen - 1; i >= 0; --i) for (i = i_grouplen - 1; i >= 0; --i)
cred->groups[i] = groups[i]; /* int to short */ cred->groups[i] = groups[i];
/* Make sure no too large values are reported. */
*grouplen = MIN (SHRT_MAX, i_grouplen);
return 1; return 1;
} }
else if (cred->grouplen == UNKNOWN) else if (cred->grouplen == UNKNOWN)
@ -554,9 +578,13 @@ authdes_getucred (const struct authdes_cred *adc, uid_t * uid, gid_t * gid,
*/ */
*uid = cred->uid; *uid = cred->uid;
*gid = cred->gid; *gid = cred->gid;
*grouplen = cred->grouplen;
for (i = cred->grouplen - 1; i >= 0; --i) /* Another stupidity in the interface: *grouplen is of type short.
groups[i] = cred->groups[i]; /* short to int */ So we might have to cut the information passed up short. */
int grouplen_copy = MIN (SHRT_MAX, cred->grouplen);
*grouplen = grouplen_copy;
for (i = grouplen_copy - 1; i >= 0; --i)
groups[i] = cred->groups[i];
return 1; return 1;
} }