Page MenuHomeFreeBSD

D27571.id81139.diff
No OneTemporary

D27571.id81139.diff

Index: include/time.h
===================================================================
--- include/time.h
+++ include/time.h
@@ -117,6 +117,7 @@
#define CLOCK_SECOND 13 /* FreeBSD-specific. */
#define CLOCK_THREAD_CPUTIME_ID 14
#define CLOCK_PROCESS_CPUTIME_ID 15
+/* CLOCK_ADJUST_REALTIME 16 is FreeBSD-private */
#endif /* !defined(CLOCK_MONOTONIC) && __POSIX_VISIBLE >= 200112 */
#if __BSD_VISIBLE
Index: lib/libc/gen/Makefile.inc
===================================================================
--- lib/libc/gen/Makefile.inc
+++ lib/libc/gen/Makefile.inc
@@ -28,6 +28,7 @@
check_utility_compat.c \
clock.c \
clock_getcpuclockid.c \
+ clock_settime_adjust.c \
closedir.c \
confstr.c \
crypt.c \
Index: lib/libc/gen/Symbol.map
===================================================================
--- lib/libc/gen/Symbol.map
+++ lib/libc/gen/Symbol.map
@@ -422,6 +422,7 @@
};
FBSD_1.6 {
+ clock_settime_adjust;
getlogin_r;
memalign;
scandir_b;
Index: lib/libc/gen/clock_settime_adjust.c
===================================================================
--- /dev/null
+++ lib/libc/gen/clock_settime_adjust.c
@@ -0,0 +1,49 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+int
+clock_settime_adjust(const struct timespec *adj, struct timespec *new)
+{
+ struct timespec adj1;
+ int error;
+
+ adj1 = *adj;
+ error == syscall(SYS_clock_settime, CLOCK_ADJUST_REALTIME, &adj1);
+ if (error == 0 && new != NULL)
+ *new = adj1;
+ return (error);
+}
Index: sys/compat/freebsd32/freebsd32_misc.c
===================================================================
--- sys/compat/freebsd32/freebsd32_misc.c
+++ sys/compat/freebsd32/freebsd32_misc.c
@@ -2919,17 +2919,27 @@
freebsd32_clock_settime(struct thread *td,
struct freebsd32_clock_settime_args *uap)
{
- struct timespec ats;
- struct timespec32 ats32;
+ struct timespec ats, ots;
+ struct timespec32 ats32, ots32;
int error;
error = copyin(uap->tp, &ats32, sizeof(ats32));
- if (error)
+ if (error != 0)
return (error);
CP(ats32, ats, tv_sec);
CP(ats32, ats, tv_nsec);
- return (kern_clock_settime(td, uap->clock_id, &ats));
+ error = kern_clock_settime(td, uap->clock_id, &ats, &ots);
+ if (error != 0)
+ return (error);
+
+ if (uap->clock_id == CLOCK_ADJUST_REALTIME) {
+ CP(ots, ots32, tv_sec);
+ CP(ots, ots32, tv_nsec);
+ error = copyout(&ots32, __DECONST(void *, uap->tp),
+ sizeof(ots32));
+ }
+ return (error);
}
int
Index: sys/compat/linux/linux_time.c
===================================================================
--- sys/compat/linux/linux_time.c
+++ sys/compat/linux/linux_time.c
@@ -422,7 +422,7 @@
return (error);
}
- error = kern_clock_settime(td, nwhich, &ts);
+ error = kern_clock_settime(td, nwhich, &ts, NULL);
if (error != 0)
LIN_SDT_PROBE1(time, linux_clock_settime, settime_error, error);
Index: sys/dev/hyperv/utilities/vmbus_timesync.c
===================================================================
--- sys/dev/hyperv/utilities/vmbus_timesync.c
+++ sys/dev/hyperv/utilities/vmbus_timesync.c
@@ -132,7 +132,7 @@
}
hv_ts.tv_sec = hv_ns / NANOSEC;
hv_ts.tv_nsec = hv_ns % NANOSEC;
- kern_clock_settime(curthread, CLOCK_REALTIME, &hv_ts);
+ kern_clock_settime(curthread, CLOCK_REALTIME, &hv_ts, NULL);
/* Done! */
return;
}
@@ -164,7 +164,8 @@
}
hv_ts.tv_sec = hv_ns / NANOSEC;
hv_ts.tv_nsec = hv_ns % NANOSEC;
- kern_clock_settime(curthread, CLOCK_REALTIME, &hv_ts);
+ kern_clock_settime(curthread, CLOCK_REALTIME, &hv_ts,
+ NULL);
}
/* Done */
return;
Index: sys/kern/kern_tc.c
===================================================================
--- sys/kern/kern_tc.c
+++ sys/kern/kern_tc.c
@@ -1245,7 +1245,7 @@
* when we booted.
*/
void
-tc_setclock(struct timespec *ts)
+tc_setclock(struct timespec *ts, struct timespec *ots, bool abs)
{
struct timespec tbef, taft;
struct bintime bt, bt2;
@@ -1254,11 +1254,19 @@
nanotime(&tbef);
mtx_lock_spin(&tc_setclock_mtx);
cpu_tick_calibrate(1);
- binuptime(&bt2);
- bintime_sub(&bt, &bt2);
+ if (abs) {
+ binuptime(&bt2);
+ bintime_sub(&bt, &bt2);
+ }
- /* XXX fiddle all the little crinkly bits around the fiords... */
+ /*
+ * Fiddle all the little crinkly bits around the fiords...
+ * If requested, return the time after adjustment, under the
+ * tc_setclock spinlock to be as close to result as possible.
+ */
tc_windup(&bt);
+ if (ots != NULL)
+ getnanotime(ots);
mtx_unlock_spin(&tc_setclock_mtx);
/* Avoid rtc_generation == 0, since td_rtcgen == 0 is special. */
Index: sys/kern/kern_time.c
===================================================================
--- sys/kern/kern_time.c
+++ sys/kern/kern_time.c
@@ -86,6 +86,9 @@
*/
static int settime(struct thread *, struct timeval *);
+static int steplimit(struct thread *td, struct timeval *tv, bool abs);
+static int steptime(struct thread *, struct timeval *, struct timeval *,
+ bool abs);
static void timevalfix(struct timeval *);
static int user_clock_nanosleep(struct thread *td, clockid_t clock_id,
int flags, const struct timespec *ua_rqtp,
@@ -115,16 +118,25 @@
SYSINIT(posix_timer, SI_SUB_P1003_1B, SI_ORDER_FIRST+4, itimer_start, NULL);
+static struct timeval maxtime, laststep;
+static struct mtx sl_lock;
+MTX_SYSINIT(sl_lock, &sl_lock, "sll", MTX_DEF);
+
static int
-settime(struct thread *td, struct timeval *tv)
+steplimit(struct thread *td, struct timeval *tv, bool abs)
{
struct timeval delta, tv1, tv2;
- static struct timeval maxtime, laststep;
- struct timespec ts;
+ int error;
+ if (securelevel_gt(td->td_ucred, 1) == 0)
+ return (0);
+
+ error = 0;
+ mtx_lock(&sl_lock);
microtime(&tv1);
delta = *tv;
- timevalsub(&delta, &tv1);
+ if (abs)
+ timevalsub(&delta, &tv1);
/*
* If the system is secure, we do not allow the time to be
@@ -132,39 +144,83 @@
* time we have yet seen. The worst a miscreant can do in
* this circumstance is "freeze" time. He couldn't go
* back to the past.
- *
- * We similarly do not allow the clock to be stepped more
- * than one second, nor more than once per second. This allows
- * a miscreant to make the clock march double-time, but no worse.
*/
- if (securelevel_gt(td->td_ucred, 1) != 0) {
- if (delta.tv_sec < 0 || delta.tv_usec < 0) {
- /*
- * Update maxtime to latest time we've seen.
- */
- if (tv1.tv_sec > maxtime.tv_sec)
- maxtime = tv1;
+ if (delta.tv_sec < 0 || delta.tv_usec < 0) {
+ /*
+ * Update maxtime to latest time we've seen.
+ */
+ if (tv1.tv_sec > maxtime.tv_sec)
+ maxtime = tv1;
+ if (abs) {
tv2 = *tv;
timevalsub(&tv2, &maxtime);
if (tv2.tv_sec < -1) {
tv->tv_sec = maxtime.tv_sec - 1;
- printf("Time adjustment clamped to -1 second\n");
+ if (bootverbose) {
+ printf("Time adjustment clamped to "
+ "-1 second\n");
+ }
}
} else {
- if (tv1.tv_sec == laststep.tv_sec)
- return (EPERM);
- if (delta.tv_sec > 1) {
- tv->tv_sec = tv1.tv_sec + 1;
- printf("Time adjustment clamped to +1 second\n");
+ if (delta.tv_sec < -1) {
+ tv->tv_sec = - 1;
+ if (bootverbose) {
+ printf("Time adjustment clamped to "
+ "-1 second\n");
+ }
}
- laststep = *tv;
}
+ goto out;
+ }
+
+ /*
+ * We similarly do not allow the clock to be stepped more
+ * than one second, nor more than once per second. This allows
+ * a miscreant to make the clock march double-time, but no worse.
+ */
+ if (tv1.tv_sec == laststep.tv_sec) {
+ error = EPERM;
+ goto out;
+ }
+ if (delta.tv_sec > 1) {
+ tv->tv_sec = abs ? tv1.tv_sec + 1 : 1;
+ printf("Time adjustment clamped to +1 second\n");
}
+ if (abs) {
+ laststep = *tv;
+ } else {
+ timevaladd(&tv1, &delta);
+ laststep = tv1;
+ }
+out:
+ mtx_unlock(&sl_lock);
+ return (error);
+}
+
+static int
+settime(struct thread *td, struct timeval *tv)
+{
+ int error;
+
+ error = steplimit(td, tv, true);
+ if (error == 0)
+ error = steptime(td, tv, NULL, true);
+ return (error);
+}
+
+static int
+steptime(struct thread *td, struct timeval *tv, struct timeval *otv, bool abs)
+{
+ struct timespec ts, ots;
ts.tv_sec = tv->tv_sec;
ts.tv_nsec = tv->tv_usec * 1000;
- tc_setclock(&ts);
+ tc_setclock(&ts, &ots, abs);
resettodr();
+ if (otv != NULL) {
+ otv->tv_sec = ots.tv_sec;
+ otv->tv_usec = ots.tv_nsec / 1000;
+ }
return (0);
}
@@ -384,12 +440,17 @@
int
sys_clock_settime(struct thread *td, struct clock_settime_args *uap)
{
- struct timespec ats;
+ struct timespec ats, ots;
int error;
if ((error = copyin(uap->tp, &ats, sizeof(ats))) != 0)
return (error);
- return (kern_clock_settime(td, uap->clock_id, &ats));
+ error = kern_clock_settime(td, uap->clock_id, &ats, &ots);
+ if (error != 0)
+ return (error);
+ if (uap->clock_id == CLOCK_ADJUST_REALTIME)
+ error = copyout(&ots, __DECONST(void *, uap->tp), sizeof(ots));
+ return (error);
}
static int allow_insane_settime = 0;
@@ -397,26 +458,50 @@
&allow_insane_settime, 0,
"do not perform possibly restrictive checks on settime(2) args");
+/*
+ * Arbitrary limit to prevent insane
+ * clock_settime(CLOCK_ADJUST_REALTIME), e.g. with a garbage ts.
+ */
+#define CLOCK_ADJUST_REALTIME_LIMIT 3600
+
int
-kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats)
+kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats,
+ struct timespec *ots)
{
- struct timeval atv;
+ struct timeval atv, oatv;
int error;
if ((error = priv_check(td, PRIV_CLOCK_SETTIME)) != 0)
return (error);
- if (clock_id != CLOCK_REALTIME)
- return (EINVAL);
- if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000 ||
- ats->tv_sec < 0)
- return (EINVAL);
- if (!allow_insane_settime &&
- (ats->tv_sec > 8000ULL * 365 * 24 * 60 * 60 ||
- ats->tv_sec < utc_offset()))
- return (EINVAL);
- /* XXX Don't convert nsec->usec and back */
- TIMESPEC_TO_TIMEVAL(&atv, ats);
- error = settime(td, &atv);
+ error = EINVAL;
+ switch (clock_id) {
+ case CLOCK_ADJUST_REALTIME:
+ if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000 ||
+ (!allow_insane_settime &&
+ (ats->tv_sec > CLOCK_ADJUST_REALTIME_LIMIT ||
+ ats->tv_sec < -CLOCK_ADJUST_REALTIME_LIMIT)))
+ break;
+ TIMESPEC_TO_TIMEVAL(&atv, ats);
+ error = steplimit(td, &atv, false);
+ if (error == 0) {
+ error = steptime(td, &atv, &oatv, false);
+ if (ots != NULL && error == 0)
+ TIMEVAL_TO_TIMESPEC(&oatv, ots);
+ }
+ break;
+ case CLOCK_REALTIME:
+ if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000 ||
+ ats->tv_sec < 0)
+ break;
+ if (!allow_insane_settime &&
+ (ats->tv_sec > 8000ULL * 365 * 24 * 60 * 60 ||
+ ats->tv_sec < utc_offset()))
+ error = EINVAL;
+ /* XXX Don't convert nsec->usec and back */
+ TIMESPEC_TO_TIMEVAL(&atv, ats);
+ error = settime(td, &atv);
+ break;
+ }
return (error);
}
Index: sys/kern/subr_rtc.c
===================================================================
--- sys/kern/subr_rtc.c
+++ sys/kern/subr_rtc.c
@@ -361,7 +361,7 @@
}
if (ts.tv_sec >= 0) {
- tc_setclock(&ts);
+ tc_setclock(&ts, NULL, true);
#ifdef FFCLOCK
ffclock_reset_clock(&ts);
#endif
Index: sys/sys/syscallsubr.h
===================================================================
--- sys/sys/syscallsubr.h
+++ sys/sys/syscallsubr.h
@@ -105,7 +105,7 @@
int kern_clock_nanosleep(struct thread *td, clockid_t clock_id, int flags,
const struct timespec *rqtp, struct timespec *rmtp);
int kern_clock_settime(struct thread *td, clockid_t clock_id,
- struct timespec *ats);
+ struct timespec *ats, struct timespec *ots);
void kern_thread_cputime(struct thread *targettd, struct timespec *ats);
void kern_process_cputime(struct proc *targetp, struct timespec *ats);
int kern_close_range(struct thread *td, u_int lowfd, u_int highfd);
Index: sys/sys/time.h
===================================================================
--- sys/sys/time.h
+++ sys/sys/time.h
@@ -480,6 +480,7 @@
#define CLOCK_SECOND 13 /* FreeBSD-specific. */
#define CLOCK_THREAD_CPUTIME_ID 14
#define CLOCK_PROCESS_CPUTIME_ID 15
+#define CLOCK_ADJUST_REALTIME 16 /* FreeBSD-specific. */
#endif
#ifndef TIMER_ABSTIME
@@ -613,6 +614,7 @@
#if __BSD_VISIBLE
int adjtime(const struct timeval *, struct timeval *);
int clock_getcpuclockid2(id_t, int, clockid_t *);
+int clock_settime_adjust(const struct timespec *, struct timespec *);
int futimes(int, const struct timeval *);
int futimesat(int, const char *, const struct timeval [2]);
int lutimes(const char *, const struct timeval *);
Index: sys/sys/timetc.h
===================================================================
--- sys/sys/timetc.h
+++ sys/sys/timetc.h
@@ -88,7 +88,7 @@
u_int64_t tc_getfrequency(void);
void tc_init(struct timecounter *tc);
-void tc_setclock(struct timespec *ts);
+void tc_setclock(struct timespec *ts, struct timespec *ots, bool abs);
void tc_ticktock(int cnt);
void cpu_tick_calibration(void);

File Metadata

Mime Type
text/plain
Expires
Tue, Apr 7, 4:21 PM (14 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31041692
Default Alt Text
D27571.id81139.diff (14 KB)

Event Timeline