From 708d89f83cd56f6262879af84e903cce4574143f Mon Sep 17 00:00:00 2001 From: cheloha Date: Tue, 22 May 2018 19:15:23 +0000 Subject: kevent: correctly check that timeout's nanoseconds are on [0, 1000000000) Validate the input with timespecfix before truncating to a timeval. timespecfix does not round, so we need to to it by hand after validation. FreeBSD and NetBSD check the input with this range, we ought to as well. Also add a regression test for this case. ok tb@ --- regress/sys/kern/kqueue/Makefile | 6 ++++-- regress/sys/kern/kqueue/kqueue-timer.c | 31 ++++++++++++++++++++++++++++++- regress/sys/kern/kqueue/main.c | 7 +++++-- regress/sys/kern/kqueue/main.h | 3 ++- sys/kern/kern_event.c | 17 ++++++++++------- 5 files changed, 51 insertions(+), 13 deletions(-) diff --git a/regress/sys/kern/kqueue/Makefile b/regress/sys/kern/kqueue/Makefile index 823f6e99161..b07b46eaffe 100644 --- a/regress/sys/kern/kqueue/Makefile +++ b/regress/sys/kern/kqueue/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.19 2016/09/20 23:05:27 bluhm Exp $ +# $OpenBSD: Makefile,v 1.20 2018/05/22 19:15:22 cheloha Exp $ PROG= kqueue-test CFLAGS+=-Wall @@ -32,9 +32,11 @@ kq-flock: ${PROG} ./${PROG} -l kq-timer: ${PROG} ./${PROG} -i +kq-invalid-timer: ${PROG} + ./${PROG} -I REGRESS_TARGETS=kq-pipe kq-fork kq-process kq-random kq-pty kq-signal \ - kq-fdpass kq-flock kq-timer + kq-fdpass kq-flock kq-timer kq-invalid-timer # kq-tun broke at some point, apparently from a change in tun routing REGRESS_ROOT_TARGETS=${REGRESS_TARGETS} .PHONY: ${REGRESS_TARGETS} diff --git a/regress/sys/kern/kqueue/kqueue-timer.c b/regress/sys/kern/kqueue/kqueue-timer.c index 02114b5094e..e95c3ba4e52 100644 --- a/regress/sys/kern/kqueue/kqueue-timer.c +++ b/regress/sys/kern/kqueue/kqueue-timer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kqueue-timer.c,v 1.2 2016/09/20 23:05:27 bluhm Exp $ */ +/* $OpenBSD: kqueue-timer.c,v 1.3 2018/05/22 19:15:22 cheloha Exp $ */ /* * Copyright (c) 2015 Bret Stephen Lambert * @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -68,3 +69,31 @@ do_timer(void) return (0); } + +int +do_invalid_timer(void) +{ + int i, kq, n; + struct kevent ev; + struct timespec invalid_ts[3] = { {-1, 0}, {0, -1}, {0, 1000000000L} }; + + ASS((kq = kqueue()) >= 0, + warn("kqueue")); + + memset(&ev, 0, sizeof(ev)); + ev.filter = EVFILT_TIMER; + ev.flags = EV_ADD | EV_ENABLE; + ev.data = 500; /* 1/2 second in ms */ + + n = kevent(kq, &ev, 1, NULL, 0, NULL); + ASSX(n != -1); + + for (i = 0; i < 3; i++) { + n = kevent(kq, NULL, 0, &ev, 1, &invalid_ts[i]); + ASS(n == -1 && errno == EINVAL, + warn("kevent: timeout %lld %ld", + (long long)invalid_ts[i].tv_sec, invalid_ts[i].tv_nsec)); + } + + return (0); +} diff --git a/regress/sys/kern/kqueue/main.c b/regress/sys/kern/kqueue/main.c index 78ca80adb25..2dcafeecb30 100644 --- a/regress/sys/kern/kqueue/main.c +++ b/regress/sys/kern/kqueue/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.9 2016/09/20 23:05:27 bluhm Exp $ */ +/* $OpenBSD: main.c,v 1.10 2018/05/22 19:15:22 cheloha Exp $ */ /* * Written by Artur Grabowski 2002 Public Domain */ @@ -16,7 +16,7 @@ main(int argc, char **argv) int ret, c; ret = 0; - while ((c = getopt(argc, argv, "fFilpPrstT")) != -1) { + while ((c = getopt(argc, argv, "fFiIlpPrstT")) != -1) { switch (c) { case 'f': ret |= check_inheritance(); @@ -27,6 +27,9 @@ main(int argc, char **argv) case 'i': ret |= do_timer(); break; + case 'I': + ret |= do_invalid_timer(); + break; case 'l': ret |= do_flock(); break; diff --git a/regress/sys/kern/kqueue/main.h b/regress/sys/kern/kqueue/main.h index 430d63cd05b..e34fd4f9a7a 100644 --- a/regress/sys/kern/kqueue/main.h +++ b/regress/sys/kern/kqueue/main.h @@ -1,4 +1,4 @@ -/* $OpenBSD: main.h,v 1.1 2016/09/20 23:05:27 bluhm Exp $ */ +/* $OpenBSD: main.h,v 1.2 2018/05/22 19:15:22 cheloha Exp $ */ /* * Written by Alexaner Bluhm 2016 Public Domain */ @@ -18,6 +18,7 @@ int check_inheritance(void); int do_fdpass(void); int do_flock(void); +int do_invalid_timer(void); int do_pipe(void); int do_process(void); int do_pty(void); diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index dd5cb18d748..f306a33e669 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_event.c,v 1.88 2018/04/27 10:13:37 mpi Exp $ */ +/* $OpenBSD: kern_event.c,v 1.89 2018/05/22 19:15:22 cheloha Exp $ */ /*- * Copyright (c) 1999,2000,2001 Jonathan Lemon @@ -693,6 +693,7 @@ kqueue_scan(struct kqueue *kq, int maxevents, struct kevent *ulistp, const struct timespec *tsp, struct proc *p, int *retval) { struct kevent *kevp; + struct timespec ats; struct timeval atv, rtv, ttv; struct knote *kn, marker; int s, count, timeout, nkev = 0, error = 0; @@ -703,16 +704,18 @@ kqueue_scan(struct kqueue *kq, int maxevents, struct kevent *ulistp, goto done; if (tsp != NULL) { - TIMESPEC_TO_TIMEVAL(&atv, tsp); - if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) { + ats = *tsp; + if (ats.tv_sec > 100000000 || timespecfix(&ats)) { + error = EINVAL; + goto done; + } + TIMESPEC_TO_TIMEVAL(&atv, &ats); + if (atv.tv_sec == 0 && atv.tv_usec == 0) { /* No timeout, just poll */ timeout = -1; goto start; } - if (itimerfix(&atv)) { - error = EINVAL; - goto done; - } + itimerround(&atv); timeout = atv.tv_sec > 24 * 60 * 60 ? 24 * 60 * 60 * hz : tvtohz(&atv); -- cgit v1.2.3