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