diff options
author | mav <mav@FreeBSD.org> | 2013-03-06 19:37:38 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2013-03-06 19:37:38 +0000 |
commit | eb7c9d2685c586dbc63824085f209d700276b116 (patch) | |
tree | e0014e3ceb1c3b632a8085f56d508783b74abf8c | |
parent | 3cc1de3474bc623e881f0ec2544b3b3fd19b98ca (diff) | |
download | FreeBSD-src-eb7c9d2685c586dbc63824085f209d700276b116.zip FreeBSD-src-eb7c9d2685c586dbc63824085f209d700276b116.tar.gz |
Fix time math overflows and improve zero intervals handling in poll(),
select(), nanosleep() and kevent() functions after calloutng changes.
Reported by: bde
-rw-r--r-- | sys/kern/kern_event.c | 15 | ||||
-rw-r--r-- | sys/kern/kern_time.c | 10 | ||||
-rw-r--r-- | sys/kern/sys_generic.c | 35 |
3 files changed, 42 insertions, 18 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 82db54e..3c8826c 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -1329,11 +1329,16 @@ kqueue_scan(struct kqueue *kq, int maxevents, struct kevent_copyops *k_ops, goto done_nl; } if (timespecisset(tsp)) { - rsbt = tstosbt(*tsp); - if (TIMESEL(&asbt, rsbt)) - asbt += tc_tick_sbt; - asbt += rsbt; - rsbt >>= tc_precexp; + if (tsp->tv_sec < INT32_MAX) { + rsbt = tstosbt(*tsp); + if (TIMESEL(&asbt, rsbt)) + asbt += tc_tick_sbt; + asbt += rsbt; + if (asbt < rsbt) + asbt = 0; + rsbt >>= tc_precexp; + } else + asbt = 0; } else asbt = -1; } else diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index da51106..9eb22c8 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -484,13 +484,20 @@ kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) { struct timespec ts; sbintime_t sbt, sbtt, prec, tmp; + time_t over; int error; if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) return (EINVAL); if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0)) return (0); - tmp = tstosbt(*rqt); + ts = *rqt; + if (ts.tv_sec > INT32_MAX / 2) { + over = ts.tv_sec - INT32_MAX / 2; + ts.tv_sec -= over; + } else + over = 0; + tmp = tstosbt(ts); prec = tmp; prec >>= tc_precexp; if (TIMESEL(&sbt, tmp)) @@ -504,6 +511,7 @@ kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) TIMESEL(&sbtt, tmp); if (rmt != NULL) { ts = sbttots(sbt - sbtt); + ts.tv_sec += over; if (ts.tv_sec < 0) timespecclear(&ts); *rmt = ts; diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 3893515..2d149b5 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -1051,12 +1051,19 @@ kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou, error = EINVAL; goto done; } - rsbt = tvtosbt(rtv); - precision = rsbt; - precision >>= tc_precexp; - if (TIMESEL(&asbt, rsbt)) - asbt += tc_tick_sbt; - asbt += rsbt; + if (rtv.tv_sec == 0 && rtv.tv_usec == 0) + asbt = 0; + else if (rtv.tv_sec < INT32_MAX) { + rsbt = tvtosbt(rtv); + precision = rsbt; + precision >>= tc_precexp; + if (TIMESEL(&asbt, rsbt)) + asbt += tc_tick_sbt; + asbt += rsbt; + if (asbt < rsbt) + asbt = -1; + } else + asbt = -1; } else asbt = -1; seltdinit(td); @@ -1295,12 +1302,16 @@ sys_poll(td, uap) error = EINVAL; goto done; } - rsbt = SBT_1MS * uap->timeout; - precision = rsbt; - precision >>= tc_precexp; - if (TIMESEL(&asbt, rsbt)) - asbt += tc_tick_sbt; - asbt += rsbt; + if (uap->timeout == 0) + asbt = 0; + else { + rsbt = SBT_1MS * uap->timeout; + precision = rsbt; + precision >>= tc_precexp; + if (TIMESEL(&asbt, rsbt)) + asbt += tc_tick_sbt; + asbt += rsbt; + } } else asbt = -1; seltdinit(td); |