Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/kern/pdeathsig.c
39483 views
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
347