From owner-dev-commits-src-branches@freebsd.org Mon Mar 15 15:41:33 2021 Return-Path: Delivered-To: dev-commits-src-branches@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 1797557ECCD; Mon, 15 Mar 2021 15:41:33 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Dzgd85FlFz3FsT; Mon, 15 Mar 2021 15:41:32 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id F15A512FE6; Mon, 15 Mar 2021 15:41:31 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 12FFfVHZ006598; Mon, 15 Mar 2021 15:41:31 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 12FFfVu2006597; Mon, 15 Mar 2021 15:41:31 GMT (envelope-from git) Date: Mon, 15 Mar 2021 15:41:31 GMT Message-Id: <202103151541.12FFfVu2006597@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Mark Johnston Subject: git: eeb0682964fc - stable/13 - posix timers: Improve the overrun calculation MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: eeb0682964fccae585ce61ee322dd0062b7a4cd6 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-branches@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commits to the stable branches of the FreeBSD src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Mar 2021 15:41:33 -0000 The branch stable/13 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=eeb0682964fccae585ce61ee322dd0062b7a4cd6 commit eeb0682964fccae585ce61ee322dd0062b7a4cd6 Author: Mark Johnston AuthorDate: 2021-03-08 17:39:06 +0000 Commit: Mark Johnston CommitDate: 2021-03-15 15:38:43 +0000 posix timers: Improve the overrun calculation timer_settime(2) may be used to configure a timeout in the past. If the timer is also periodic, we also try to compute the number of timer overruns that occurred between the initial timeout and the time at which the timer fired. This is done in a loop which iterates once per period between the initial timeout and now. If the period is small and the initial timeout was a long time ago, this loop can take forever to run, so the system is effectively DOSed. Replace the loop with a more direct calculation of (now - initial timeout) / period to compute the number of overruns. Reported by: syzkaller Reviewed by: kib Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D29093 (cherry picked from commit 7995dae9d3f58abf38ef0001cee24131f3c9054b) --- sys/kern/kern_time.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 3e85f8e1d6ec..44f6b4ad07f2 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -1603,6 +1603,13 @@ itimespecfix(struct timespec *ts) return (0); } +#define timespectons(tsp) \ + ((uint64_t)(tsp)->tv_sec * 1000000000 + (tsp)->tv_nsec) +#define timespecfromns(ns) (struct timespec){ \ + .tv_sec = (ns) / 1000000000, \ + .tv_nsec = (ns) % 1000000000 \ +} + /* Timeout callback for realtime timer */ static void realtimer_expire(void *arg) @@ -1610,6 +1617,7 @@ realtimer_expire(void *arg) struct timespec cts, ts; struct timeval tv; struct itimer *it; + uint64_t interval, now, overruns, value; it = (struct itimer *)arg; @@ -1620,14 +1628,27 @@ realtimer_expire(void *arg) timespecadd(&it->it_time.it_value, &it->it_time.it_interval, &it->it_time.it_value); - while (timespeccmp(&cts, &it->it_time.it_value, >=)) { - if (it->it_overrun < INT_MAX) - it->it_overrun++; - else + + interval = timespectons(&it->it_time.it_interval); + value = timespectons(&it->it_time.it_value); + now = timespectons(&cts); + + if (now >= value) { + /* + * We missed at least one period. + */ + overruns = howmany(now - value + 1, interval); + if (it->it_overrun + overruns >= + it->it_overrun && + it->it_overrun + overruns <= INT_MAX) { + it->it_overrun += (int)overruns; + } else { + it->it_overrun = INT_MAX; it->it_ksi.ksi_errno = ERANGE; - timespecadd(&it->it_time.it_value, - &it->it_time.it_interval, - &it->it_time.it_value); + } + value = + now + interval - (now - value) % interval; + it->it_time.it_value = timespecfromns(value); } } else { /* single shot timer ? */