On Tue, 2011-06-14 at 02:10 +0200, ext Tito wrote:
>
> 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."
Agree, my brain has inverted the expected result value of the comparison
"- (nn > *n)", so I've missed this part.
>
> Please take a look at the attached alternative patch that seems to work for
> me:
Works for me as well. Thanks.
>
> 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
>
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox