1332740Skib/*-
2332740Skib * Copyright (c) 2018 Thomas Munro
3332740Skib * All rights reserved.
4332740Skib *
5332740Skib * Redistribution and use in source and binary forms, with or without
6332740Skib * modification, are permitted provided that the following conditions
7332740Skib * are met:
8332740Skib * 1. Redistributions of source code must retain the above copyright
9332740Skib *    notice, this list of conditions and the following disclaimer.
10332740Skib * 2. Redistributions in binary form must reproduce the above copyright
11332740Skib *    notice, this list of conditions and the following disclaimer in the
12332740Skib *    documentation and/or other materials provided with the distribution.
13332740Skib *
14332740Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15332740Skib * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16332740Skib * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17332740Skib * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18332740Skib * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19332740Skib * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20332740Skib * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21332740Skib * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22332740Skib * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23332740Skib * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24332740Skib * SUCH DAMAGE.
25332740Skib */
26332740Skib
27332740Skib#include <sys/cdefs.h>
28332740Skib__FBSDID("$FreeBSD: stable/11/tests/sys/kern/pdeathsig.c 351506 2019-08-26 08:08:15Z kib $");
29332740Skib
30332740Skib#include <assert.h>
31332740Skib#include <atf-c.h>
32332740Skib#include <errno.h>
33332740Skib#include <signal.h>
34332740Skib#include <stdio.h>
35332740Skib#include <stdlib.h>
36332740Skib#include <time.h>
37332740Skib#include <unistd.h>
38332740Skib#include <sys/procctl.h>
39332740Skib#include <sys/ptrace.h>
40332740Skib#include <sys/signal.h>
41332740Skib#include <sys/types.h>
42332740Skib
43332740Skibstatic void
44332740Skibdummy_signal_handler(int signum)
45332740Skib{
46332740Skib}
47332740Skib
48332740SkibATF_TC_WITHOUT_HEAD(arg_validation);
49332740SkibATF_TC_BODY(arg_validation, tc)
50332740Skib{
51332740Skib	int signum;
52332740Skib	int rc;
53332740Skib
54332740Skib	/* bad signal */
55332740Skib	signum = 8888;
56333162Skib	rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
57332740Skib	ATF_CHECK_EQ(-1, rc);
58332740Skib	ATF_CHECK_EQ(EINVAL, errno);
59332740Skib
60332740Skib	/* bad id type */
61332740Skib	signum = SIGINFO;
62333162Skib	rc = procctl(8888, 0, PROC_PDEATHSIG_CTL, &signum);
63332740Skib	ATF_CHECK_EQ(-1, rc);
64332740Skib	ATF_CHECK_EQ(EINVAL, errno);
65332740Skib
66332740Skib	/* bad id (pid that doesn't match mine or zero) */
67332740Skib	signum = SIGINFO;
68332740Skib	rc = procctl(P_PID, (((getpid() + 1) % 10) + 100),
69333162Skib	    PROC_PDEATHSIG_CTL, &signum);
70332740Skib	ATF_CHECK_EQ(-1, rc);
71332740Skib	ATF_CHECK_EQ(EINVAL, errno);
72332740Skib
73332740Skib	/* null pointer */
74332740Skib	signum = SIGINFO;
75333162Skib	rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, NULL);
76332740Skib	ATF_CHECK_EQ(-1, rc);
77332740Skib	ATF_CHECK_EQ(EFAULT, errno);
78332740Skib
79332740Skib	/* good (pid == 0) */
80332740Skib	signum = SIGINFO;
81333162Skib	rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
82332740Skib	ATF_CHECK_EQ(0, rc);
83332740Skib
84332740Skib	/* good (pid == my pid) */
85332740Skib	signum = SIGINFO;
86333162Skib	rc = procctl(P_PID, getpid(), PROC_PDEATHSIG_CTL, &signum);
87332740Skib	ATF_CHECK_EQ(0, rc);
88332740Skib
89332740Skib	/* check that we can read the signal number back */
90332740Skib	signum = 0xdeadbeef;
91333162Skib	rc = procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &signum);
92332740Skib	ATF_CHECK_EQ(0, rc);
93332740Skib	ATF_CHECK_EQ(SIGINFO, signum);
94332740Skib}
95332740Skib
96332740SkibATF_TC_WITHOUT_HEAD(fork_no_inherit);
97332740SkibATF_TC_BODY(fork_no_inherit, tc)
98332740Skib{
99332740Skib	int status;
100332740Skib	int signum;
101332740Skib	int rc;
102332740Skib
103332740Skib	/* request a signal on parent death in the parent */
104332740Skib	signum = SIGINFO;
105333162Skib	rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
106332740Skib
107332740Skib	rc = fork();
108332740Skib	ATF_REQUIRE(rc != -1);
109332740Skib	if (rc == 0) {
110332740Skib		/* check that we didn't inherit the setting */
111332740Skib		signum = 0xdeadbeef;
112333162Skib		rc = procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &signum);
113332740Skib		assert(rc == 0);
114332740Skib		assert(signum == 0);
115332740Skib		_exit(0);
116332740Skib	}
117332740Skib
118332740Skib	/* wait for the child to exit successfully */
119332740Skib	waitpid(rc, &status, 0);
120332740Skib	ATF_CHECK_EQ(0, status);
121332740Skib}
122332740Skib
123332740SkibATF_TC_WITHOUT_HEAD(exec_inherit);
124332740SkibATF_TC_BODY(exec_inherit, tc)
125332740Skib{
126332740Skib	int status;
127332740Skib	int rc;
128332740Skib
129332740Skib	rc = fork();
130332740Skib	ATF_REQUIRE(rc != -1);
131332740Skib	if (rc == 0) {
132332740Skib		char exec_path[1024];
133332740Skib		int signum;
134332740Skib
135332740Skib		/* compute the path of the helper executable */
136332740Skib		snprintf(exec_path, sizeof(exec_path), "%s/pdeathsig_helper",
137332740Skib			 atf_tc_get_config_var(tc, "srcdir"));
138332740Skib
139332740Skib		/* request a signal on parent death and register a handler */
140332740Skib		signum = SIGINFO;
141333162Skib		rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
142332740Skib		assert(rc == 0);
143332740Skib
144332740Skib		/* execute helper program: it asserts that it has the setting */
145332740Skib		rc = execl(exec_path, exec_path, NULL);
146332740Skib		assert(rc == 0);
147332740Skib		_exit(0);
148332740Skib	}
149332740Skib
150332740Skib	/* wait for the child to exit successfully */
151332740Skib	waitpid(rc, &status, 0);
152332740Skib	ATF_CHECK_EQ(0, status);
153332740Skib}
154332740Skib
155332740SkibATF_TC_WITHOUT_HEAD(signal_delivered);
156332740SkibATF_TC_BODY(signal_delivered, tc)
157332740Skib{
158332740Skib	sigset_t sigset;
159332740Skib	int signum;
160332740Skib	int rc;
161332740Skib	int pipe_ca[2];
162332740Skib	int pipe_cb[2];
163332740Skib	char buffer;
164332740Skib
165332740Skib	rc = pipe(pipe_ca);
166332740Skib	ATF_REQUIRE(rc == 0);
167332740Skib	rc = pipe(pipe_cb);
168332740Skib	ATF_REQUIRE(rc == 0);
169332740Skib
170332740Skib	rc = fork();
171332740Skib	ATF_REQUIRE(rc != -1);
172332740Skib	if (rc == 0) {
173332740Skib		rc = fork();
174332740Skib		assert(rc >= 0);
175332740Skib		if (rc == 0) {
176332740Skib			/* process C */
177332740Skib			signum = SIGINFO;
178332740Skib
179332740Skib			/* block signals so we can handle them synchronously */
180332740Skib			rc = sigfillset(&sigset);
181332740Skib			assert(rc == 0);
182332740Skib			rc = sigprocmask(SIG_SETMASK, &sigset, NULL);
183332740Skib			assert(rc == 0);
184332740Skib
185332740Skib			/* register a dummy handler or the kernel will not queue it */
186332740Skib			signal(signum, dummy_signal_handler);
187332740Skib
188332740Skib			/* request a signal on death of our parent B */
189333162Skib			rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
190332740Skib			assert(rc == 0);
191332740Skib
192332740Skib			/* tell B that we're ready for it to exit now */
193332740Skib			rc = write(pipe_cb[1], ".", 1);
194332740Skib			assert(rc == 1);
195332740Skib
196332740Skib			/* wait for B to die and signal us... */
197332740Skib			signum = 0xdeadbeef;
198332740Skib			rc = sigwait(&sigset, &signum);
199332740Skib			assert(rc == 0);
200332740Skib			assert(signum == SIGINFO);
201332740Skib
202332740Skib			/* tell A the test passed */
203332740Skib			rc = write(pipe_ca[1], ".", 1);
204332740Skib			assert(rc == 1);
205332740Skib			_exit(0);
206332740Skib		}
207332740Skib
208332740Skib		/* process B */
209332740Skib
210332740Skib		/* wait for C to tell us it is ready for us to exit */
211332740Skib		rc = read(pipe_cb[0], &buffer, 1);
212332740Skib		assert(rc == 1);
213332740Skib
214332740Skib		/* now we exit so that C gets a signal */
215332740Skib		_exit(0);
216332740Skib	}
217332740Skib	/* process A */
218332740Skib
219332740Skib	/* wait for C to tell us the test passed */
220332740Skib	rc = read(pipe_ca[0], &buffer, 1);
221332740Skib	ATF_CHECK_EQ(1, rc);
222332740Skib}
223332740Skib
224332740SkibATF_TC_WITHOUT_HEAD(signal_delivered_ptrace);
225332740SkibATF_TC_BODY(signal_delivered_ptrace, tc)
226332740Skib{
227332740Skib	sigset_t sigset;
228332740Skib	int signum;
229332740Skib	int rc;
230332740Skib	int pipe_ca[2];
231332740Skib	int pipe_db[2];
232351506Skib	int pipe_cd[2];
233332740Skib	char buffer;
234332740Skib	int status;
235332740Skib
236332740Skib	rc = pipe(pipe_ca);
237332740Skib	ATF_REQUIRE(rc == 0);
238332740Skib	rc = pipe(pipe_db);
239332740Skib	ATF_REQUIRE(rc == 0);
240351506Skib	rc = pipe(pipe_cd);
241351506Skib	assert(rc == 0);
242332740Skib
243332740Skib	rc = fork();
244332740Skib	ATF_REQUIRE(rc != -1);
245332740Skib	if (rc == 0) {
246332740Skib		pid_t c_pid;
247332740Skib
248332740Skib		/* process B */
249332740Skib
250332740Skib		rc = fork();
251332740Skib		assert(rc >= 0);
252332740Skib		if (rc == 0) {
253332740Skib			/* process C */
254332740Skib			signum = SIGINFO;
255332740Skib
256332740Skib			/* block signals so we can handle them synchronously */
257332740Skib			rc = sigfillset(&sigset);
258332740Skib			assert(rc == 0);
259332740Skib			rc = sigprocmask(SIG_SETMASK, &sigset, NULL);
260332740Skib			assert(rc == 0);
261332740Skib
262332740Skib			/* register a dummy handler or the kernel will not queue it */
263332740Skib			signal(signum, dummy_signal_handler);
264332740Skib
265332740Skib			/* request a signal on parent death and register a handler */
266333162Skib			rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
267332740Skib			assert(rc == 0);
268332740Skib
269351506Skib			rc = write(pipe_cd[1], "x", 1);
270351506Skib			assert(rc == 1);
271351506Skib
272332740Skib			/* wait for B to die and signal us... */
273332740Skib			signum = 0xdeadbeef;
274332740Skib			rc = sigwait(&sigset, &signum);
275332740Skib			assert(rc == 0);
276332740Skib			assert(signum == SIGINFO);
277332740Skib
278332740Skib			/* tell A the test passed */
279332740Skib			rc = write(pipe_ca[1], ".", 1);
280332740Skib			assert(rc == 1);
281332740Skib			_exit(0);
282332740Skib		}
283332740Skib		c_pid = rc;
284332740Skib
285332740Skib
286332740Skib		/* fork another process to ptrace C */
287332740Skib		rc = fork();
288332740Skib		assert(rc >= 0);
289332740Skib		if (rc == 0) {
290332740Skib
291332740Skib			/* process D */
292332740Skib			rc = ptrace(PT_ATTACH, c_pid, 0, 0);
293332740Skib			assert(rc == 0);
294332740Skib
295332740Skib			waitpid(c_pid, &status, 0);
296332740Skib			assert(WIFSTOPPED(status));
297332740Skib			assert(WSTOPSIG(status) == SIGSTOP);
298332740Skib
299332740Skib			rc = ptrace(PT_CONTINUE, c_pid, (caddr_t) 1, 0);
300332740Skib			assert(rc == 0);
301332740Skib
302351506Skib			rc = read(pipe_cd[0], &buffer, 1);
303351506Skib			assert(rc == 1);
304351506Skib
305332740Skib			/* tell B that we're ready for it to exit now */
306332740Skib			rc = write(pipe_db[1], ".", 1);
307332740Skib			assert(rc == 1);
308332740Skib
309332740Skib			waitpid(c_pid, &status, 0);
310332740Skib			assert(WIFSTOPPED(status));
311332740Skib			assert(WSTOPSIG(status) == SIGINFO);
312332740Skib
313332740Skib			rc = ptrace(PT_CONTINUE, c_pid, (caddr_t) 1,
314332740Skib				    WSTOPSIG(status));
315332740Skib			assert(rc == 0);
316332740Skib
317351505Skib			waitpid(c_pid, &status, 0);
318351505Skib			if (!WIFEXITED(status))
319351505Skib				ptrace(PT_DETACH, c_pid, 0, 0);
320332740Skib
321332740Skib			_exit(0);
322332740Skib		}
323332740Skib
324332740Skib		/* wait for D to tell us it is ready for us to exit */
325332740Skib		rc = read(pipe_db[0], &buffer, 1);
326332740Skib		assert(rc == 1);
327332740Skib
328332740Skib		/* now we exit so that C gets a signal */
329332740Skib		_exit(0);
330332740Skib	}
331332740Skib
332332740Skib	/* process A */
333332740Skib
334332740Skib	/* wait for C to tell us the test passed */
335332740Skib	rc = read(pipe_ca[0], &buffer, 1);
336332740Skib	ATF_CHECK_EQ(1, rc);
337332740Skib}
338332740Skib
339332740SkibATF_TP_ADD_TCS(tp)
340332740Skib{
341332740Skib	ATF_TP_ADD_TC(tp, arg_validation);
342332740Skib	ATF_TP_ADD_TC(tp, fork_no_inherit);
343332740Skib	ATF_TP_ADD_TC(tp, exec_inherit);
344332740Skib	ATF_TP_ADD_TC(tp, signal_delivered);
345332740Skib	ATF_TP_ADD_TC(tp, signal_delivered_ptrace);
346332740Skib	return (atf_no_error());
347332740Skib}
348