161c57676SDmitry Safonov // SPDX-License-Identifier: GPL-2.0
261c57676SDmitry Safonov #define _GNU_SOURCE
361c57676SDmitry Safonov #include <errno.h>
461c57676SDmitry Safonov #include <fcntl.h>
561c57676SDmitry Safonov #include <sched.h>
661c57676SDmitry Safonov #include <stdio.h>
761c57676SDmitry Safonov #include <stdbool.h>
861c57676SDmitry Safonov #include <sys/stat.h>
961c57676SDmitry Safonov #include <sys/syscall.h>
1061c57676SDmitry Safonov #include <sys/types.h>
1161c57676SDmitry Safonov #include <time.h>
1261c57676SDmitry Safonov #include <unistd.h>
1361c57676SDmitry Safonov #include <string.h>
1461c57676SDmitry Safonov
1561c57676SDmitry Safonov #include "log.h"
1661c57676SDmitry Safonov #include "timens.h"
1761c57676SDmitry Safonov
1861c57676SDmitry Safonov /*
1961c57676SDmitry Safonov * Test shouldn't be run for a day, so add 10 days to child
2061c57676SDmitry Safonov * time and check parent's time to be in the same day.
2161c57676SDmitry Safonov */
2261c57676SDmitry Safonov #define DAY_IN_SEC (60*60*24)
2361c57676SDmitry Safonov #define TEN_DAYS_IN_SEC (10*DAY_IN_SEC)
2461c57676SDmitry Safonov
2561c57676SDmitry Safonov struct test_clock {
2661c57676SDmitry Safonov clockid_t id;
2761c57676SDmitry Safonov char *name;
2861c57676SDmitry Safonov /*
2961c57676SDmitry Safonov * off_id is -1 if a clock has own offset, or it contains an index
3061c57676SDmitry Safonov * which contains a right offset of this clock.
3161c57676SDmitry Safonov */
3261c57676SDmitry Safonov int off_id;
3361c57676SDmitry Safonov time_t offset;
3461c57676SDmitry Safonov };
3561c57676SDmitry Safonov
3661c57676SDmitry Safonov #define ct(clock, off_id) { clock, #clock, off_id }
3761c57676SDmitry Safonov static struct test_clock clocks[] = {
3861c57676SDmitry Safonov ct(CLOCK_BOOTTIME, -1),
3961c57676SDmitry Safonov ct(CLOCK_BOOTTIME_ALARM, 1),
4061c57676SDmitry Safonov ct(CLOCK_MONOTONIC, -1),
4161c57676SDmitry Safonov ct(CLOCK_MONOTONIC_COARSE, 1),
4261c57676SDmitry Safonov ct(CLOCK_MONOTONIC_RAW, 1),
4361c57676SDmitry Safonov };
4461c57676SDmitry Safonov #undef ct
4561c57676SDmitry Safonov
4661c57676SDmitry Safonov static int child_ns, parent_ns = -1;
4761c57676SDmitry Safonov
switch_ns(int fd)4861c57676SDmitry Safonov static int switch_ns(int fd)
4961c57676SDmitry Safonov {
5061c57676SDmitry Safonov if (setns(fd, CLONE_NEWTIME)) {
5161c57676SDmitry Safonov pr_perror("setns()");
5261c57676SDmitry Safonov return -1;
5361c57676SDmitry Safonov }
5461c57676SDmitry Safonov
5561c57676SDmitry Safonov return 0;
5661c57676SDmitry Safonov }
5761c57676SDmitry Safonov
init_namespaces(void)5861c57676SDmitry Safonov static int init_namespaces(void)
5961c57676SDmitry Safonov {
6061c57676SDmitry Safonov char path[] = "/proc/self/ns/time_for_children";
6161c57676SDmitry Safonov struct stat st1, st2;
6261c57676SDmitry Safonov
6361c57676SDmitry Safonov if (parent_ns == -1) {
6461c57676SDmitry Safonov parent_ns = open(path, O_RDONLY);
6561c57676SDmitry Safonov if (parent_ns <= 0)
6661c57676SDmitry Safonov return pr_perror("Unable to open %s", path);
6761c57676SDmitry Safonov }
6861c57676SDmitry Safonov
6961c57676SDmitry Safonov if (fstat(parent_ns, &st1))
7061c57676SDmitry Safonov return pr_perror("Unable to stat the parent timens");
7161c57676SDmitry Safonov
7261c57676SDmitry Safonov if (unshare_timens())
7361c57676SDmitry Safonov return -1;
7461c57676SDmitry Safonov
7561c57676SDmitry Safonov child_ns = open(path, O_RDONLY);
7661c57676SDmitry Safonov if (child_ns <= 0)
7761c57676SDmitry Safonov return pr_perror("Unable to open %s", path);
7861c57676SDmitry Safonov
7961c57676SDmitry Safonov if (fstat(child_ns, &st2))
8061c57676SDmitry Safonov return pr_perror("Unable to stat the timens");
8161c57676SDmitry Safonov
8261c57676SDmitry Safonov if (st1.st_ino == st2.st_ino)
8361c57676SDmitry Safonov return pr_perror("The same child_ns after CLONE_NEWTIME");
8461c57676SDmitry Safonov
8561c57676SDmitry Safonov return 0;
8661c57676SDmitry Safonov }
8761c57676SDmitry Safonov
test_gettime(clockid_t clock_index,bool raw_syscall,time_t offset)8861c57676SDmitry Safonov static int test_gettime(clockid_t clock_index, bool raw_syscall, time_t offset)
8961c57676SDmitry Safonov {
9061c57676SDmitry Safonov struct timespec child_ts_new, parent_ts_old, cur_ts;
9161c57676SDmitry Safonov char *entry = raw_syscall ? "syscall" : "vdso";
9261c57676SDmitry Safonov double precision = 0.0;
9361c57676SDmitry Safonov
9461c57676SDmitry Safonov if (check_skip(clocks[clock_index].id))
9561c57676SDmitry Safonov return 0;
9661c57676SDmitry Safonov
9761c57676SDmitry Safonov switch (clocks[clock_index].id) {
9861c57676SDmitry Safonov case CLOCK_MONOTONIC_COARSE:
9961c57676SDmitry Safonov case CLOCK_MONOTONIC_RAW:
10061c57676SDmitry Safonov precision = -2.0;
10161c57676SDmitry Safonov break;
10261c57676SDmitry Safonov }
10361c57676SDmitry Safonov
10461c57676SDmitry Safonov if (switch_ns(parent_ns))
10561c57676SDmitry Safonov return pr_err("switch_ns(%d)", child_ns);
10661c57676SDmitry Safonov
10761c57676SDmitry Safonov if (_gettime(clocks[clock_index].id, &parent_ts_old, raw_syscall))
10861c57676SDmitry Safonov return -1;
10961c57676SDmitry Safonov
11061c57676SDmitry Safonov child_ts_new.tv_nsec = parent_ts_old.tv_nsec;
11161c57676SDmitry Safonov child_ts_new.tv_sec = parent_ts_old.tv_sec + offset;
11261c57676SDmitry Safonov
11361c57676SDmitry Safonov if (switch_ns(child_ns))
11461c57676SDmitry Safonov return pr_err("switch_ns(%d)", child_ns);
11561c57676SDmitry Safonov
11661c57676SDmitry Safonov if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall))
11761c57676SDmitry Safonov return -1;
11861c57676SDmitry Safonov
11961c57676SDmitry Safonov if (difftime(cur_ts.tv_sec, child_ts_new.tv_sec) < precision) {
12061c57676SDmitry Safonov ksft_test_result_fail(
12161c57676SDmitry Safonov "Child's %s (%s) time has not changed: %lu -> %lu [%lu]\n",
12261c57676SDmitry Safonov clocks[clock_index].name, entry, parent_ts_old.tv_sec,
12361c57676SDmitry Safonov child_ts_new.tv_sec, cur_ts.tv_sec);
12461c57676SDmitry Safonov return -1;
12561c57676SDmitry Safonov }
12661c57676SDmitry Safonov
12761c57676SDmitry Safonov if (switch_ns(parent_ns))
12861c57676SDmitry Safonov return pr_err("switch_ns(%d)", parent_ns);
12961c57676SDmitry Safonov
13061c57676SDmitry Safonov if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall))
13161c57676SDmitry Safonov return -1;
13261c57676SDmitry Safonov
13361c57676SDmitry Safonov if (difftime(cur_ts.tv_sec, parent_ts_old.tv_sec) > DAY_IN_SEC) {
13461c57676SDmitry Safonov ksft_test_result_fail(
13561c57676SDmitry Safonov "Parent's %s (%s) time has changed: %lu -> %lu [%lu]\n",
13661c57676SDmitry Safonov clocks[clock_index].name, entry, parent_ts_old.tv_sec,
13761c57676SDmitry Safonov child_ts_new.tv_sec, cur_ts.tv_sec);
13861c57676SDmitry Safonov /* Let's play nice and put it closer to original */
13961c57676SDmitry Safonov clock_settime(clocks[clock_index].id, &cur_ts);
14061c57676SDmitry Safonov return -1;
14161c57676SDmitry Safonov }
14261c57676SDmitry Safonov
14361c57676SDmitry Safonov ksft_test_result_pass("Passed for %s (%s)\n",
14461c57676SDmitry Safonov clocks[clock_index].name, entry);
14561c57676SDmitry Safonov return 0;
14661c57676SDmitry Safonov }
14761c57676SDmitry Safonov
main(int argc,char * argv[])14861c57676SDmitry Safonov int main(int argc, char *argv[])
14961c57676SDmitry Safonov {
15061c57676SDmitry Safonov unsigned int i;
15161c57676SDmitry Safonov time_t offset;
15261c57676SDmitry Safonov int ret = 0;
15361c57676SDmitry Safonov
15461c57676SDmitry Safonov nscheck();
15561c57676SDmitry Safonov
156*558ae035SAndrei Vagin check_supported_timers();
15761c57676SDmitry Safonov
15861c57676SDmitry Safonov ksft_set_plan(ARRAY_SIZE(clocks) * 2);
15961c57676SDmitry Safonov
16061c57676SDmitry Safonov if (init_namespaces())
16161c57676SDmitry Safonov return 1;
16261c57676SDmitry Safonov
16361c57676SDmitry Safonov /* Offsets have to be set before tasks enter the namespace. */
16461c57676SDmitry Safonov for (i = 0; i < ARRAY_SIZE(clocks); i++) {
16561c57676SDmitry Safonov if (clocks[i].off_id != -1)
16661c57676SDmitry Safonov continue;
16761c57676SDmitry Safonov offset = TEN_DAYS_IN_SEC + i * 1000;
16861c57676SDmitry Safonov clocks[i].offset = offset;
16961c57676SDmitry Safonov if (_settime(clocks[i].id, offset))
17061c57676SDmitry Safonov return 1;
17161c57676SDmitry Safonov }
17261c57676SDmitry Safonov
17361c57676SDmitry Safonov for (i = 0; i < ARRAY_SIZE(clocks); i++) {
17461c57676SDmitry Safonov if (clocks[i].off_id != -1)
17561c57676SDmitry Safonov offset = clocks[clocks[i].off_id].offset;
17661c57676SDmitry Safonov else
17761c57676SDmitry Safonov offset = clocks[i].offset;
17861c57676SDmitry Safonov ret |= test_gettime(i, true, offset);
17961c57676SDmitry Safonov ret |= test_gettime(i, false, offset);
18061c57676SDmitry Safonov }
18161c57676SDmitry Safonov
18261c57676SDmitry Safonov if (ret)
18361c57676SDmitry Safonov ksft_exit_fail();
18461c57676SDmitry Safonov
18561c57676SDmitry Safonov ksft_exit_pass();
18661c57676SDmitry Safonov return !!ret;
18761c57676SDmitry Safonov }
188