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 pid = vfork(); 59 if (pid < 0) 60 return pr_perror("fork"); 61 62 if (pid == 0) { 63 char now_str[64]; 64 char *cargv[] = {"exec", now_str, NULL}; 65 char *cenv[] = {NULL}; 66 67 // Check that we are still in the source timens. 68 for (i = 0; i < 2; i++) { 69 _gettime(CLOCK_MONOTONIC, &tst, i); 70 if (abs(tst.tv_sec - now.tv_sec) > 5) 71 return pr_fail("%ld %ld\n", 72 now.tv_sec, tst.tv_sec); 73 } 74 75 /* Check for proper vvar offsets after execve. */ 76 snprintf(now_str, sizeof(now_str), "%ld", now.tv_sec + OFFSET); 77 execve("/proc/self/exe", cargv, cenv); 78 return pr_perror("execve"); 79 } 80 81 if (waitpid(pid, &status, 0) != pid) 82 return pr_perror("waitpid"); 83 84 if (status) 85 ksft_exit_fail(); 86 87 ksft_test_result_pass("exec\n"); 88 ksft_exit_pass(); 89 return 0; 90 } 91