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