Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 15 May 2009 13:32:52 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Brooks Davis <brooks@freebsd.org>
Cc:        svn-src-projects@freebsd.org, src-committers@freebsd.org
Subject:   Re: svn commit: r192087 - in projects/ngroups: lib/libc/gen lib/libc/rpc lib/libc/sys usr.bin/id usr.bin/newgrp usr.bin/quota usr.sbin/chown usr.sbin/chroot usr.sbin/jail usr.sbin/jexec usr.sbin/lpr/lpc
Message-ID:  <20090515122400.B15792@delplex.bde.org>
In-Reply-To: <200905140650.n4E6oURU079910@svn.freebsd.org>
References:  <200905140650.n4E6oURU079910@svn.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 14 May 2009, Brooks Davis wrote:

> Log:
>  Use to value returned by sysconf(_SC_NGROUPS_MAX) in favor of
>  NGROUPS_MAX or NGROUPS since POSIX says that NGROUPS_MAX represents a
>  lower bound on sysconf(_SC_NGROUPS_MAX).

Actually, POSIX says that NGROUPS_MAX is identical to
sysconf(_SC_NGROUPS_MAX) if it is defined (and the sysconf() succeeds).
It is _POSIX_NGROUPS_MAX that gives the lower bound.  _POSIX_NGROUPS_MAX
is always 8, except under old versions of POSIX that don't require
supplementary groups to be supported, where it is always 0.  It is a
bug for a POSIX implementation to define NGROUPS_MAX if its value is
not always identical to sysconf(_SC_NGROUPS_MAX), or for a POSIX
application to use NGROUPS_MAX unconditionally.

> Modified: projects/ngroups/lib/libc/gen/initgroups.c
> ==============================================================================
> --- projects/ngroups/lib/libc/gen/initgroups.c	Thu May 14 06:48:38 2009	(r192086)
> +++ projects/ngroups/lib/libc/gen/initgroups.c	Thu May 14 06:50:30 2009	(r192087)
> @@ -35,10 +35,12 @@ __FBSDID("$FreeBSD$");
>
> #include <sys/param.h>
>
> +#include <stdlib.h>

Insertion sort error.

> #include <stdio.h>
> #include "namespace.h"
> #include <err.h>
> #include "un-namespace.h"
> +#include <errno.h>

Insertion sort error.

> #include <unistd.h>
>
> int
> @@ -46,14 +48,20 @@ initgroups(uname, agroup)
> 	const char *uname;
> 	gid_t agroup;
> {
> -	int ngroups;
> +	int ngroups, ret;
> +	gid_t *groups;

Insertion sort error.

> +
> 	/*
> -	 * Provide space for one group more than NGROUPS to allow
> +	 * Provide space for one group more than possible to allow
> 	 * setgroups to fail and set errno.
> 	 */
> -	gid_t groups[NGROUPS + 1];
> +	ngroups = sysconf(_SC_NGROUPS_MAX) + 1;

This is missing error checking and overflow checking:
- sysconf() returns -1 on error
- sysconf() returns long so assigning to an int gives undefined behaviour
   if its value is preposterously large
- adding 1 to sysconf() may cause overflow before the assignment.

> +	groups = malloc(sizeof(gid_t)*ngroups);

This has style bugs and is missing and is missing overflow checking:
- missing spaces around binary operator
- the multiplication overflows if ngroups is preposterously large

See ps/args.c for the messy error handing needed for a similar case
(_SC_ARG_MAX for ps).  For groups, your changes would be cleaner and
correcter using a utility function to handle all the details.  Something
like the following:

%%%
gid_t *
allocgroups(void)
{
 	long ngroups_max;

 	ngroups_max = sysconf(_SC_NGROUPS_MAX);
 	if (ngroups_max < 0 || ngroups_max > LONG_MAX - 1 ||
 	    ngroups_max > SIZE_MAX / sizeof(gid_t) - 1)
 		return (NULL);
 	return (malloc(sizeof(gid_t) * (ngroups_max + 1)));
}
%%%

> +	if (groups == NULL)
> +		return (ENOSPC);

ENOSPC means no space on a device.  ENOMEM should be used.

Neither ENOSPC nor ENOMEM is a documented errno for initgroups(3).  The
documented errors are those for setgroups(2).

>
> -	ngroups = NGROUPS + 1;
> 	getgrouplist(uname, agroup, groups, &ngroups);
> -	return (setgroups(ngroups, groups));
> +	ret = setgroups(ngroups, groups);
> +	free(groups);
> +	return(ret);
> }

Lost the space after 'return'.

> ...

Similarly, except the whitespace errors are smaller.

One function aborts on getgroups() failure so maybe it can't handle
returning NULL on malloc() failure.  Another function uses err()
for malloc() failure and warn() for getgroups() failure.  Of course,
malloc() cannot fail and library functions cannot abort or exit :-).

> Modified: projects/ngroups/lib/libc/sys/getgroups.2
> ==============================================================================
> --- projects/ngroups/lib/libc/sys/getgroups.2	Thu May 14 06:48:38 2009	(r192086)
> +++ projects/ngroups/lib/libc/sys/getgroups.2	Thu May 14 06:50:30 2009	(r192087)
> @@ -59,7 +59,7 @@ system call
> returns the actual number of groups returned in
> .Fa gidset .
> No more than
> -.Dv NGROUPS_MAX
> +.Fn sysconf _SC_NGROUPS_MAX
> will ever
> be returned.
> If

This and many other places should use POSIX notation {FOO_MAX} for limits.
Saying either NGROUPS_MAX or sysconf(_SC_NGROUPS_MAX} overspecifies the
behaviour and makes it hard to change.  Since getroups() is a syscall and
you haven't changed the kernel yet, NGROUPS_MAX is still correct here.

> @@ -91,7 +91,8 @@ an invalid address.
> .El
> .Sh SEE ALSO
> .Xr setgroups 2 ,
> -.Xr initgroups 3
> +.Xr initgroups 3 ,
> +.Xr sysconf 3

POSIX doesn't bloat man pages that refer to {FOO_MAX} with references to
sysconf().  Here the cross-reference is even less needed since the
reference to sysconf() is explicit in context.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090515122400.B15792>