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