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 __FBSDID("$FreeBSD$");
29
30 #include <assert.h>
31 #include <atf-c.h>
32 #include <errno.h>
33 #include <signal.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include <sys/procctl.h>
39 #include <sys/ptrace.h>
40 #include <sys/signal.h>
41 #include <sys/types.h>
42
43 static void
dummy_signal_handler(int signum)44 dummy_signal_handler(int signum)
45 {
46 }
47
48 ATF_TC_WITHOUT_HEAD(arg_validation);
ATF_TC_BODY(arg_validation,tc)49 ATF_TC_BODY(arg_validation, tc)
50 {
51 int signum;
52 int rc;
53
54 /* bad signal */
55 signum = 8888;
56 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
57 ATF_CHECK_EQ(-1, rc);
58 ATF_CHECK_EQ(EINVAL, errno);
59
60 /* bad id type */
61 signum = SIGINFO;
62 rc = procctl(8888, 0, PROC_PDEATHSIG_CTL, &signum);
63 ATF_CHECK_EQ(-1, rc);
64 ATF_CHECK_EQ(EINVAL, errno);
65
66 /* bad id (pid that doesn't match mine or zero) */
67 signum = SIGINFO;
68 rc = procctl(P_PID, (((getpid() + 1) % 10) + 100),
69 PROC_PDEATHSIG_CTL, &signum);
70 ATF_CHECK_EQ(-1, rc);
71 ATF_CHECK_EQ(EINVAL, errno);
72
73 /* null pointer */
74 signum = SIGINFO;
75 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, NULL);
76 ATF_CHECK_EQ(-1, rc);
77 ATF_CHECK_EQ(EFAULT, errno);
78
79 /* good (pid == 0) */
80 signum = SIGINFO;
81 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
82 ATF_CHECK_EQ(0, rc);
83
84 /* good (pid == my pid) */
85 signum = SIGINFO;
86 rc = procctl(P_PID, getpid(), PROC_PDEATHSIG_CTL, &signum);
87 ATF_CHECK_EQ(0, rc);
88
89 /* check that we can read the signal number back */
90 signum = 0xdeadbeef;
91 rc = procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &signum);
92 ATF_CHECK_EQ(0, rc);
93 ATF_CHECK_EQ(SIGINFO, signum);
94 }
95
96 ATF_TC_WITHOUT_HEAD(fork_no_inherit);
ATF_TC_BODY(fork_no_inherit,tc)97 ATF_TC_BODY(fork_no_inherit, tc)
98 {
99 int status;
100 int signum;
101 int rc;
102
103 /* request a signal on parent death in the parent */
104 signum = SIGINFO;
105 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
106
107 rc = fork();
108 ATF_REQUIRE(rc != -1);
109 if (rc == 0) {
110 /* check that we didn't inherit the setting */
111 signum = 0xdeadbeef;
112 rc = procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &signum);
113 assert(rc == 0);
114 assert(signum == 0);
115 _exit(0);
116 }
117
118 /* wait for the child to exit successfully */
119 waitpid(rc, &status, 0);
120 ATF_CHECK_EQ(0, status);
121 }
122
123 ATF_TC_WITHOUT_HEAD(exec_inherit);
ATF_TC_BODY(exec_inherit,tc)124 ATF_TC_BODY(exec_inherit, tc)
125 {
126 int status;
127 int rc;
128
129 rc = fork();
130 ATF_REQUIRE(rc != -1);
131 if (rc == 0) {
132 char exec_path[1024];
133 int signum;
134
135 /* compute the path of the helper executable */
136 snprintf(exec_path, sizeof(exec_path), "%s/pdeathsig_helper",
137 atf_tc_get_config_var(tc, "srcdir"));
138
139 /* request a signal on parent death and register a handler */
140 signum = SIGINFO;
141 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
142 assert(rc == 0);
143
144 /* execute helper program: it asserts that it has the setting */
145 rc = execl(exec_path, exec_path, NULL);
146 assert(rc == 0);
147 _exit(0);
148 }
149
150 /* wait for the child to exit successfully */
151 waitpid(rc, &status, 0);
152 ATF_CHECK_EQ(0, status);
153 }
154
155 ATF_TC_WITHOUT_HEAD(signal_delivered);
ATF_TC_BODY(signal_delivered,tc)156 ATF_TC_BODY(signal_delivered, tc)
157 {
158 sigset_t sigset;
159 int signum;
160 int rc;
161 int pipe_ca[2];
162 int pipe_cb[2];
163 char buffer;
164
165 rc = pipe(pipe_ca);
166 ATF_REQUIRE(rc == 0);
167 rc = pipe(pipe_cb);
168 ATF_REQUIRE(rc == 0);
169
170 rc = fork();
171 ATF_REQUIRE(rc != -1);
172 if (rc == 0) {
173 rc = fork();
174 assert(rc >= 0);
175 if (rc == 0) {
176 /* process C */
177 signum = SIGINFO;
178
179 /* block signals so we can handle them synchronously */
180 rc = sigfillset(&sigset);
181 assert(rc == 0);
182 rc = sigprocmask(SIG_SETMASK, &sigset, NULL);
183 assert(rc == 0);
184
185 /* register a dummy handler or the kernel will not queue it */
186 signal(signum, dummy_signal_handler);
187
188 /* request a signal on death of our parent B */
189 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
190 assert(rc == 0);
191
192 /* tell B that we're ready for it to exit now */
193 rc = write(pipe_cb[1], ".", 1);
194 assert(rc == 1);
195
196 /* wait for B to die and signal us... */
197 signum = 0xdeadbeef;
198 rc = sigwait(&sigset, &signum);
199 assert(rc == 0);
200 assert(signum == SIGINFO);
201
202 /* tell A the test passed */
203 rc = write(pipe_ca[1], ".", 1);
204 assert(rc == 1);
205 _exit(0);
206 }
207
208 /* process B */
209
210 /* wait for C to tell us it is ready for us to exit */
211 rc = read(pipe_cb[0], &buffer, 1);
212 assert(rc == 1);
213
214 /* now we exit so that C gets a signal */
215 _exit(0);
216 }
217 /* process A */
218
219 /* wait for C to tell us the test passed */
220 rc = read(pipe_ca[0], &buffer, 1);
221 ATF_CHECK_EQ(1, rc);
222 }
223
224 ATF_TC_WITHOUT_HEAD(signal_delivered_ptrace);
ATF_TC_BODY(signal_delivered_ptrace,tc)225 ATF_TC_BODY(signal_delivered_ptrace, tc)
226 {
227 sigset_t sigset;
228 int signum;
229 int rc;
230 int pipe_ca[2];
231 int pipe_db[2];
232 int pipe_cd[2];
233 char buffer;
234 int status;
235
236 rc = pipe(pipe_ca);
237 ATF_REQUIRE(rc == 0);
238 rc = pipe(pipe_db);
239 ATF_REQUIRE(rc == 0);
240 rc = pipe(pipe_cd);
241 assert(rc == 0);
242
243 rc = fork();
244 ATF_REQUIRE(rc != -1);
245 if (rc == 0) {
246 pid_t c_pid;
247
248 /* process B */
249
250 rc = fork();
251 assert(rc >= 0);
252 if (rc == 0) {
253 /* process C */
254 signum = SIGINFO;
255
256 /* block signals so we can handle them synchronously */
257 rc = sigfillset(&sigset);
258 assert(rc == 0);
259 rc = sigprocmask(SIG_SETMASK, &sigset, NULL);
260 assert(rc == 0);
261
262 /* register a dummy handler or the kernel will not queue it */
263 signal(signum, dummy_signal_handler);
264
265 /* request a signal on parent death and register a handler */
266 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
267 assert(rc == 0);
268
269 rc = write(pipe_cd[1], "x", 1);
270 assert(rc == 1);
271
272 /* wait for B to die and signal us... */
273 signum = 0xdeadbeef;
274 rc = sigwait(&sigset, &signum);
275 assert(rc == 0);
276 assert(signum == SIGINFO);
277
278 /* tell A the test passed */
279 rc = write(pipe_ca[1], ".", 1);
280 assert(rc == 1);
281 _exit(0);
282 }
283 c_pid = rc;
284
285
286 /* fork another process to ptrace C */
287 rc = fork();
288 assert(rc >= 0);
289 if (rc == 0) {
290
291 /* process D */
292 rc = ptrace(PT_ATTACH, c_pid, 0, 0);
293 assert(rc == 0);
294
295 waitpid(c_pid, &status, 0);
296 assert(WIFSTOPPED(status));
297 assert(WSTOPSIG(status) == SIGSTOP);
298
299 rc = ptrace(PT_CONTINUE, c_pid, (caddr_t) 1, 0);
300 assert(rc == 0);
301
302 rc = read(pipe_cd[0], &buffer, 1);
303 assert(rc == 1);
304
305 /* tell B that we're ready for it to exit now */
306 rc = write(pipe_db[1], ".", 1);
307 assert(rc == 1);
308
309 waitpid(c_pid, &status, 0);
310 assert(WIFSTOPPED(status));
311 assert(WSTOPSIG(status) == SIGINFO);
312
313 rc = ptrace(PT_CONTINUE, c_pid, (caddr_t) 1,
314 WSTOPSIG(status));
315 assert(rc == 0);
316
317 waitpid(c_pid, &status, 0);
318 if (!WIFEXITED(status))
319 ptrace(PT_DETACH, c_pid, 0, 0);
320
321 _exit(0);
322 }
323
324 /* wait for D to tell us it is ready for us to exit */
325 rc = read(pipe_db[0], &buffer, 1);
326 assert(rc == 1);
327
328 /* now we exit so that C gets a signal */
329 _exit(0);
330 }
331
332 /* process A */
333
334 /* wait for C to tell us the test passed */
335 rc = read(pipe_ca[0], &buffer, 1);
336 ATF_CHECK_EQ(1, rc);
337 }
338
ATF_TP_ADD_TCS(tp)339 ATF_TP_ADD_TCS(tp)
340 {
341 ATF_TP_ADD_TC(tp, arg_validation);
342 ATF_TP_ADD_TC(tp, fork_no_inherit);
343 ATF_TP_ADD_TC(tp, exec_inherit);
344 ATF_TP_ADD_TC(tp, signal_delivered);
345 ATF_TP_ADD_TC(tp, signal_delivered_ptrace);
346 return (atf_no_error());
347 }
348