From owner-dev-commits-src-all@freebsd.org Mon Mar 8 17:55:09 2021 Return-Path: Delivered-To: dev-commits-src-all@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 65BCE550D57; Mon, 8 Mar 2021 17:55:09 +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 4DvQwX5fqtz3CRv; Mon, 8 Mar 2021 17:55:07 +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 59D5F56D9; Mon, 8 Mar 2021 17:55:06 +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 128Ht6we069431; Mon, 8 Mar 2021 17:55:06 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 128Ht6UV069430; Mon, 8 Mar 2021 17:55:06 GMT (envelope-from git) Date: Mon, 8 Mar 2021 17:55:06 GMT Message-Id: <202103081755.128Ht6UV069430@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Mark Johnston Subject: git: 7995dae9d3f5 - main - 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/main X-Git-Reftype: branch X-Git-Commit: 7995dae9d3f58abf38ef0001cee24131f3c9054b Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-all@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for all branches of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 08 Mar 2021 17:55:09 -0000 The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=7995dae9d3f58abf38ef0001cee24131f3c9054b commit 7995dae9d3f58abf38ef0001cee24131f3c9054b Author: Mark Johnston AuthorDate: 2021-03-08 17:39:06 +0000 Commit: Mark Johnston CommitDate: 2021-03-08 17:39:06 +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 MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D29093 --- 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 ? */