Fix overflow for timeout values of more than 68 years, which is the maximum

covered by sbintime (LONG_MAX seconds).

Some programs use timeout values in excess of 1000 years. The conversion
to sbintime caused wrap-around on overflow, which resulted in short or
negative timeout values. This caused long delays on sockets opened by
affected programs (e.g. OpenSSH).

Kernels compiled without -fno-strict-overflow were not affected, apparently
because the compiler tested the sign of the timeout value before performing
the multiplication that lead to overflow.

When the -fno-strict-overflow option was added to CFLAGS, this optimization
was disabled and the test was performed on the result of the multiplication.
Negative products were caught and resulted in EINVAL being returned, but
wrap-around to positive values just shortened the timeout value to the
residue of the result that could be represented by sbintime.

The fix is to cap the timeout values at the maximum that can be represented
by sbintime, which is 2^31 - 1 seconds or more than 68 years.

After this change, the kernel can be compiled with -fno-strict-overflow
with no ill effects.

MFC after:	3 days
This commit is contained in:
Stefan Eßer 2013-12-19 09:01:46 +00:00
parent 6311cc9efe
commit 53d5cc255d

View File

@ -526,7 +526,8 @@ knote_fork(struct knlist *list, int pid)
static __inline sbintime_t
timer2sbintime(intptr_t data)
{
if (data > LLONG_MAX / SBT_1MS)
return LLONG_MAX;
return (SBT_1MS * data);
}