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 #include <pthread.h> 16 17 #include "log.h" 18 #include "timens.h" 19 20 #define OFFSET (36000) 21 22 struct thread_args { 23 char *tst_name; 24 struct timespec *now; 25 }; 26 27 static void *tcheck(void *_args) 28 { 29 struct thread_args *args = _args; 30 struct timespec *now = args->now, tst; 31 int i; 32 33 for (i = 0; i < 2; i++) { 34 _gettime(CLOCK_MONOTONIC, &tst, i); 35 if (labs(tst.tv_sec - now->tv_sec) > 5) { 36 pr_fail("%s: in-thread: unexpected value: %ld (%ld)\n", 37 args->tst_name, tst.tv_sec, now->tv_sec); 38 return (void *)1UL; 39 } 40 } 41 return NULL; 42 } 43 44 static int check_in_thread(char *tst_name, struct timespec *now) 45 { 46 struct thread_args args = { 47 .tst_name = tst_name, 48 .now = now, 49 }; 50 pthread_t th; 51 void *retval; 52 53 if (pthread_create(&th, NULL, tcheck, &args)) 54 return pr_perror("thread"); 55 if (pthread_join(th, &retval)) 56 return pr_perror("pthread_join"); 57 return !(retval == NULL); 58 } 59 60 static int check(char *tst_name, struct timespec *now) 61 { 62 struct timespec tst; 63 int i; 64 65 for (i = 0; i < 2; i++) { 66 _gettime(CLOCK_MONOTONIC, &tst, i); 67 if (labs(tst.tv_sec - now->tv_sec) > 5) 68 return pr_fail("%s: unexpected value: %ld (%ld)\n", 69 tst_name, tst.tv_sec, now->tv_sec); 70 } 71 if (check_in_thread(tst_name, now)) 72 return 1; 73 ksft_test_result_pass("%s\n", tst_name); 74 return 0; 75 } 76 77 int main(int argc, char *argv[]) 78 { 79 struct timespec now; 80 int status; 81 pid_t pid; 82 83 if (argc > 1) { 84 char *endptr; 85 86 ksft_cnt.ksft_pass = 1; 87 now.tv_sec = strtoul(argv[1], &endptr, 0); 88 if (*endptr != 0) 89 return pr_perror("strtoul"); 90 91 return check("child after exec", &now); 92 } 93 94 nscheck(); 95 96 ksft_set_plan(4); 97 98 clock_gettime(CLOCK_MONOTONIC, &now); 99 100 if (unshare_timens()) 101 return 1; 102 103 if (_settime(CLOCK_MONOTONIC, OFFSET)) 104 return 1; 105 106 if (check("parent before vfork", &now)) 107 return 1; 108 109 pid = vfork(); 110 if (pid < 0) 111 return pr_perror("fork"); 112 113 if (pid == 0) { 114 char now_str[64]; 115 char *cargv[] = {"exec", now_str, NULL}; 116 char *cenv[] = {NULL}; 117 118 /* Check for proper vvar offsets after execve. */ 119 snprintf(now_str, sizeof(now_str), "%ld", now.tv_sec + OFFSET); 120 execve("/proc/self/exe", cargv, cenv); 121 pr_perror("execve"); 122 _exit(1); 123 } 124 125 if (waitpid(pid, &status, 0) != pid) 126 return pr_perror("waitpid"); 127 128 if (status) 129 ksft_exit_fail(); 130 ksft_inc_pass_cnt(); 131 ksft_test_result_pass("wait for child\n"); 132 133 /* Check that we are still in the source timens. */ 134 if (check("parent after vfork", &now)) 135 return 1; 136 137 ksft_exit_pass(); 138 return 0; 139 } 140