svn commit: r347063 - head/sys/kern
Bruce Evans
brde at optusnet.com.au
Tue May 7 17:44:06 UTC 2019
On Tue, 7 May 2019, John Baldwin wrote:
> On 5/7/19 8:45 AM, Bruce Evans wrote:
>> On Mon, 6 May 2019, John Baldwin wrote:
>>
>>> On 5/6/19 11:45 AM, Mark Johnston wrote:
>>>> On Mon, May 06, 2019 at 11:07:18AM -0700, John Baldwin wrote:
>>>>> On 5/3/19 2:26 PM, Mark Johnston wrote:
>>>>>> Author: markj
>>>>>> Date: Fri May 3 21:26:44 2019
>>>>>> New Revision: 347063
>>>>>> URL: https://svnweb.freebsd.org/changeset/base/347063
>>>>>>
>>>>>> Log:
>>>>>> Disallow excessively small times of day in clock_settime(2).
>>
>> This actually disallows negative timespecs in clock_settime(), with
>> collateral disallowment for small positive times.
>
> FWIW, clock_settime already disallows negative times due to the
> existing check in the previous two lines:
>
> if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000 ||
> ats->tv_sec < 0)
> return (EINVAL);
>
> I would probably lean towards not disallowing negative times as I
> said in one of my earlier replies, but given we have that blanket
> check already in place, the current patch doesn't seem to make
> things much worse.
This check was correctly missing in FreeBSD-5.
This check doesn't actually work. I rememeber another detail in my test
program. It sets the time to INT_MAX - 2 == INT32_MAX - 2 to get an
overflow 2 seconds later with 32-bit time_t. This is how I got a file
time of 1901.
The check for large times on the line after the above is broken in another
way. It has an upper limit of approx. 8000ULL years. This limit is
unreachable for 32-bit time_t (except for the unsign extension bug for
negative times which is unreachable due to the above check). So the check
only works to prevent overflow to a negative time with 64-bit time_t.
Other parts of the system are or were more careful about this:
- setitimer() and alarm() used to have a limit of 10**8 seconds to
prevent overflow of 32-bit time_t when adding this number to the
current time. 10**8 seconds is 3.16 years, so this works up to about
2035. This was broken by silently removing the check for 10**8 in
itimerfix() as part of implementing POSIX itimers but the man pages
still document the limit. This is not allowed by POSIX. POSIX
requires times to work up to the limit of a time_t. Some APIs return
the residual time after a timeout, so this cannot be implemented by
clamping the time to a reasonably small value. POSIX itimers have a
different implementation that is closer to not needing this limit
and more broken having it.
setitimer() is also broken for negative times (doesn't allow them).
IIRC, POSIX requires this bug. This just give more work for applications.
Small negative differences can easily occur as the result of subtracting
times. Applications must either check for them after calculating
differences, or handle the error for them from setimer(). Usually the
correct handling is to treat negative timeouts as 0.
- sbintimes have 32 bits for the seconds part, so they have similar
problems to 32-bit time_t. Some places handle these problems by limiting
the timeouts to INT32_MAX / 2. The timeout is sometimes added to the
current time, but since the current time is the monotonic time it is at
most a few years so the limit for the timeout could be a bit larger than
INT32_MAX / 2.
Oops, sbintimes are now used for for setitimer(), and setitimer() is one
of the few places with the INT32_MAX / 2 limit. This gives the following
bugs for setitimer() and alarm():
- these syscalls still have a limit which is not allowed by POSIX
- the limit is INT32_MAX / 2 seconds (+ maximal usec?), not the documented
one.
64_bit time_t's mostly just increase the overflow bugs. Applications can
probe for bugs using INT64_MAX in tv_sec. This overflows all 32-bit
calculations and most signed 64-bit calculations. The kernel has to
reduce to 32 bits in seconds for all uses of sbintimes. The kernel
does do this for nanosleep().
Bruce
More information about the svn-src-head
mailing list