summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2013-03-06 19:37:38 +0000
committermav <mav@FreeBSD.org>2013-03-06 19:37:38 +0000
commiteb7c9d2685c586dbc63824085f209d700276b116 (patch)
treee0014e3ceb1c3b632a8085f56d508783b74abf8c
parent3cc1de3474bc623e881f0ec2544b3b3fd19b98ca (diff)
downloadFreeBSD-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.c15
-rw-r--r--sys/kern/kern_time.c10
-rw-r--r--sys/kern/sys_generic.c35
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);
OpenPOWER on IntegriCloud