mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-07 17:25:07 -05:00
Compare commits
11 Commits
4.8-pre1
...
3c39afa13c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c39afa13c | ||
|
|
03875f1ea5 | ||
|
|
2e29935c54 | ||
|
|
8084961011 | ||
|
|
120bf44989 | ||
|
|
9e8541e3c4 | ||
|
|
e95d5a161d | ||
|
|
2c63dfee34 | ||
|
|
42e6b5577a | ||
|
|
830c8bb18a | ||
|
|
0289442998 |
2
client.c
2
client.c
@@ -270,7 +270,7 @@ open_unix_socket(char *server_path)
|
||||
if (snprintf(sock_dir1, sizeof (sock_dir1),
|
||||
"%s/chronyc.%d", sock_dir0, (int)getpid()) >= sizeof (sock_dir1) ||
|
||||
snprintf(sock_dir2, sizeof (sock_dir2),
|
||||
"%s/%s", sock_dir1, rand_dir) >= sizeof (sock_dir1) ||
|
||||
"%s/%s", sock_dir1, rand_dir) >= sizeof (sock_dir2) ||
|
||||
snprintf(sock_path, sizeof (sock_path),
|
||||
"%s/sock", sock_dir2) >= sizeof (sock_path)) {
|
||||
LOG(LOGS_ERR, "Server socket path %s is too long", server_path);
|
||||
|
||||
1
configure
vendored
1
configure
vendored
@@ -808,6 +808,7 @@ then
|
||||
# a time and the async resolver would block the main thread
|
||||
priv_ops="NAME2IPADDRESS RELOADDNS"
|
||||
EXTRA_LIBS="$EXTRA_LIBS -lseccomp"
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS sys_linux_scmp.o"
|
||||
fi
|
||||
|
||||
if [ "x$priv_ops" != "x" ]; then
|
||||
|
||||
@@ -1133,23 +1133,29 @@ distances are in milliseconds.
|
||||
|
||||
[[clockprecision]]*clockprecision* _precision_::
|
||||
The *clockprecision* directive specifies the precision of the system clock (in
|
||||
seconds). It is used by *chronyd* to estimate the minimum noise in NTP
|
||||
measurements and randomise low-order bits of timestamps in NTP responses. By
|
||||
default, the precision is measured on start-up as the minimum time to read the
|
||||
clock.
|
||||
seconds). This value is used by *chronyd* as the minimum expected error and
|
||||
amount of noise in NTP and refclock measurements, and to randomise low-order
|
||||
bits of timestamps in NTP responses to make them less predictable. The minimum
|
||||
value is 1 nanosecond and the maximum value is 1 second.
|
||||
+
|
||||
The measured value works well in most cases. It generally overestimates the
|
||||
precision and it can be sensitive to the CPU speed, however, which can
|
||||
change over time to save power. In some cases with a high-precision clocksource
|
||||
(e.g. the Time Stamp Counter of the CPU) and hardware timestamping, setting the
|
||||
precision on the server to a smaller value can improve stability of clients'
|
||||
NTP measurements. The server's precision is reported on clients by the
|
||||
By default, *chronyd* tries to determine the precision on start-up as the
|
||||
resolution of the clock. On Linux, it tries to measure the resolution by
|
||||
observing the minimum change in differences between consecutive readings of the
|
||||
clock. On other systems it relies on the *clock_getres(2)* system function.
|
||||
+
|
||||
If the measurement fails, or the value provided by the system is too large, the
|
||||
minimum measured time needed to read the clock will be used instead. This value
|
||||
is typically larger than the resolution, and it is sensitive to the CPU speed,
|
||||
however, which can change over time to save power.
|
||||
+
|
||||
The server's precision is reported on clients by the
|
||||
<<chronyc.adoc#ntpdata,*ntpdata*>> command.
|
||||
+
|
||||
An example setting the precision to 8 nanoseconds is:
|
||||
An example setting the precision to 1 nanosecond (e.g. when the system clock is
|
||||
using a Time Stamp Counter (TSC) updated at a rate of at least 1 GHz) is:
|
||||
+
|
||||
----
|
||||
clockprecision 8e-9
|
||||
clockprecision 1e-9
|
||||
----
|
||||
|
||||
[[corrtimeratio]]*corrtimeratio* _ratio_::
|
||||
|
||||
2
leapdb.c
2
leapdb.c
@@ -130,7 +130,7 @@ get_list_leap(time_t when, int *tai_offset)
|
||||
char *p;
|
||||
|
||||
/* Ignore blank lines */
|
||||
for (p = line; *p && isspace(*p); ++p)
|
||||
for (p = line; *p && isspace((unsigned char)*p); ++p)
|
||||
;
|
||||
if (!*p)
|
||||
continue;
|
||||
|
||||
163
local.c
163
local.c
@@ -97,8 +97,142 @@ static double precision_quantum;
|
||||
|
||||
static double max_clock_error;
|
||||
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Ask the system for the resolution of the system clock. The Linux
|
||||
clock_getres() is not usable, because it reports the internal timer
|
||||
resolution, which is 1 ns when high-resolution timers are enabled,
|
||||
even when using a lower-resolution clocksource. */
|
||||
|
||||
static int
|
||||
get_clock_resolution(void)
|
||||
{
|
||||
#if defined(HAVE_CLOCK_GETTIME) && !defined(LINUX)
|
||||
struct timespec res;
|
||||
|
||||
if (clock_getres(CLOCK_REALTIME, &res) < 0)
|
||||
return 0;
|
||||
|
||||
return NSEC_PER_SEC * res.tv_sec + res.tv_nsec;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(LINUX) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC_RAW)
|
||||
|
||||
static int
|
||||
compare_ints(const void *a, const void *b)
|
||||
{
|
||||
return *(const int *)a - *(const int *)b;
|
||||
}
|
||||
|
||||
#define READINGS 64
|
||||
|
||||
/* On Linux, try to measure the actual resolution of the system
|
||||
clock by performing a varying amount of busy work between clock
|
||||
readings and finding the minimum change in the measured interval.
|
||||
Require a change of at least two nanoseconds to ignore errors
|
||||
caused by conversion to timespec. Use the raw monotonic clock
|
||||
to avoid the impact of potential frequency changes due to NTP
|
||||
adjustments made by other processes, and the kernel dithering of
|
||||
the 32-bit multiplier. */
|
||||
|
||||
static int
|
||||
measure_clock_resolution(void)
|
||||
{
|
||||
int i, j, b, busy, diffs[READINGS - 1], diff2, min;
|
||||
struct timespec start_ts, ts[READINGS];
|
||||
uint32_t acc;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_ts) < 0)
|
||||
return 0;
|
||||
|
||||
for (acc = 0, busy = 1; busy < 100000; busy = busy * 3 / 2 + 1) {
|
||||
for (i = 0, b = busy * READINGS; i < READINGS; i++, b -= busy) {
|
||||
if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts[i]) < 0)
|
||||
return 0;
|
||||
|
||||
for (j = b; j > 0; j--)
|
||||
acc += (acc & 1) + (uint32_t)ts[i].tv_nsec;
|
||||
}
|
||||
|
||||
/* Give up after 0.1 seconds */
|
||||
if (UTI_DiffTimespecsToDouble(&ts[READINGS - 1], &start_ts) > 0.1) {
|
||||
DEBUG_LOG("Measurement too slow");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < READINGS - 1; i++) {
|
||||
diffs[i] = NSEC_PER_SEC * (ts[i + 1].tv_sec - ts[i].tv_sec) +
|
||||
(ts[i + 1].tv_nsec - ts[i].tv_nsec);
|
||||
|
||||
/* Make sure the differences are sane. A resolution larger than the
|
||||
reading time will be measured in measure_clock_read_delay(). */
|
||||
if (diffs[i] <= 0 || diffs[i] > NSEC_PER_SEC)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sort the differences and keep values unique within 1 ns from the
|
||||
first half of the array, which are less likely to be impacted by CPU
|
||||
interruptions */
|
||||
qsort(diffs, READINGS - 1, sizeof (diffs[0]), compare_ints);
|
||||
for (i = 1, j = 0; i < READINGS / 2; i++) {
|
||||
if (diffs[j] + 1 < diffs[i])
|
||||
diffs[++j] = diffs[i];
|
||||
}
|
||||
j++;
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < j; i++)
|
||||
DEBUG_LOG("busy %d diff %d %d", busy, i, diffs[i]);
|
||||
#endif
|
||||
|
||||
/* Require at least three unique differences to be more confident
|
||||
with the result */
|
||||
if (j < 3)
|
||||
continue;
|
||||
|
||||
/* Find the smallest difference between the unique differences */
|
||||
for (i = 1, min = 0; i < j; i++) {
|
||||
diff2 = diffs[i] - diffs[i - 1];
|
||||
if (min == 0 || min > diff2)
|
||||
min = diff2;
|
||||
}
|
||||
|
||||
if (min == 0)
|
||||
continue;
|
||||
|
||||
/* Prevent the compiler from optimising the busy work out */
|
||||
if (acc == 0)
|
||||
min += 1;
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static int
|
||||
measure_clock_resolution(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* As a fallback, measure how long it takes to read the clock. It
|
||||
typically takes longer than the resolution of the clock (and it
|
||||
depends on the CPU speed), i.e. every reading gives a different
|
||||
value, but handle also low-resolution clocks that might give
|
||||
the same reading multiple times. */
|
||||
|
||||
/* Define the number of increments of the system clock that we want
|
||||
to see to be fairly sure that we've got something approaching
|
||||
the minimum increment. Even on a crummy implementation that can't
|
||||
@@ -106,10 +240,8 @@ static double max_clock_error;
|
||||
under 1s of busy waiting. */
|
||||
#define NITERS 100
|
||||
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
|
||||
static double
|
||||
measure_clock_precision(void)
|
||||
static int
|
||||
measure_clock_read_delay(void)
|
||||
{
|
||||
struct timespec ts, old_ts;
|
||||
int iters, diff, best;
|
||||
@@ -135,7 +267,28 @@ measure_clock_precision(void)
|
||||
|
||||
assert(best > 0);
|
||||
|
||||
return 1.0e-9 * best;
|
||||
return best;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
measure_clock_precision(void)
|
||||
{
|
||||
int res, delay, prec;
|
||||
|
||||
res = get_clock_resolution();
|
||||
if (res <= 0)
|
||||
res = measure_clock_resolution();
|
||||
|
||||
delay = measure_clock_read_delay();
|
||||
|
||||
if (res > 0)
|
||||
prec = MIN(res, delay);
|
||||
else
|
||||
prec = delay;
|
||||
|
||||
return prec / 1.0e9;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
12
sys_linux.c
12
sys_linux.c
@@ -63,6 +63,7 @@
|
||||
#endif
|
||||
|
||||
#include "sys_linux.h"
|
||||
#include "sys_linux_scmp.h"
|
||||
#include "sys_timex.h"
|
||||
#include "conf.h"
|
||||
#include "local.h"
|
||||
@@ -728,6 +729,14 @@ SYS_Linux_EnableSystemCallFilter(int level, SYS_ProcessContext context)
|
||||
SCMP_A1(SCMP_CMP_EQ, ioctls[i])) < 0)
|
||||
goto add_failed;
|
||||
}
|
||||
|
||||
/* Allow selected ioctls that need to be specified in a separate
|
||||
file to avoid conflicting headers (e.g. TCGETS2) */
|
||||
for (i = 0; SYS_Linux_GetExtraScmpIoctl(i) != 0; i++) {
|
||||
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, SYS_Linux_GetExtraScmpIoctl(i))) < 0)
|
||||
goto add_failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (seccomp_load(ctx) < 0)
|
||||
@@ -944,8 +953,7 @@ SYS_Linux_OpenPHC(const char *device, int flags)
|
||||
if (phc_fd < 0) {
|
||||
phc_fd = open_phc_by_iface_name(device, flags);
|
||||
if (phc_fd < 0) {
|
||||
LOG(LOGS_ERR, "Could not open PHC of iface %s : %s",
|
||||
device, strerror(errno));
|
||||
LOG(LOGS_ERR, "Could not open PHC (of) %s", device);
|
||||
return -1;
|
||||
}
|
||||
phc_fd = verify_fd_is_phc(phc_fd);
|
||||
|
||||
44
sys_linux_scmp.c
Normal file
44
sys_linux_scmp.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2025
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Lists of values that are needed in seccomp filters but need to
|
||||
be compiled separately from sys_linux.c due to conflicting headers.
|
||||
*/
|
||||
|
||||
#include <linux/termios.h>
|
||||
|
||||
#include "sys_linux_scmp.h"
|
||||
|
||||
unsigned long
|
||||
SYS_Linux_GetExtraScmpIoctl(int index)
|
||||
{
|
||||
const unsigned long ioctls[] = {
|
||||
#ifdef TCGETS2
|
||||
/* Conflict between <linux/termios.h> and <sys/ioctl.h> */
|
||||
TCGETS2,
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
return ioctls[index];
|
||||
}
|
||||
28
sys_linux_scmp.h
Normal file
28
sys_linux_scmp.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2025
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for lists that are needed in seccomp filters but need to
|
||||
be compiled separately from sys_linux.c due to conflicting headers.
|
||||
*/
|
||||
|
||||
extern unsigned long SYS_Linux_GetExtraScmpIoctl(int index);
|
||||
@@ -1,7 +1,7 @@
|
||||
This is a collection of simulation tests using the clknetsim simulator
|
||||
(supported on Linux only).
|
||||
|
||||
https://github.com/mlichvar/clknetsim
|
||||
https://gitlab.com/chrony/clknetsim
|
||||
|
||||
The CLKNETSIM_PATH environment variable should point to the directory where
|
||||
clknetsim was downloaded and compiled. If the variable is not set, the tests
|
||||
|
||||
@@ -213,7 +213,10 @@ generate_chrony_conf() {
|
||||
|
||||
user=$(get_user)
|
||||
ntpport=$(get_free_port)
|
||||
cmdport=$(get_free_port)
|
||||
while true; do
|
||||
cmdport=$(get_free_port)
|
||||
[ "$ntpport" -ne "$cmdport" ] && break
|
||||
done
|
||||
|
||||
echo "0.0 10000" > "$TEST_LIBDIR/driftfile"
|
||||
echo "1 MD5 abcdefghijklmnopq" > "$TEST_DIR/keys"
|
||||
|
||||
@@ -193,6 +193,8 @@ test_unit(void)
|
||||
|
||||
server_cred = NKSN_CreateServerCertCredentials(&cert, &key, 1);
|
||||
client_cred = NKSN_CreateClientCertCredentials(&cert, &cert_id, 1, 0);
|
||||
TEST_CHECK(server_cred);
|
||||
TEST_CHECK(client_cred);
|
||||
|
||||
TEST_CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds) == 0);
|
||||
TEST_CHECK(fcntl(sock_fds[0], F_SETFL, O_NONBLOCK) == 0);
|
||||
|
||||
@@ -191,6 +191,7 @@ test_unit(void)
|
||||
s3 = SCK_AcceptConnection(s1, &sa2);
|
||||
TEST_CHECK(UTI_CompareIPs(&sa1.ip_addr, &sa2.ip_addr, NULL) == 0);
|
||||
|
||||
fcntl(s3, F_SETFL, fcntl(s3, F_GETFL) & ~O_NONBLOCK);
|
||||
send_and_recv(SCK_ADDR_IP, 1, 1, s3, s2);
|
||||
|
||||
SCK_ShutdownConnection(s2);
|
||||
@@ -227,6 +228,7 @@ test_unit(void)
|
||||
s3 = SCK_AcceptConnection(s1, &sa2);
|
||||
TEST_CHECK(sa2.ip_addr.family == IPADDR_UNSPEC);
|
||||
|
||||
fcntl(s3, F_SETFL, fcntl(s3, F_GETFL) & ~O_NONBLOCK);
|
||||
send_and_recv(SCK_ADDR_UNIX, 1, i % 2, s3, s2);
|
||||
|
||||
if (i % 4)
|
||||
|
||||
2
util.c
2
util.c
@@ -1203,7 +1203,7 @@ create_dir(char *p, mode_t mode, uid_t uid, gid_t gid)
|
||||
}
|
||||
|
||||
/* Set its owner */
|
||||
if (chown(p, uid, gid) < 0) {
|
||||
if (lchown(p, uid, gid) < 0) {
|
||||
LOG(LOGS_ERR, "Could not change ownership of %s : %s", p, strerror(errno));
|
||||
/* Don't leave it there with incorrect ownership */
|
||||
rmdir(p);
|
||||
|
||||
Reference in New Issue
Block a user