diff options
author | 2019-01-31 05:00:18 +0000 | |
---|---|---|
committer | 2019-01-31 05:00:18 +0000 | |
commit | e12a049bd4bbd1e8315c373a739e08972ed6dd1d (patch) | |
tree | 89b2f2100ef5c9651266cbd1dec8063e3f74e8ed | |
parent | use "sc" as the name of the softc variable in the ioctl code too. (diff) | |
download | wireguard-openbsd-e12a049bd4bbd1e8315c373a739e08972ed6dd1d.tar.xz wireguard-openbsd-e12a049bd4bbd1e8315c373a739e08972ed6dd1d.zip |
tc_setclock: Don't rewind the system uptime during resume/unhibernate.
When we come back from suspend/hibernate the BIOS/firmware/whatever can
hand us *any* TOD, so we need to check that the given TOD doesn't set our
boot offset backwards, breaking the monotonicity of e.g. CLOCK_MONOTONIC.
This is trivial to do from the BIOS on most PCs before unhibernating.
There might be other ways it can happen, accidentally or otherwise.
This is a bit messy but it can be made prettier later with a "bintimecmp"
macro or something like that.
Problem confirmed by jmatthew@.
"you are very likely right" deraadt@
-rw-r--r-- | sys/kern/kern_tc.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index 5fde04474a7..607d06fbeee 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_tc.c,v 1.36 2019/01/20 01:13:03 cheloha Exp $ */ +/* $OpenBSD: kern_tc.c,v 1.37 2019/01/31 05:00:18 cheloha Exp $ */ /* * Copyright (c) 2000 Poul-Henning Kamp <phk@FreeBSD.org> @@ -382,6 +382,7 @@ void tc_setclock(const struct timespec *ts) { struct bintime bt, bt2; + struct timespec earlier; static int first = 1; #ifndef SMALL_KERNEL long long adj_ticks; @@ -402,6 +403,20 @@ tc_setclock(const struct timespec *ts) mtx_enter(&timecounter_mtx); timespec2bintime(ts, &bt); bintime_sub(&bt, &timehands->th_boottime); + + /* + * Don't rewind the offset. + */ + if (bt.sec < timehands->th_offset.sec || + (bt.sec == timehands->th_offset.sec && + bt.frac < timehands->th_offset.frac)) { + mtx_leave(&timecounter_mtx); + bintime2timespec(&bt, &earlier); + printf("%s: cannot rewind uptime to %lld.%09ld\n", + __func__, (long long)earlier.tv_sec, earlier.tv_nsec); + return; + } + bt2 = timehands->th_offset; timehands->th_offset = bt; |