162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#define _GNU_SOURCE 362306a36Sopenharmony_ci#include <errno.h> 462306a36Sopenharmony_ci#include <fcntl.h> 562306a36Sopenharmony_ci#include <sched.h> 662306a36Sopenharmony_ci#include <stdio.h> 762306a36Sopenharmony_ci#include <stdbool.h> 862306a36Sopenharmony_ci#include <sys/stat.h> 962306a36Sopenharmony_ci#include <sys/syscall.h> 1062306a36Sopenharmony_ci#include <sys/types.h> 1162306a36Sopenharmony_ci#include <sys/wait.h> 1262306a36Sopenharmony_ci#include <time.h> 1362306a36Sopenharmony_ci#include <unistd.h> 1462306a36Sopenharmony_ci#include <string.h> 1562306a36Sopenharmony_ci#include <pthread.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "log.h" 1862306a36Sopenharmony_ci#include "timens.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define OFFSET (36000) 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct thread_args { 2362306a36Sopenharmony_ci char *tst_name; 2462306a36Sopenharmony_ci struct timespec *now; 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic void *tcheck(void *_args) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct thread_args *args = _args; 3062306a36Sopenharmony_ci struct timespec *now = args->now, tst; 3162306a36Sopenharmony_ci int i; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 3462306a36Sopenharmony_ci _gettime(CLOCK_MONOTONIC, &tst, i); 3562306a36Sopenharmony_ci if (abs(tst.tv_sec - now->tv_sec) > 5) { 3662306a36Sopenharmony_ci pr_fail("%s: in-thread: unexpected value: %ld (%ld)\n", 3762306a36Sopenharmony_ci args->tst_name, tst.tv_sec, now->tv_sec); 3862306a36Sopenharmony_ci return (void *)1UL; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci return NULL; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic int check_in_thread(char *tst_name, struct timespec *now) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct thread_args args = { 4762306a36Sopenharmony_ci .tst_name = tst_name, 4862306a36Sopenharmony_ci .now = now, 4962306a36Sopenharmony_ci }; 5062306a36Sopenharmony_ci pthread_t th; 5162306a36Sopenharmony_ci void *retval; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (pthread_create(&th, NULL, tcheck, &args)) 5462306a36Sopenharmony_ci return pr_perror("thread"); 5562306a36Sopenharmony_ci if (pthread_join(th, &retval)) 5662306a36Sopenharmony_ci return pr_perror("pthread_join"); 5762306a36Sopenharmony_ci return !(retval == NULL); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic int check(char *tst_name, struct timespec *now) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct timespec tst; 6362306a36Sopenharmony_ci int i; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 6662306a36Sopenharmony_ci _gettime(CLOCK_MONOTONIC, &tst, i); 6762306a36Sopenharmony_ci if (abs(tst.tv_sec - now->tv_sec) > 5) 6862306a36Sopenharmony_ci return pr_fail("%s: unexpected value: %ld (%ld)\n", 6962306a36Sopenharmony_ci tst_name, tst.tv_sec, now->tv_sec); 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci if (check_in_thread(tst_name, now)) 7262306a36Sopenharmony_ci return 1; 7362306a36Sopenharmony_ci ksft_test_result_pass("%s\n", tst_name); 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ciint main(int argc, char *argv[]) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct timespec now; 8062306a36Sopenharmony_ci int status; 8162306a36Sopenharmony_ci pid_t pid; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (argc > 1) { 8462306a36Sopenharmony_ci char *endptr; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci ksft_cnt.ksft_pass = 1; 8762306a36Sopenharmony_ci now.tv_sec = strtoul(argv[1], &endptr, 0); 8862306a36Sopenharmony_ci if (*endptr != 0) 8962306a36Sopenharmony_ci return pr_perror("strtoul"); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return check("child after exec", &now); 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci nscheck(); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci ksft_set_plan(4); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &now); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (unshare_timens()) 10162306a36Sopenharmony_ci return 1; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (_settime(CLOCK_MONOTONIC, OFFSET)) 10462306a36Sopenharmony_ci return 1; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (check("parent before vfork", &now)) 10762306a36Sopenharmony_ci return 1; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci pid = vfork(); 11062306a36Sopenharmony_ci if (pid < 0) 11162306a36Sopenharmony_ci return pr_perror("fork"); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (pid == 0) { 11462306a36Sopenharmony_ci char now_str[64]; 11562306a36Sopenharmony_ci char *cargv[] = {"exec", now_str, NULL}; 11662306a36Sopenharmony_ci char *cenv[] = {NULL}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* Check for proper vvar offsets after execve. */ 11962306a36Sopenharmony_ci snprintf(now_str, sizeof(now_str), "%ld", now.tv_sec + OFFSET); 12062306a36Sopenharmony_ci execve("/proc/self/exe", cargv, cenv); 12162306a36Sopenharmony_ci pr_perror("execve"); 12262306a36Sopenharmony_ci _exit(1); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (waitpid(pid, &status, 0) != pid) 12662306a36Sopenharmony_ci return pr_perror("waitpid"); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (status) 12962306a36Sopenharmony_ci ksft_exit_fail(); 13062306a36Sopenharmony_ci ksft_inc_pass_cnt(); 13162306a36Sopenharmony_ci ksft_test_result_pass("wait for child\n"); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* Check that we are still in the source timens. */ 13462306a36Sopenharmony_ci if (check("parent after vfork", &now)) 13562306a36Sopenharmony_ci return 1; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci ksft_exit_pass(); 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci} 140