Page MenuHomeFreeBSD

D27571.id81170.diff
No OneTemporary

D27571.id81170.diff

diff --git a/include/time.h b/include/time.h
--- a/include/time.h
+++ b/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
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
--- a/lib/libc/gen/Makefile.inc
+++ b/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 \
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -422,6 +422,7 @@
};
FBSD_1.6 {
+ clock_settime_adjust;
getlogin_r;
memalign;
scandir_b;
diff --git a/lib/libc/gen/clock_settime_adjust.c b/lib/libc/gen/clock_settime_adjust.c
new file mode 100644
--- /dev/null
+++ b/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);
+}
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -2919,17 +2919,25 @@
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 && 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
diff --git a/sys/compat/linux/linux_time.c b/sys/compat/linux/linux_time.c
--- a/sys/compat/linux/linux_time.c
+++ b/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);
diff --git a/sys/dev/hyperv/utilities/vmbus_timesync.c b/sys/dev/hyperv/utilities/vmbus_timesync.c
--- a/sys/dev/hyperv/utilities/vmbus_timesync.c
+++ b/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;
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c
--- a/sys/kern/kern_tc.c
+++ b/sys/kern/kern_tc.c
@@ -1245,7 +1245,7 @@
* when we booted.
*/
void
-tc_setclock(struct timespec *ts)
+tc_setclock(struct timespec *ts, bool abs)
{
struct timespec tbef, taft;
struct bintime bt, bt2;
@@ -1254,10 +1254,14 @@
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...
+ */
tc_windup(&bt);
mtx_unlock_spin(&tc_setclock_mtx);
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -86,6 +86,8 @@
*/
static int settime(struct thread *, struct timeval *);
+static int steplimit(struct thread *td, struct timeval *tv, bool abs);
+static void steptime(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,
@@ -113,18 +115,53 @@
#define CLOCK_CALL(clock, call, arglist) \
((*posix_clocks[clock].call) arglist)
+static SYSCTL_NODE(_kern, OID_AUTO, settime, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "Controls for settime");
+
+static int allow_insane_settime = 0;
+SYSCTL_INT(_kern_settime, OID_AUTO, allow_insane_settime, CTLFLAG_RWTUN,
+ &allow_insane_settime, 0,
+ "do not perform possibly restrictive checks on settime(2) args");
+static u_long insane_settime_val = 8000;
+SYSCTL_ULONG(_kern_settime, OID_AUTO, insane_settime_val, CTLFLAG_RWTUN,
+ &insane_settime_val, 0,
+ "insane years for clock_settime(2)");
+static int secure_steplimit = 1;
+SYSCTL_INT(_kern_settime, OID_AUTO, secure_steplimit, CTLFLAG_RWTUN,
+ &secure_steplimit, 0,
+ "limit for step on securelevel > 1, in seconds");
+/*
+ * Default limit it set to 12h to allow adjustment to fix local-zone RTC
+ * without requiring tuning.
+ */
+static int insane_adjust_limit = 12 * 3600;
+SYSCTL_INT(_kern_settime, OID_AUTO, insane_adjust_limit, CTLFLAG_RWTUN,
+ &insane_adjust_limit, 0,
+ "insane seconds for CLOCK_ADJUST_REALTIME");
+
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, sl;
+
+ 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);
+
+ sl = secure_steplimit;
/*
* If the system is secure, we do not allow the time to be
@@ -132,40 +169,81 @@
* 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 (tv2.tv_sec < -sl) {
+ tv->tv_sec = maxtime.tv_sec - sl;
+ if (bootverbose) {
+ printf(
+ "Time adjustment clamped to -%d second\n",
+ sl);
+ }
}
} 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 < -sl) {
+ tv->tv_sec = - sl;
+ if (bootverbose) {
+ printf(
+ "Time adjustment clamped to -%d second\n",
+ sl);
+ }
}
- 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 > sl) {
+ tv->tv_sec = abs ? tv1.tv_sec + sl : sl;
+ printf("Time adjustment clamped to +%d second\n", sl);
+ }
+ 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)
+ steptime(tv, true);
+ return (error);
+}
+
+static void
+steptime(struct timeval *tv, bool abs)
+{
+ struct timespec ts;
+
ts.tv_sec = tv->tv_sec;
ts.tv_nsec = tv->tv_usec * 1000;
- tc_setclock(&ts);
+ tc_setclock(&ts, abs);
resettodr();
- return (0);
}
#ifndef _SYS_SYSPROTO_H_
@@ -384,39 +462,56 @@
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 && uap->clock_id == CLOCK_ADJUST_REALTIME)
+ error = copyout(&ots, __DECONST(void *, uap->tp), sizeof(ots));
+ return (error);
}
-static int allow_insane_settime = 0;
-SYSCTL_INT(_debug, OID_AUTO, allow_insane_settime, CTLFLAG_RWTUN,
- &allow_insane_settime, 0,
- "do not perform possibly restrictive checks on settime(2) args");
-
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;
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)
+ break;
+ if (!allow_insane_settime &&
+ (ats->tv_sec > insane_adjust_limit ||
+ ats->tv_sec < -insane_adjust_limit))
+ break;
+ TIMESPEC_TO_TIMEVAL(&atv, ats);
+ error = steplimit(td, &atv, false);
+ if (error != 0)
+ break;
+ steptime(&atv, false);
+ if (ots != NULL)
+ TIMEVAL_TO_TIMESPEC(&atv, 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 > insane_settime_val * 365ULL * 24 * 60 * 60 ||
+ ats->tv_sec < utc_offset()))
+ break;
+ /* XXX Don't convert nsec->usec and back */
+ TIMESPEC_TO_TIMEVAL(&atv, ats);
+ error = settime(td, &atv);
+ break;
+ }
return (error);
}
diff --git a/sys/kern/subr_rtc.c b/sys/kern/subr_rtc.c
--- a/sys/kern/subr_rtc.c
+++ b/sys/kern/subr_rtc.c
@@ -361,7 +361,7 @@
}
if (ts.tv_sec >= 0) {
- tc_setclock(&ts);
+ tc_setclock(&ts, true);
#ifdef FFCLOCK
ffclock_reset_clock(&ts);
#endif
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
--- a/sys/sys/syscallsubr.h
+++ b/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);
diff --git a/sys/sys/time.h b/sys/sys/time.h
--- a/sys/sys/time.h
+++ b/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 *);
diff --git a/sys/sys/timetc.h b/sys/sys/timetc.h
--- a/sys/sys/timetc.h
+++ b/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, bool abs);
void tc_ticktock(int cnt);
void cpu_tick_calibration(void);

File Metadata

Mime Type
text/plain
Expires
Tue, May 19, 6:52 AM (11 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33298120
Default Alt Text
D27571.id81170.diff (14 KB)

Event Timeline