Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151184707
D27571.id81139.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D27571.id81139.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D27571: CLOCK_ADJUST_REALTIME
Attached
Detach File
Event Timeline
Log In to Comment