1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <sched.h>
6 #include <stdio.h>
7 #include <stdbool.h>
8 #include <sys/stat.h>
9 #include <sys/syscall.h>
10 #include <sys/types.h>
11 #include <time.h>
12 #include <unistd.h>
13 #include <time.h>
14 #include <string.h>
15 
16 #include "log.h"
17 #include "timens.h"
18 
19 /*
20  * Test shouldn't be run for a day, so add 10 days to child
21  * time and check parent's time to be in the same day.
22  */
23 #define DAY_IN_SEC			(60*60*24)
24 #define TEN_DAYS_IN_SEC			(10*DAY_IN_SEC)
25 
26 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
27 
28 struct test_clock {
29 	clockid_t id;
30 	char *name;
31 	/*
32 	 * off_id is -1 if a clock has own offset, or it contains an index
33 	 * which contains a right offset of this clock.
34 	 */
35 	int off_id;
36 	time_t offset;
37 };
38 
39 #define ct(clock, off_id)	{ clock, #clock, off_id }
40 static struct test_clock clocks[] = {
41 	ct(CLOCK_BOOTTIME, -1),
42 	ct(CLOCK_BOOTTIME_ALARM, 1),
43 	ct(CLOCK_MONOTONIC, -1),
44 	ct(CLOCK_MONOTONIC_COARSE, 1),
45 	ct(CLOCK_MONOTONIC_RAW, 1),
46 };
47 #undef ct
48 
49 static int child_ns, parent_ns = -1;
50 
51 static int switch_ns(int fd)
52 {
53 	if (setns(fd, CLONE_NEWTIME)) {
54 		pr_perror("setns()");
55 		return -1;
56 	}
57 
58 	return 0;
59 }
60 
61 static int init_namespaces(void)
62 {
63 	char path[] = "/proc/self/ns/time_for_children";
64 	struct stat st1, st2;
65 
66 	if (parent_ns == -1) {
67 		parent_ns = open(path, O_RDONLY);
68 		if (parent_ns <= 0)
69 			return pr_perror("Unable to open %s", path);
70 	}
71 
72 	if (fstat(parent_ns, &st1))
73 		return pr_perror("Unable to stat the parent timens");
74 
75 	if (unshare_timens())
76 		return  -1;
77 
78 	child_ns = open(path, O_RDONLY);
79 	if (child_ns <= 0)
80 		return pr_perror("Unable to open %s", path);
81 
82 	if (fstat(child_ns, &st2))
83 		return pr_perror("Unable to stat the timens");
84 
85 	if (st1.st_ino == st2.st_ino)
86 		return pr_perror("The same child_ns after CLONE_NEWTIME");
87 
88 	return 0;
89 }
90 
91 static int test_gettime(clockid_t clock_index, bool raw_syscall, time_t offset)
92 {
93 	struct timespec child_ts_new, parent_ts_old, cur_ts;
94 	char *entry = raw_syscall ? "syscall" : "vdso";
95 	double precision = 0.0;
96 
97 	if (check_skip(clocks[clock_index].id))
98 		return 0;
99 
100 	switch (clocks[clock_index].id) {
101 	case CLOCK_MONOTONIC_COARSE:
102 	case CLOCK_MONOTONIC_RAW:
103 		precision = -2.0;
104 		break;
105 	}
106 
107 	if (switch_ns(parent_ns))
108 		return pr_err("switch_ns(%d)", child_ns);
109 
110 	if (_gettime(clocks[clock_index].id, &parent_ts_old, raw_syscall))
111 		return -1;
112 
113 	child_ts_new.tv_nsec = parent_ts_old.tv_nsec;
114 	child_ts_new.tv_sec = parent_ts_old.tv_sec + offset;
115 
116 	if (switch_ns(child_ns))
117 		return pr_err("switch_ns(%d)", child_ns);
118 
119 	if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall))
120 		return -1;
121 
122 	if (difftime(cur_ts.tv_sec, child_ts_new.tv_sec) < precision) {
123 		ksft_test_result_fail(
124 			"Child's %s (%s) time has not changed: %lu -> %lu [%lu]\n",
125 			clocks[clock_index].name, entry, parent_ts_old.tv_sec,
126 			child_ts_new.tv_sec, cur_ts.tv_sec);
127 		return -1;
128 	}
129 
130 	if (switch_ns(parent_ns))
131 		return pr_err("switch_ns(%d)", parent_ns);
132 
133 	if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall))
134 		return -1;
135 
136 	if (difftime(cur_ts.tv_sec, parent_ts_old.tv_sec) > DAY_IN_SEC) {
137 		ksft_test_result_fail(
138 			"Parent's %s (%s) time has changed: %lu -> %lu [%lu]\n",
139 			clocks[clock_index].name, entry, parent_ts_old.tv_sec,
140 			child_ts_new.tv_sec, cur_ts.tv_sec);
141 		/* Let's play nice and put it closer to original */
142 		clock_settime(clocks[clock_index].id, &cur_ts);
143 		return -1;
144 	}
145 
146 	ksft_test_result_pass("Passed for %s (%s)\n",
147 				clocks[clock_index].name, entry);
148 	return 0;
149 }
150 
151 int main(int argc, char *argv[])
152 {
153 	unsigned int i;
154 	time_t offset;
155 	int ret = 0;
156 
157 	nscheck();
158 
159 	check_config_posix_timers();
160 
161 	ksft_set_plan(ARRAY_SIZE(clocks) * 2);
162 
163 	if (init_namespaces())
164 		return 1;
165 
166 	/* Offsets have to be set before tasks enter the namespace. */
167 	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
168 		if (clocks[i].off_id != -1)
169 			continue;
170 		offset = TEN_DAYS_IN_SEC + i * 1000;
171 		clocks[i].offset = offset;
172 		if (_settime(clocks[i].id, offset))
173 			return 1;
174 	}
175 
176 	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
177 		if (clocks[i].off_id != -1)
178 			offset = clocks[clocks[i].off_id].offset;
179 		else
180 			offset = clocks[i].offset;
181 		ret |= test_gettime(i, true, offset);
182 		ret |= test_gettime(i, false, offset);
183 	}
184 
185 	if (ret)
186 		ksft_exit_fail();
187 
188 	ksft_exit_pass();
189 	return !!ret;
190 }
191