xref: /freebsd/tests/sys/kern/pdeathsig.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
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
42 dummy_signal_handler(int signum)
43 {
44 }
45 
46 ATF_TC_WITHOUT_HEAD(arg_validation);
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);
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);
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);
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);
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 
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