1 /*-
2 * Copyright (c) 2018 Thomas Munro
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 #include <assert.h>
29 #include <atf-c.h>
30 #include <errno.h>
31 #include <signal.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <time.h>
35 #include <unistd.h>
36 #include <sys/procctl.h>
37 #include <sys/ptrace.h>
38 #include <sys/signal.h>
39 #include <sys/types.h>
40
41 static void
dummy_signal_handler(int signum)42 dummy_signal_handler(int signum)
43 {
44 }
45
46 ATF_TC_WITHOUT_HEAD(arg_validation);
ATF_TC_BODY(arg_validation,tc)47 ATF_TC_BODY(arg_validation, tc)
48 {
49 int signum;
50 int rc;
51
52 /* bad signal */
53 signum = 8888;
54 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
55 ATF_CHECK_EQ(-1, rc);
56 ATF_CHECK_EQ(EINVAL, errno);
57
58 /* bad id type */
59 signum = SIGINFO;
60 rc = procctl(8888, 0, PROC_PDEATHSIG_CTL, &signum);
61 ATF_CHECK_EQ(-1, rc);
62 ATF_CHECK_EQ(EINVAL, errno);
63
64 /* bad id (pid that doesn't match mine or zero) */
65 signum = SIGINFO;
66 rc = procctl(P_PID, (((getpid() + 1) % 10) + 100),
67 PROC_PDEATHSIG_CTL, &signum);
68 ATF_CHECK_EQ(-1, rc);
69 ATF_CHECK_EQ(EINVAL, errno);
70
71 /* null pointer */
72 signum = SIGINFO;
73 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, NULL);
74 ATF_CHECK_EQ(-1, rc);
75 ATF_CHECK_EQ(EFAULT, errno);
76
77 /* good (pid == 0) */
78 signum = SIGINFO;
79 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
80 ATF_CHECK_EQ(0, rc);
81
82 /* good (pid == my pid) */
83 signum = SIGINFO;
84 rc = procctl(P_PID, getpid(), PROC_PDEATHSIG_CTL, &signum);
85 ATF_CHECK_EQ(0, rc);
86
87 /* check that we can read the signal number back */
88 signum = 0xdeadbeef;
89 rc = procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &signum);
90 ATF_CHECK_EQ(0, rc);
91 ATF_CHECK_EQ(SIGINFO, signum);
92 }
93
94 ATF_TC_WITHOUT_HEAD(fork_no_inherit);
ATF_TC_BODY(fork_no_inherit,tc)95 ATF_TC_BODY(fork_no_inherit, tc)
96 {
97 int status;
98 int signum;
99 int rc;
100
101 /* request a signal on parent death in the parent */
102 signum = SIGINFO;
103 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
104
105 rc = fork();
106 ATF_REQUIRE(rc != -1);
107 if (rc == 0) {
108 /* check that we didn't inherit the setting */
109 signum = 0xdeadbeef;
110 rc = procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &signum);
111 assert(rc == 0);
112 assert(signum == 0);
113 _exit(0);
114 }
115
116 /* wait for the child to exit successfully */
117 waitpid(rc, &status, 0);
118 ATF_CHECK_EQ(0, status);
119 }
120
121 ATF_TC_WITHOUT_HEAD(exec_inherit);
ATF_TC_BODY(exec_inherit,tc)122 ATF_TC_BODY(exec_inherit, tc)
123 {
124 int status;
125 int rc;
126
127 rc = fork();
128 ATF_REQUIRE(rc != -1);
129 if (rc == 0) {
130 char exec_path[1024];
131 int signum;
132
133 /* compute the path of the helper executable */
134 snprintf(exec_path, sizeof(exec_path), "%s/pdeathsig_helper",
135 atf_tc_get_config_var(tc, "srcdir"));
136
137 /* request a signal on parent death and register a handler */
138 signum = SIGINFO;
139 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
140 assert(rc == 0);
141
142 /* execute helper program: it asserts that it has the setting */
143 rc = execl(exec_path, exec_path, NULL);
144 assert(rc == 0);
145 _exit(0);
146 }
147
148 /* wait for the child to exit successfully */
149 waitpid(rc, &status, 0);
150 ATF_CHECK_EQ(0, status);
151 }
152
153 ATF_TC_WITHOUT_HEAD(signal_delivered);
ATF_TC_BODY(signal_delivered,tc)154 ATF_TC_BODY(signal_delivered, tc)
155 {
156 sigset_t sigset;
157 int signum;
158 int rc;
159 int pipe_ca[2];
160 int pipe_cb[2];
161 char buffer;
162
163 rc = pipe(pipe_ca);
164 ATF_REQUIRE(rc == 0);
165 rc = pipe(pipe_cb);
166 ATF_REQUIRE(rc == 0);
167
168 rc = fork();
169 ATF_REQUIRE(rc != -1);
170 if (rc == 0) {
171 rc = fork();
172 assert(rc >= 0);
173 if (rc == 0) {
174 /* process C */
175 signum = SIGINFO;
176
177 /* block signals so we can handle them synchronously */
178 rc = sigfillset(&sigset);
179 assert(rc == 0);
180 rc = sigprocmask(SIG_SETMASK, &sigset, NULL);
181 assert(rc == 0);
182
183 /* register a dummy handler or the kernel will not queue it */
184 signal(signum, dummy_signal_handler);
185
186 /* request a signal on death of our parent B */
187 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
188 assert(rc == 0);
189
190 /* tell B that we're ready for it to exit now */
191 rc = write(pipe_cb[1], ".", 1);
192 assert(rc == 1);
193
194 /* wait for B to die and signal us... */
195 signum = 0xdeadbeef;
196 rc = sigwait(&sigset, &signum);
197 assert(rc == 0);
198 assert(signum == SIGINFO);
199
200 /* tell A the test passed */
201 rc = write(pipe_ca[1], ".", 1);
202 assert(rc == 1);
203 _exit(0);
204 }
205
206 /* process B */
207
208 /* wait for C to tell us it is ready for us to exit */
209 rc = read(pipe_cb[0], &buffer, 1);
210 assert(rc == 1);
211
212 /* now we exit so that C gets a signal */
213 _exit(0);
214 }
215 /* process A */
216
217 /* wait for C to tell us the test passed */
218 rc = read(pipe_ca[0], &buffer, 1);
219 ATF_CHECK_EQ(1, rc);
220 }
221
222 ATF_TC_WITHOUT_HEAD(signal_delivered_ptrace);
ATF_TC_BODY(signal_delivered_ptrace,tc)223 ATF_TC_BODY(signal_delivered_ptrace, tc)
224 {
225 sigset_t sigset;
226 int signum;
227 int rc;
228 int pipe_ca[2];
229 int pipe_db[2];
230 int pipe_cd[2];
231 char buffer;
232 int status;
233
234 rc = pipe(pipe_ca);
235 ATF_REQUIRE(rc == 0);
236 rc = pipe(pipe_db);
237 ATF_REQUIRE(rc == 0);
238 rc = pipe(pipe_cd);
239 assert(rc == 0);
240
241 rc = fork();
242 ATF_REQUIRE(rc != -1);
243 if (rc == 0) {
244 pid_t c_pid;
245
246 /* process B */
247
248 rc = fork();
249 assert(rc >= 0);
250 if (rc == 0) {
251 /* process C */
252 signum = SIGINFO;
253
254 /* block signals so we can handle them synchronously */
255 rc = sigfillset(&sigset);
256 assert(rc == 0);
257 rc = sigprocmask(SIG_SETMASK, &sigset, NULL);
258 assert(rc == 0);
259
260 /* register a dummy handler or the kernel will not queue it */
261 signal(signum, dummy_signal_handler);
262
263 /* request a signal on parent death and register a handler */
264 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
265 assert(rc == 0);
266
267 rc = write(pipe_cd[1], "x", 1);
268 assert(rc == 1);
269
270 /* wait for B to die and signal us... */
271 signum = 0xdeadbeef;
272 rc = sigwait(&sigset, &signum);
273 assert(rc == 0);
274 assert(signum == SIGINFO);
275
276 /* tell A the test passed */
277 rc = write(pipe_ca[1], ".", 1);
278 assert(rc == 1);
279 _exit(0);
280 }
281 c_pid = rc;
282
283
284 /* fork another process to ptrace C */
285 rc = fork();
286 assert(rc >= 0);
287 if (rc == 0) {
288
289 /* process D */
290 rc = ptrace(PT_ATTACH, c_pid, 0, 0);
291 assert(rc == 0);
292
293 waitpid(c_pid, &status, 0);
294 assert(WIFSTOPPED(status));
295 assert(WSTOPSIG(status) == SIGSTOP);
296
297 rc = ptrace(PT_CONTINUE, c_pid, (caddr_t) 1, 0);
298 assert(rc == 0);
299
300 rc = read(pipe_cd[0], &buffer, 1);
301 assert(rc == 1);
302
303 /* tell B that we're ready for it to exit now */
304 rc = write(pipe_db[1], ".", 1);
305 assert(rc == 1);
306
307 waitpid(c_pid, &status, 0);
308 assert(WIFSTOPPED(status));
309 assert(WSTOPSIG(status) == SIGINFO);
310
311 rc = ptrace(PT_CONTINUE, c_pid, (caddr_t) 1,
312 WSTOPSIG(status));
313 assert(rc == 0);
314
315 waitpid(c_pid, &status, 0);
316 if (!WIFEXITED(status))
317 ptrace(PT_DETACH, c_pid, 0, 0);
318
319 _exit(0);
320 }
321
322 /* wait for D to tell us it is ready for us to exit */
323 rc = read(pipe_db[0], &buffer, 1);
324 assert(rc == 1);
325
326 /* now we exit so that C gets a signal */
327 _exit(0);
328 }
329
330 /* process A */
331
332 /* wait for C to tell us the test passed */
333 rc = read(pipe_ca[0], &buffer, 1);
334 ATF_CHECK_EQ(1, rc);
335 }
336
ATF_TP_ADD_TCS(tp)337 ATF_TP_ADD_TCS(tp)
338 {
339 ATF_TP_ADD_TC(tp, arg_validation);
340 ATF_TP_ADD_TC(tp, fork_no_inherit);
341 ATF_TP_ADD_TC(tp, exec_inherit);
342 ATF_TP_ADD_TC(tp, signal_delivered);
343 ATF_TP_ADD_TC(tp, signal_delivered_ptrace);
344 return (atf_no_error());
345 }
346