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 <sys/wait.h>
12 #include <time.h>
13 #include <unistd.h>
14 #include <time.h>
15 #include <string.h>
16 
17 #include "log.h"
18 #include "timens.h"
19 
20 #define OFFSET (36000)
21 
22 int main(int argc, char *argv[])
23 {
24 	struct timespec now, tst;
25 	int status, i;
26 	pid_t pid;
27 
28 	if (argc > 1) {
29 		if (sscanf(argv[1], "%ld", &now.tv_sec) != 1)
30 			return pr_perror("sscanf");
31 
32 		for (i = 0; i < 2; i++) {
33 			_gettime(CLOCK_MONOTONIC, &tst, i);
34 			if (abs(tst.tv_sec - now.tv_sec) > 5)
35 				return pr_fail("%ld %ld\n", now.tv_sec, tst.tv_sec);
36 		}
37 		return 0;
38 	}
39 
40 	nscheck();
41 
42 	ksft_set_plan(1);
43 
44 	clock_gettime(CLOCK_MONOTONIC, &now);
45 
46 	if (unshare_timens())
47 		return 1;
48 
49 	if (_settime(CLOCK_MONOTONIC, OFFSET))
50 		return 1;
51 
52 	for (i = 0; i < 2; i++) {
53 		_gettime(CLOCK_MONOTONIC, &tst, i);
54 		if (abs(tst.tv_sec - now.tv_sec) > 5)
55 			return pr_fail("%ld %ld\n",
56 					now.tv_sec, tst.tv_sec);
57 	}
58 
59 	if (argc > 1)
60 		return 0;
61 
62 	pid = fork();
63 	if (pid < 0)
64 		return pr_perror("fork");
65 
66 	if (pid == 0) {
67 		char now_str[64];
68 		char *cargv[] = {"exec", now_str, NULL};
69 		char *cenv[] = {NULL};
70 
71 		/* Check that a child process is in the new timens. */
72 		for (i = 0; i < 2; i++) {
73 			_gettime(CLOCK_MONOTONIC, &tst, i);
74 			if (abs(tst.tv_sec - now.tv_sec - OFFSET) > 5)
75 				return pr_fail("%ld %ld\n",
76 						now.tv_sec + OFFSET, tst.tv_sec);
77 		}
78 
79 		/* Check for proper vvar offsets after execve. */
80 		snprintf(now_str, sizeof(now_str), "%ld", now.tv_sec + OFFSET);
81 		execve("/proc/self/exe", cargv, cenv);
82 		return pr_perror("execve");
83 	}
84 
85 	if (waitpid(pid, &status, 0) != pid)
86 		return pr_perror("waitpid");
87 
88 	if (status)
89 		ksft_exit_fail();
90 
91 	ksft_test_result_pass("exec\n");
92 	ksft_exit_pass();
93 	return 0;
94 }
95