NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/58922: itimer(9): arithmetic overflow
>Number: 58922
>Category: kern
>Synopsis: itimer(9): arithmetic overflow
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Dec 20 02:05:00 +0000 2024
>Originator: Taylor R Campbell
>Release: current, 10, 9, ...
>Organization:
The TimeBSD Overflowndation
>Environment:
>Description:
When an itimer (setitimer, timer_settime, timerfd_settime) expires, and it has been configured with a periodic interval, the computation of the next expiry time works by converting timespecs for now, the last expiry time, and the interval to 64-bit nanoseconds:
872 now_ns = timespec2ns(&now);
873 last_val = timespec2ns(&it->it_time.it_value);
874 interval = timespec2ns(&it->it_time.it_interval);
875
876 next_val = now_ns +
877 (now_ns - last_val + interval - 1) % interval;
878
879 if (backwards)
880 next_val += interval;
881 else
882 it->it_overruns += (now_ns - last_val) / interval;
883
884 it->it_time.it_value.tv_sec = next_val / 1000000000;
885 it->it_time.it_value.tv_nsec = next_val % 1000000000;
https://nxr.netbsd.org/xref/src/sys/kern/kern_time.c?r=1.223#872
Although the current time probably isn't going to overflow this conversion until the year 2514 (or we have deeper problems -- which we might be vulnerable to, like a rogue ntp server, but that's a separate issue), unprivileged userland controls the value of it->it_time.it_interval within any valid nonnegative struct timespec -- that is, the only constraint is that tv_sec be nonnegative and tv_nsec lie within [0, 999999999].
The magic interval {18446744073, 709551616} overflows to exactly 2^64, triggering divide-by-zero in the kernel.
>How-To-Repeat:
#include <err.h>
#include <time.h>
#include <unistd.h>
int
main(void)
{
const struct itimerspec it = {
.it_value = {0, 1},
.it_interval = {18446744073, 709551616},
};
timer_t t;
if (timer_create(CLOCK_MONOTONIC, NULL, &t) == -1)
err(1, "timer_create");
if (timer_settime(t, 0, &it, NULL) == -1)
err(1, "timer_settime");
if (nanosleep(&(const struct timespec){0, 1}, NULL) == -1)
err(1, "nanosleep");
return 0;
}
>Fix:
Yes, please!
Home |
Main Index |
Thread Index |
Old Index