]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/kern/pdeathsig.c
sys/{x86,amd64}: remove one of doubled ;s
[FreeBSD/FreeBSD.git] / tests / sys / kern / pdeathsig.c
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
44 dummy_signal_handler(int signum)
45 {
46 }
47
48 ATF_TC_WITHOUT_HEAD(arg_validation);
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);
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);
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);
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);
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         char buffer;
233         int status;
234
235         rc = pipe(pipe_ca);
236         ATF_REQUIRE(rc == 0);
237         rc = pipe(pipe_db);
238         ATF_REQUIRE(rc == 0);
239
240         rc = fork();
241         ATF_REQUIRE(rc != -1);
242         if (rc == 0) {
243                 pid_t c_pid;
244
245                 /* process B */
246
247                 rc = fork();
248                 assert(rc >= 0);
249                 if (rc == 0) {
250                         /* process C */
251                         signum = SIGINFO;
252
253                         /* block signals so we can handle them synchronously */
254                         rc = sigfillset(&sigset);
255                         assert(rc == 0);
256                         rc = sigprocmask(SIG_SETMASK, &sigset, NULL);
257                         assert(rc == 0);
258
259                         /* register a dummy handler or the kernel will not queue it */
260                         signal(signum, dummy_signal_handler);
261
262                         /* request a signal on parent death and register a handler */
263                         rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
264                         assert(rc == 0);
265
266                         /* wait for B to die and signal us... */
267                         signum = 0xdeadbeef;
268                         rc = sigwait(&sigset, &signum);
269                         assert(rc == 0);
270                         assert(signum == SIGINFO);
271
272                         /* tell A the test passed */
273                         rc = write(pipe_ca[1], ".", 1);
274                         assert(rc == 1);
275                         _exit(0);
276                 }
277                 c_pid = rc;
278
279
280                 /* fork another process to ptrace C */
281                 rc = fork();
282                 assert(rc >= 0);
283                 if (rc == 0) {
284
285                         /* process D */
286                         rc = ptrace(PT_ATTACH, c_pid, 0, 0);
287                         assert(rc == 0);
288
289                         waitpid(c_pid, &status, 0);
290                         assert(WIFSTOPPED(status));
291                         assert(WSTOPSIG(status) == SIGSTOP);
292
293                         rc = ptrace(PT_CONTINUE, c_pid, (caddr_t) 1, 0);
294                         assert(rc == 0);
295
296                         /* tell B that we're ready for it to exit now */
297                         rc = write(pipe_db[1], ".", 1);
298                         assert(rc == 1);
299
300                         waitpid(c_pid, &status, 0);
301                         assert(WIFSTOPPED(status));
302                         assert(WSTOPSIG(status) == SIGINFO);
303
304                         rc = ptrace(PT_CONTINUE, c_pid, (caddr_t) 1,
305                                     WSTOPSIG(status));
306                         assert(rc == 0);
307
308                         ptrace(PT_DETACH, c_pid, 0, 0);
309
310                         _exit(0);
311                 }
312
313                 /* wait for D to tell us it is ready for us to exit */
314                 rc = read(pipe_db[0], &buffer, 1);
315                 assert(rc == 1);
316
317                 /* now we exit so that C gets a signal */
318                 _exit(0);
319         }
320
321         /* process A */
322
323         /* wait for C to tell us the test passed */
324         rc = read(pipe_ca[0], &buffer, 1);
325         ATF_CHECK_EQ(1, rc);
326 }
327
328 ATF_TP_ADD_TCS(tp)
329 {
330         ATF_TP_ADD_TC(tp, arg_validation);
331         ATF_TP_ADD_TC(tp, fork_no_inherit);
332         ATF_TP_ADD_TC(tp, exec_inherit);
333         ATF_TP_ADD_TC(tp, signal_delivered);
334         ATF_TP_ADD_TC(tp, signal_delivered_ptrace);
335         return (atf_no_error());
336 }