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