On Monday 13 June 2011 16:46:21 Tito wrote:
>
> On Monday 13 June 2011 16:00:14 Tito wrote:
> >
> > On Monday 13 June 2011 14:11:50 Alexey Fomenko wrote:
> > > Hello!
> > >
> > > In coreutils/id.c get_groups() gets groups list for further printing out
> > > on screen. According to id's main function - return value from
> > > get_groups is expected even < 0 in order to extend (xrealloc) the
> > > list size for the groups in case if there's more than 64:
> > > > 123 int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
> > > > 124 int id_main(int argc UNUSED_PARAM, char **argv)
> > > > 125 {
> > > ...
> > > > 180 n = 64;
> > > > 181 if (get_groups(username, rgid, groups, &n) < 0)
> > > > {
> > > > 182 /* Need bigger buffer after all */
> > > > 183 groups = xrealloc(groups, n *
> > > > sizeof(gid_t));
> > > > 184 get_groups(username, rgid, groups, &n);
> > > > 185 }
> > > > 186 if (n > 0) {
> > > But get_groups() allowed to return only >=0 value:
> >
> > Hi,
> > get_groups seems able to return value < 0:
> >
> > A) in case getgrouplist is used:
> >
> > from man getgrouplist:
> >
> > The n(groups) argument is a value-result argument: on return it always
> > contains the number of groups found for user, including group;
> > this
> > value may be greater than the number of groups stored in groups.
> >
> > so we just catch an unexpected exception in case of *n < 0,
> >
> > If the number of groups of which user is a member is less than or equal
> > to *n, then the value *n is returned.
> >
> > If the user is a member of more than *n groups, then
> > getgrouplist() returns -1
> >
> > so here we have:
> > 1) number of groups <= n m = 0
> > 2) number of groups > n m = -1 *n = number of
> > groups needed for realloc
> > 3) *n < 0 m = 0 /*
> > something bad happened , dont realloc */
> >
> > B) in case getgroups is used:
> >
> > On success, getgroups() returns the number of supplementary group IDs.
> > On error, -1 is returned, and errno is set appropriately.
> >
> > 1) nn > *n m = - 1
> > 2) nn = *n m = 0
> > 3) nn < *n m = 0
> >
> > *n < 0 is not possible in this case
>
> Was wrong on this:
> On error -1 is returned, which ends up in *n
>
> 4) nn < 0 m = 0 /* something bad happened , dont realloc */
> >
> > So it seems to me that get_groups could return a value < 0.
> >
> > static int get_groups(const char *username, gid_t rgid, gid_t *groups, int
> > *n)
> > {
> > int m;
> >
> > if (username) {
> > /* If the user is a member of more than
> > * *n groups, then -1 is returned. Otherwise >= 0.
> > * (and no defined way of detecting errors?!) */
> > m = getgrouplist(username, rgid, groups, n);
> > /* I guess *n < 0 might indicate error. Anyway,
> > * malloc'ing -1 bytes won't be good, so: */
> > //if (*n < 0)
> > // return 0;
> > //return m;
> > //commented out here, happens below anyway
> > } else {
> > /* On error -1 is returned, which ends up in *n */
> > int nn = getgroups(*n, groups);
> > /* 0: nn <= *n, groups[] was big enough; -1 otherwise */
> > m = - (nn > *n);
> > *n = nn;
> > }
> > if (*n < 0)
> > return 0; /* error, don't return < 0! */
> > return m;
> > }
> >
> >
> > Ciao,
> > Tito
> >
> >
> > > > 96 static int get_groups(const char *username, gid_t rgid, gid_t
> > > > *groups, int *n)
> > > ...
> > > > 118 if (*n < 0)
> > > > 119 return 0; /* error, don't return < 0! */
> > > > 120 return m;
> > > > 121 }
> > > And as a result - no way to get more than 64 groups, it goes strait to
> > > the bb_err_msg:
> > > > 196 } else if (n < 0) { /* error in get_groups() */
> > > > 197 if (ENABLE_DESKTOP)
> > > > 198 bb_error_msg_and_die("can't get
> > > > groups");
> > > > 199 return EXIT_FAILURE;
> > > > 200 }
> > > Is there any reason for such kind of restriction in get_groups? I'm
> > > suggesting
> > > to substitute this restriction with the call to "getgroups(0, groups)",
> > > to get an
> > > actual amount of groups before returning -1. In this case we're calling
> > > getgroups()
> > > 3 times. But only if we have more than 64 groups, it's a rare case.
> > > Another way -
> > > is to call getgroups() twice but always, first time to get amount of
> > > groups and
> > > then the actual groups list. I guess to call three times but in rare
> > > cases is
> > > better than twice but always.
> > >
> > > Patch is in attachment:
> > >
> > > >From 3a99379834788c6169a7dd992473524c9652e6a4 Mon Sep 17 00:00:00 2001
> > >
> > > Alexey Fomenko (1):
> > > id: fix return value when trying to get more than 64 groups
> > >
> > > coreutils/id.c | 5 +++--
> > > 1 files changed, 3 insertions(+), 2 deletions(-)
> > >
Hi,
by looking closer at it I now see the bug (sorry for the previous noise).
It seems to me that your proposed patch doesn't fix it and causes
garbled text to be printed to the terminal. This is easily demonstrated
by setting n to a low number e.g. n=2 and running id as user with more than 2
groups:
./busybox id
uid=1000(tito) gid=1000(tito)
groups=0(root),0(root),0(root),0(root),0(root),0(root),0(root),0(root),0(root),0(root),0(root),0(root),0(root),135092064,4294967295
It is due to the fact that (from man getgroups):
" If size is zero, __list is not modified__, but the total number of
supplementary group IDs for the process is returned."
Please take a look at the attached alternative patch that seems to work for me:
id: fix for the case when the calling process is a member
of more than 64 supplementary groups.
Signed-off-by: Tito Ragusa <[email protected]>
--- coreutils/id.c.original 2011-06-14 01:18:56.000000000 +0200
+++ coreutils/id.c 2011-06-14 01:58:06.000000000 +0200
@@ -110,11 +110,10 @@ static int get_groups(const char *userna
//return m;
//commented out here, happens below anyway
} else {
- /* On error -1 is returned, which ends up in *n */
- int nn = getgroups(*n, groups);
- /* 0: nn <= *n, groups[] was big enough; -1 otherwise */
- m = - (nn > *n);
- *n = nn;
+ if ((m = getgroups(*n, groups)) < 0 /* && errno == EINVAL */)
+ *n = getgroups(0, groups);
+ else
+ *n = m;
}
if (*n < 0)
return 0; /* error, don't return < 0! */
Ciao,
Tito
id: fix for the case when the calling process is a member
of more than 64 supplementary groups.
Signed-off-by: Tito Ragusa <[email protected]>
--- coreutils/id.c.original 2011-06-14 01:18:56.000000000 +0200
+++ coreutils/id.c 2011-06-14 02:03:26.000000000 +0200
@@ -110,11 +110,10 @@ static int get_groups(const char *userna
//return m;
//commented out here, happens below anyway
} else {
- /* On error -1 is returned, which ends up in *n */
- int nn = getgroups(*n, groups);
- /* 0: nn <= *n, groups[] was big enough; -1 otherwise */
- m = - (nn > *n);
- *n = nn;
+ if ((m = getgroups(*n, groups)) < 0 /* && errno == EINVAL */)
+ *n = getgroups(0, groups);
+ else
+ *n = m;
}
if (*n < 0)
return 0; /* error, don't return < 0! */
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox