Skip to content

Commit 29b9b12

Browse files
committed
selftests/timens: add a test for vfork+exit
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2116442 commit af4fddf Author: Andrei Vagin <avagin@gmail.com> Date: Thu Oct 13 10:31:54 2022 -0700 selftests/timens: add a test for vfork+exit * check that a child process is in parent's time namespace after vfork. * check that a child process is in the target namespace after exec. Output on success: 1..4 ok 1 parent before vfork ok 2 child after exec ok 3 wait for child ok 4 parent after vfork # Totals: pass:4 fail:0 xfail:0 xpass:0 skip:0 error:0 Signed-off-by: Andrei Vagin <avagin@gmail.com> Signed-off-by: Kees Cook <keescook@chromium.org> Link: https://lore.kernel.org/r/20221013173154.291597-1-avagin@google.com Signed-off-by: Oleg Nesterov <oleg@redhat.com>
1 parent 9da64ba commit 29b9b12

File tree

3 files changed

+141
-1
lines changed

3 files changed

+141
-1
lines changed

tools/testing/selftests/timens/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ procfs
88
timens
99
timer
1010
timerfd
11+
vfork_exec

tools/testing/selftests/timens/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
TEST_GEN_PROGS := timens timerfd timer clock_nanosleep procfs exec futex
1+
TEST_GEN_PROGS := timens timerfd timer clock_nanosleep procfs exec futex vfork_exec
22
TEST_GEN_PROGS_EXTENDED := gettime_perf
33

44
CFLAGS := -Wall -Werror -pthread
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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 (abs(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 (abs(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+
}

0 commit comments

Comments
 (0)