Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 1 Aug 2015 20:35:56 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Baptiste Daroussin <bapt@freebsd.org>
Cc:        src-committers@freebsd.org, svn-src-all@freebsd.org,  svn-src-head@freebsd.org
Subject:   Re: svn commit: r286148 - head/usr.sbin/chkgrp
Message-ID:  <20150801200929.F2212@besplex.bde.org>
In-Reply-To: <201508010835.t718ZKiH035944@repo.freebsd.org>
References:  <201508010835.t718ZKiH035944@repo.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, 1 Aug 2015, Baptiste Daroussin wrote:

> Log:
>  Use strtoumax instead of strtoul

This does nothing good, and breaks 32-bit arches.

> Modified: head/usr.sbin/chkgrp/chkgrp.c
> ==============================================================================
> --- head/usr.sbin/chkgrp/chkgrp.c	Sat Aug  1 07:51:48 2015	(r286147)
> +++ head/usr.sbin/chkgrp/chkgrp.c	Sat Aug  1 08:35:20 2015	(r286148)
> @@ -169,9 +170,9 @@ main(int argc, char *argv[])
>
> 		/* check the range of the group id */
> 		errno = 0;
> -		gid = strtoul(f[2], NULL, 10);
> +		gid = strtoumax(f[2], NULL, 10);

gid still has type u_long (spelled verbosely as unsigned long.)  This
used to work on arches where gid_t is no larger than u_long, which is
the case on all supported arches.  Now the value returned by strtoumax()
is corrupted by blindly assigning it to u_long.  E.g., 0x100000001
becomes 1.

> 		if (errno != 0) {
> -			warnx("%s: line %d: strtoul failed", gfn, n);
> +			warnx("%s: line %d: strtoumax failed", gfn, n);

This has a less usual subset of common bugs in using the strtoul() family.
The most common bug is to not check ERANGE.  This does check ERANGE, but
doesn't check for garbage following the integer (it doesn't even pass
endptr).  It uses a POSIX extension to check that the integer has some
digits.

> 		} else if (gid > GID_MAX) {

This used to work.  Now it checks the corrupted value.

> 			warnx("%s: line %d: group id is too large (%ju > %ju)",
> 			    gfn, n, (uintmax_t)gid, (uintmax_t)GID_MAX);

This format is bogus for printing `gid'.  gid should have type gid_t, but
actually has type u_long.  u_long should be printed using %lu and no
cast.

GID_MAX is undocumented, so no one knows its type.  Its type should
be gid_t, but is actually u_int.  gid_t is logically different again
-- it is __uint32_t.  GID_MAX is defined in sys/limits.h, so there are
namespace problems in matching its type with that of gid_t.  The
current implementation is best until gid_t is expanded.

So casting GID_MAX to uintmax_t is good for safety and portability.
However, chckgrp.c already assumed that gid_t is no larger than u_long.
Otherwise it would have been broken in the reverse way to this commit
-- values would have been clamped by strtoul().  The bounds checking
would have worked, but large values would have been unsupported.  The
old value might as well have cast to u_long.  strtoumax() can support
any size for gid_t.  After fixing all the other type errors, the types
in the warnx() become correct.

Bruce



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