standards/149980: [libc] [patch] negative value integer to nanosleep(2) should fail with EINVAL

Bruce Evans brde at optusnet.com.au
Wed Feb 23 23:07:13 UTC 2011


On Wed, 23 Feb 2011, Alexander Best wrote:

> The following reply was made to PR standards/149980; it has been noted by GNATS.
>
> From: Alexander Best <arundel at freebsd.org>
> To: bug-followup at freebsd.org
> Cc:
> Subject: Re: standards/149980: [libc] [patch] negative value integer to nanosleep(2) should fail with EINVAL
> Date: Wed, 23 Feb 2011 21:38:02 +0000
>
> since this might break some ports or 3rd party applications, how about adding
> something like kern.allow_negative_sleep?

It shouldn't fail.  POSIX doesn't require it to fail, at least in the old
2001 draft7:

% 26886 ERRORS
% 26887              The nanosleep( ) function shall fail if:
% 26888              [EINTR]              The nanosleep( ) function was interrupted by a signal.
% 26889              [EINVAL]             The rqtp argument specified a nanosecond value less than zero or greater than
% 26890                                   or equal to 1000 million.

It just specifies EINVAL for out-of-bounds nanoseconds values because those
give an invalid timeval.  Negative values for the seconds field are valid
if they are representable.

A negative sleep time is equally physically impossible as a sleep time
of 0, but I haven't seen any proposals to break the latter.  But if you
want full breakage, be sure to disallow both negative timevals and ones
longer than the lifetime of the universe ;-).

In private or maybe public old mail about this, I pointed out bugs in
itimerfix() and itimespecfix().  These functions do generate EINVAL
for negative times and are very broken for large positive values
considerably shorter than the lifetime of the universe for 32-bit
time_t's but considerably longer than the lifetime of the universe for
64-bit time_t's.  Callers depend on the time_t's being considerably
less than the time until the time_t's wrap around.  This used ti be
avoided (until 2035 for 32-bit signed time_t's) by restricting the
time_t's to 1000 million seconds (3+ years) in itimerfix().  This has
been broken, so anyone who can make syscalls that use itimers can cause
overflows in the kernel.  Limiting the maximum itimer to 100 million
seconds or even the lifetime of the univers is not supported by POSIX,
but it is what BSD always did until FreeBSD broke it.  itimerfix() and
itimespecfix() also do bogus rounding up to a multiple of the timer
granularity.  This is mostly cosmetic, but breaks syscalls that return
residual times.  itimespecfix() also has a namespace error.  It corresponds
to itimerfix().  There is no itimevalfix(), but there is a confusingly
similar timevalfix().

These bugs don't directly affect nanosleep(), since it doesn't use
itimespecfix(), perhaps intentionally to avoid breaking it for negative
times.  Its overflow bugs bugs are smaller in nanosleep(), since it
loops internally to handle large times and its algorithm of comparing
the current time with the end time in case it wakes up early is fairly
robust.  However, it blindly adds timespecs using timespecadd(&ts,
rqt), where ts is initially the current time (spec) and *rqt is the
arg, and ts is finally the end time.  *rqt must be limited to prevent
overflow of this.  The usual (but broken) limit of 100 million seconds
would work (until 2035) as elsewhere.  When overflow occurs, the result
is undefined.  The actual behaviour is normally a garbage negative end
time in ts, and although there are lots of compensating overflows
(adding and subtracting the current time), I think the logic isn't all
accidentally correct throughout.

Bruce


More information about the freebsd-standards mailing list