1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org>
4 *
5 * Basic clone3() test.
6 */
7 #define _GNU_SOURCE
8
9 #include <stdlib.h>
10 #include <sys/wait.h>
11
12 #include "tst_test.h"
13 #include "lapi/clone.h"
14 #include "lapi/pidfd_send_signal.h"
15
16 #define CHILD_SIGNAL SIGUSR1
17 #define DATA 777
18
19 static int pidfd, child_tid, parent_tid, parent_received_signal;
20 static volatile int child_received_signal, child_data;
21 static struct clone_args *args;
22
23 static struct tcase {
24 uint64_t flags;
25 int exit_signal;
26 } tcases[] = {
27 {0, SIGCHLD},
28 {0, SIGUSR2},
29 {CLONE_FS, SIGCHLD},
30 {CLONE_NEWPID, SIGCHLD},
31 {CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_PIDFD, SIGCHLD},
32 };
33
parent_rx_signal(int sig)34 static void parent_rx_signal(int sig)
35 {
36 parent_received_signal = sig;
37 }
38
child_rx_signal(int sig,siginfo_t * info,void * ucontext)39 static void child_rx_signal(int sig, siginfo_t *info, void *ucontext)
40 {
41 (void) ucontext;
42
43 child_received_signal = sig;
44 child_data = info->si_value.sival_int;
45 }
46
47 static struct sigaction psig_action = {
48 .sa_handler = parent_rx_signal,
49 };
50
51 static struct sigaction csig_action = {
52 .sa_sigaction = child_rx_signal,
53 .sa_flags = SA_SIGINFO,
54 };
55
56 static siginfo_t uinfo = {
57 .si_signo = CHILD_SIGNAL,
58 .si_code = SI_QUEUE,
59 .si_value.sival_int = DATA,
60 };
61
62
do_child(int clone_pidfd)63 static void do_child(int clone_pidfd)
64 {
65 int count = 1000;
66
67 if (clone_pidfd) {
68 child_received_signal = 0;
69 child_data = 0;
70
71 SAFE_SIGACTION(CHILD_SIGNAL, &csig_action, NULL);
72
73 TST_CHECKPOINT_WAKE(0);
74
75 while (child_received_signal != CHILD_SIGNAL && --count)
76 usleep(100);
77
78 if (!child_received_signal) {
79 tst_res(TFAIL, "Child haven't got signal");
80 exit(0);
81 }
82
83 if (child_received_signal != CHILD_SIGNAL) {
84 tst_res(TFAIL, "Child got %s (%i) signal expected %s",
85 tst_strsig(child_received_signal),
86 child_received_signal,
87 tst_strsig(CHILD_SIGNAL));
88 exit(0);
89 }
90
91 tst_res(TPASS, "Child got correct signal %s",
92 tst_strsig(CHILD_SIGNAL));
93
94 if (child_data != DATA) {
95 tst_res(TFAIL, "Child got wrong si_value=%i expected %i",
96 child_data, DATA);
97 } else {
98 tst_res(TPASS, "Child got correct si_value");
99 }
100 }
101
102 exit(0);
103 }
104
run(unsigned int n)105 static void run(unsigned int n)
106 {
107 struct tcase *tc = &tcases[n];
108 int status, clone_pidfd = tc->flags & CLONE_PIDFD;
109 pid_t pid;
110
111 args->flags = tc->flags;
112 args->pidfd = (uint64_t)(&pidfd);
113 args->child_tid = (uint64_t)(&child_tid);
114 args->parent_tid = (uint64_t)(&parent_tid);
115 args->exit_signal = tc->exit_signal;
116 args->stack = 0;
117 args->stack_size = 0;
118 args->tls = 0;
119
120 parent_received_signal = 0;
121 SAFE_SIGACTION(tc->exit_signal, &psig_action, NULL);
122
123 TEST(pid = clone3(args, sizeof(*args)));
124 if (pid < 0) {
125 tst_res(TFAIL | TTERRNO, "clone3() failed (%d)", n);
126 return;
127 }
128
129 if (!pid)
130 do_child(clone_pidfd);
131
132 /* Need to send signal to child process */
133 if (clone_pidfd) {
134 TST_CHECKPOINT_WAIT(0);
135
136 TEST(pidfd_send_signal(pidfd, CHILD_SIGNAL, &uinfo, 0));
137 if (TST_RET != 0) {
138 tst_res(TFAIL | TTERRNO, "pidfd_send_signal() failed");
139 return;
140 }
141 }
142
143 SAFE_WAITPID(pid, &status, __WALL);
144
145 if (!parent_received_signal) {
146 tst_res(TFAIL, "Parent haven't got signal");
147 return;
148 }
149
150 if (parent_received_signal != tc->exit_signal) {
151 tst_res(TFAIL, "Parent got %s (%i) signal expected %s",
152 tst_strsig(parent_received_signal),
153 parent_received_signal,
154 tst_strsig(tc->exit_signal));
155 return;
156 }
157
158 tst_res(TPASS, "Parent got correct signal %s",
159 tst_strsig(parent_received_signal));
160 }
161
setup(void)162 static void setup(void)
163 {
164 clone3_supported_by_kernel();
165
166 uinfo.si_pid = getpid();
167 uinfo.si_uid = getuid();
168 }
169
170 static struct tst_test test = {
171 .tcnt = ARRAY_SIZE(tcases),
172 .test = run,
173 .setup = setup,
174 .needs_root = 1,
175 .needs_tmpdir = 1,
176 .needs_checkpoints = 1,
177 .bufs = (struct tst_buffers []) {
178 {&args, .size = sizeof(*args)},
179 {},
180 }
181 };
182