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