13#include <sys/syscall.h>
14#include <sys/timerfd.h>
18_Static_assert(
sizeof(
struct timex) == 208,
"Linux amd64 timex ABI");
19_Static_assert(offsetof(
struct timex, time) == 72,
"Linux amd64 timex time ABI");
20_Static_assert(offsetof(
struct timex, tai) == 160,
"Linux amd64 timex TAI ABI");
22#define CHECK(expression) \
24 if (!(expression)) { \
25 fprintf(stderr, "CLOCK-ADJUST-CONTRACT: line=%d errno=%d %s\n", __LINE__, errno, \
32static int64_t now(clockid_t clock) {
33 struct timespec value;
34 return clock_gettime(clock, &value) ? -1 : (int64_t)value.tv_sec * 1000000000 + value.tv_nsec;
37static struct timespec timespec(int64_t value) {
38 return (
struct timespec){value / 1000000000, value % 1000000000};
41static int state(
const struct timex* value) {
42 const long units = value->status & STA_NANO ? 1000000000 : 1000000;
43 return (value->status & STA_UNSYNC) && !(value->status & (STA_PLL | STA_PPSFREQ | STA_PPSTIME)) &&
44 value->time.tv_sec > 0 && value->time.tv_usec >= 0 && value->time.tv_usec < units &&
45 value->offset == 0 && value->freq == 0 && value->ppsfreq == 0 && value->maxerror > 0 &&
49static int query(
void) {
52 memset(&value, 0xA5,
sizeof(value));
54 const int64_t before = now(CLOCK_REALTIME);
55 CHECK(adjtimex(&value) == TIME_ERROR && state(&value));
56 const int64_t timestamp = (int64_t)value.time.tv_sec * 1000000000 +
57 value.time.tv_usec * ((value.status & STA_NANO) ? 1 : 1000);
58 CHECK(timestamp >= before - 100000000 && timestamp <= now(CLOCK_REALTIME) + 100000000);
59 for (
unsigned n = 0; n <
sizeof(value.__padding) /
sizeof(value.__padding[0]); ++n)
60 CHECK(value.__padding[n] == 0);
61 value = (
struct timex){0};
62 CHECK(syscall(SYS_clock_adjtime, CLOCK_REALTIME, &value) == TIME_ERROR && state(&value));
63 value = (
struct timex){.modes = ADJ_OFFSET_SS_READ};
64 CHECK(syscall(SYS_adjtimex, &value) == TIME_ERROR && state(&value) && value.offset == 0);
65 value = (
struct timex){0};
66 CHECK(clock_adjtime(CLOCK_MONOTONIC, &value) == -1 && errno == EOPNOTSUPP);
67 CHECK(syscall(SYS_clock_adjtime, 123456, &value) == -1 && errno == EINVAL);
68 CHECK(syscall(SYS_adjtimex, NULL) == -1 && errno == EFAULT);
69 CHECK(syscall(SYS_clock_adjtime, CLOCK_REALTIME, NULL) == -1 && errno == EFAULT);
74static int step(int64_t seconds, int64_t fraction,
unsigned modes,
int route) {
75 struct timex value = {.modes = ADJ_SETOFFSET | modes,
76 .time = {.tv_sec = seconds, .tv_usec = fraction}};
77 return route ? syscall(SYS_clock_adjtime, CLOCK_REALTIME, &value) : syscall(SYS_adjtimex, &value);
80static int steps(
void) {
81 int failed = 0, canceled = -1, absolute = -1, monotonic = -1;
82 struct timex value = {.modes = ADJ_NANO};
83 struct itimerspec setting = {0}, remaining;
85 CHECK(geteuid() == 0);
86 CHECK(adjtimex(&value) == TIME_ERROR && (value.status & STA_NANO));
87 value = (
struct timex){.modes = ADJ_OFFSET_SS_READ};
88 CHECK(adjtimex(&value) == TIME_ERROR && (value.status & STA_NANO));
89 value = (
struct timex){0};
90 CHECK(adjtimex(&value) == TIME_ERROR && (value.status & STA_NANO));
92 CHECK((canceled = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK)) >= 0);
93 CHECK((absolute = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK)) >= 0);
94 CHECK((monotonic = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) >= 0);
95 setting.it_value = timespec(now(CLOCK_REALTIME) + 5000000000);
96 CHECK(timerfd_settime(canceled, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &setting, NULL) ==
98 CHECK(timerfd_settime(absolute, TFD_TIMER_ABSTIME, &setting, NULL) == 0);
99 setting.it_value = timespec(now(CLOCK_MONOTONIC) + 5000000000);
100 CHECK(timerfd_settime(monotonic, TFD_TIMER_ABSTIME, &setting, NULL) == 0);
101 int64_t before = now(CLOCK_REALTIME) - now(CLOCK_MONOTONIC);
102 CHECK(step(10, 250000000, ADJ_NANO, 1) == TIME_ERROR);
103 int64_t after = now(CLOCK_REALTIME) - now(CLOCK_MONOTONIC);
104 CHECK(after - before > 10150000000 && after - before < 10350000000);
105 CHECK(read(canceled, &count,
sizeof(count)) == -1 && errno == ECANCELED);
106 CHECK(read(absolute, &count,
sizeof(count)) ==
sizeof(count) && count == 1);
107 CHECK(read(monotonic, &count,
sizeof(count)) == -1 && errno == EAGAIN);
108 CHECK(timerfd_gettime(monotonic, &remaining) == 0 && remaining.it_value.tv_sec >= 3);
112 CHECK(step(-2, 750000, 0, 0) == TIME_ERROR);
113 after = now(CLOCK_REALTIME) - now(CLOCK_MONOTONIC);
114 CHECK(after - before > -1350000000 && after - before < -1150000000);
115 value = (
struct timex){0};
116 CHECK(adjtimex(&value) == TIME_ERROR && (value.status & STA_NANO));
118 value = (
struct timex){.modes = ADJ_MICRO};
119 CHECK(adjtimex(&value) == TIME_ERROR && !(value.status & STA_NANO));
120 CHECK(step(0, -1, ADJ_NANO, 0) == -1 && errno == EINVAL);
121 CHECK(step(0, 1000000, 0, 0) == -1 && errno == EINVAL);
122 CHECK(step(0, 1000000000, ADJ_NANO, 1) == -1 && errno == EINVAL);
123 CHECK(step(INT64_MAX, 0, ADJ_NANO, 0) == -1 && errno == EINVAL);
124 CHECK(step(INT64_MIN, 0, ADJ_NANO, 1) == -1 && errno == EINVAL);
125 CHECK(step(-now(CLOCK_REALTIME) / 1000000000 - 60, 0, ADJ_NANO, 0) == -1 && errno == EINVAL);
126 value = (
struct timex){0};
127 CHECK(adjtimex(&value) == TIME_ERROR && !(value.status & STA_NANO));
128 const unsigned unsupported[] = {ADJ_FREQUENCY, ADJ_OFFSET, ADJ_OFFSET_SINGLESHOT,
129 ADJ_STATUS, ADJ_TICK, ADJ_TAI,
130 ADJ_MAXERROR, ADJ_ESTERROR, ADJ_TIMECONST};
131 for (
unsigned n = 0; n <
sizeof(unsupported) /
sizeof(unsupported[0]); ++n) {
132 value = (
struct timex){.modes = unsupported[n], .freq = 100, .status = STA_PLL};
133 CHECK(adjtimex(&value) == -1 && errno == EOPNOTSUPP);
135 value = (
struct timex){.modes = 0x40000000};
136 CHECK(adjtimex(&value) == -1 && errno == EINVAL);
147static int privilege(
void) {
149 CHECK(setuid(65534) == 0 && geteuid() == 65534);
151 CHECK(step(0, 0, 0, 0) == -1 && errno == EPERM);
152 const unsigned modes[] = {ADJ_NANO, ADJ_MICRO, ADJ_OFFSET_SINGLESHOT, ADJ_FREQUENCY};
153 for (
unsigned n = 0; n <
sizeof(modes) /
sizeof(modes[0]); ++n) {
154 struct timex value = {.modes = modes[n]};
155 CHECK(adjtimex(&value) == -1 && errno == EPERM);
161static int reap(pid_t child) {
162 const int64_t deadline = now(CLOCK_MONOTONIC) + 30000000000;
163 while (now(CLOCK_MONOTONIC) < deadline) {
165 pid_t result = waitpid(child, &status, WNOHANG);
167 return WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
168 if (result < 0 && errno != EINTR)
170 struct timespec pause = {0, 5000000};
171 nanosleep(&pause, NULL);
173 kill(child, SIGKILL);
174 while (waitpid(child, NULL, 0) < 0 && errno == EINTR) {
181 puts(
"CLOCK-ADJUST-CONTRACT: FAIL requires root");
187 } suites[] = {{
"query", query}, {
"steps", steps}, {
"privilege", privilege}};
188 for (
unsigned n = 0; n <
sizeof(suites) /
sizeof(suites[0]); ++n) {
189 struct timex original = {0};
190 if (adjtimex(&original) < 0)
192 int64_t realtime = now(CLOCK_REALTIME), monotonic = now(CLOCK_MONOTONIC);
193 printf(
"CLOCK-ADJUST-CONTRACT: BEGIN %s\n", suites[n].name);
195 pid_t child = fork();
200 int result = suites[n].test();
203 _exit(result ? 1 : 0);
205 int result = reap(child);
206 if (!strcmp(suites[n].name,
"steps")) {
207 struct timespec restored = timespec(realtime + now(CLOCK_MONOTONIC) - monotonic);
208 struct timex mode = {.modes = original.status & STA_NANO ? ADJ_NANO : ADJ_MICRO};
209 if (clock_settime(CLOCK_REALTIME, &restored) || adjtimex(&mode) < 0)
212 printf(
"CLOCK-ADJUST-CONTRACT: %s %s status=%d\n", result ?
"FAIL" :
"PASS", suites[n].name,
218 puts(
"CLOCK-ADJUST-CONTRACT: END PASS");