Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 20 May 2021 14:10:40 GMT
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: ec00c33f8181 - stable/13 - posix timers: Check for overflow when converting to ns
Message-ID:  <202105201410.14KEAeC2039008@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=ec00c33f8181978cdeb56b392ce9e5a823251483

commit ec00c33f8181978cdeb56b392ce9e5a823251483
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2021-05-13 12:33:37 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2021-05-20 13:16:05 +0000

    posix timers: Check for overflow when converting to ns
    
    Disallow a time or timer period value when the conversion to nanoseconds
    would overflow.  Otherwise it is possible to trigger a divison by zero
    in realtime_expire_l(), where we compute the number of overruns by
    dividing by the timer interval.
    
    Fixes:  7995dae9 ("posix timers: Improve the overrun calculation")
    Reported by:    syzbot+5ab360bd3d3e3c5a6e0e@syzkaller.appspotmail.com
    Reported by:    syzbot+157b74ff493140d86eac@syzkaller.appspotmail.com
    Reviewed by:    kib
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D30233
    
    (cherry picked from commit 8b3c4231abf0ef6ac79655e463d0ef98ad84cd51)
---
 sys/kern/kern_time.c | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
index ab22ac4a1697..323ef9a1f7a0 100644
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -72,6 +72,8 @@ __FBSDID("$FreeBSD$");
 #define MAKE_PROCESS_CPUCLOCK(pid)	\
 	(CPUCLOCK_BIT|CPUCLOCK_PROCESS_BIT|(pid))
 
+#define NS_PER_SEC	1000000000
+
 static struct kclock	posix_clocks[MAX_CLOCKS];
 static uma_zone_t	itimer_zone = NULL;
 
@@ -408,8 +410,7 @@ kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats)
 		return (error);
 	if (clock_id != CLOCK_REALTIME)
 		return (EINVAL);
-	if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000 ||
-	    ats->tv_sec < 0)
+	if (ats->tv_nsec < 0 || ats->tv_nsec >= NS_PER_SEC || ats->tv_sec < 0)
 		return (EINVAL);
 	if (!allow_insane_settime &&
 	    (ats->tv_sec > 8000ULL * 365 * 24 * 60 * 60 ||
@@ -462,12 +463,12 @@ kern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts)
 		 * Rounding up is especially important if rounding down
 		 * would give 0.  Perfect rounding is unimportant.
 		 */
-		ts->tv_nsec = 1000000000 / tc_getfrequency() + 1;
+		ts->tv_nsec = NS_PER_SEC / tc_getfrequency() + 1;
 		break;
 	case CLOCK_VIRTUAL:
 	case CLOCK_PROF:
 		/* Accurately round up here because we can do so cheaply. */
-		ts->tv_nsec = howmany(1000000000, hz);
+		ts->tv_nsec = howmany(NS_PER_SEC, hz);
 		break;
 	case CLOCK_SECOND:
 		ts->tv_sec = 1;
@@ -509,7 +510,7 @@ kern_clock_nanosleep(struct thread *td, clockid_t clock_id, int flags,
 	int error;
 	bool is_abs_real;
 
-	if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000)
+	if (rqt->tv_nsec < 0 || rqt->tv_nsec >= NS_PER_SEC)
 		return (EINVAL);
 	if ((flags & ~TIMER_ABSTIME) != 0)
 		return (EINVAL);
@@ -1650,7 +1651,9 @@ static int
 itimespecfix(struct timespec *ts)
 {
 
-	if (ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000)
+	if (ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= NS_PER_SEC)
+		return (EINVAL);
+	if ((UINT64_MAX - ts->tv_nsec) / NS_PER_SEC < ts->tv_sec)
 		return (EINVAL);
 	if (ts->tv_sec == 0 && ts->tv_nsec != 0 && ts->tv_nsec < tick * 1000)
 		ts->tv_nsec = tick * 1000;
@@ -1658,10 +1661,10 @@ itimespecfix(struct timespec *ts)
 }
 
 #define	timespectons(tsp)			\
-	((uint64_t)(tsp)->tv_sec * 1000000000 + (tsp)->tv_nsec)
+	((uint64_t)(tsp)->tv_sec * NS_PER_SEC + (tsp)->tv_nsec)
 #define	timespecfromns(ns) (struct timespec){	\
-	.tv_sec = (ns) / 1000000000,		\
-	.tv_nsec = (ns) % 1000000000		\
+	.tv_sec = (ns) / NS_PER_SEC,		\
+	.tv_nsec = (ns) % NS_PER_SEC		\
 }
 
 static void



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202105201410.14KEAeC2039008>