xref: /freebsd/tests/sys/kern/ptrace_test.c (revision 6c5bc49c5a803101b52861068594eacf6775e08c)
1 /*-
2  * Copyright (c) 2015 John Baldwin <jhb@FreeBSD.org>
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 <sys/types.h>
31 #include <sys/ptrace.h>
32 #include <sys/sysctl.h>
33 #include <sys/user.h>
34 #include <sys/wait.h>
35 #include <errno.h>
36 #include <signal.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <atf-c.h>
40 
41 /*
42  * Verify that a parent debugger process "sees" the exit of a debugged
43  * process exactly once when attached via PT_TRACE_ME.
44  */
45 ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_trace_me);
46 ATF_TC_BODY(ptrace__parent_wait_after_trace_me, tc)
47 {
48 	pid_t child, wpid;
49 	int status;
50 
51 	ATF_REQUIRE((child = fork()) != -1);
52 	if (child == 0) {
53 		/* Child process. */
54 		ATF_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
55 
56 		/* Trigger a stop. */
57 		raise(SIGSTOP);
58 
59 		exit(1);
60 	}
61 
62 	/* Parent process. */
63 
64 	/* The first wait() should report the stop from SIGSTOP. */
65 	wpid = waitpid(child, &status, 0);
66 	ATF_REQUIRE(wpid == child);
67 	ATF_REQUIRE(WIFSTOPPED(status));
68 	ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
69 
70 	/* Continue the child ignoring the SIGSTOP. */
71 	ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
72 
73 	/* The second wait() should report the exit status. */
74 	wpid = waitpid(child, &status, 0);
75 	ATF_REQUIRE(wpid == child);
76 	ATF_REQUIRE(WIFEXITED(status));
77 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
78 
79 	/* The child should no longer exist. */
80 	wpid = waitpid(child, &status, 0);
81 	ATF_REQUIRE(wpid == -1);
82 	ATF_REQUIRE(errno == ECHILD);
83 }
84 
85 /*
86  * Verify that a parent debugger process "sees" the exit of a debugged
87  * process exactly once when attached via PT_ATTACH.
88  */
89 ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_attach);
90 ATF_TC_BODY(ptrace__parent_wait_after_attach, tc)
91 {
92 	pid_t child, wpid;
93 	int cpipe[2], status;
94 	char c;
95 
96 	ATF_REQUIRE(pipe(cpipe) == 0);
97 	ATF_REQUIRE((child = fork()) != -1);
98 	if (child == 0) {
99 		/* Child process. */
100 		close(cpipe[0]);
101 
102 		/* Wait for the parent to attach. */
103 		ATF_REQUIRE(read(cpipe[1], &c, sizeof(c)) == 0);
104 
105 		exit(1);
106 	}
107 	close(cpipe[1]);
108 
109 	/* Parent process. */
110 
111 	/* Attach to the child process. */
112 	ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) == 0);
113 
114 	/* The first wait() should report the SIGSTOP from PT_ATTACH. */
115 	wpid = waitpid(child, &status, 0);
116 	ATF_REQUIRE(wpid == child);
117 	ATF_REQUIRE(WIFSTOPPED(status));
118 	ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
119 
120 	/* Continue the child ignoring the SIGSTOP. */
121 	ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
122 
123 	/* Signal the child to exit. */
124 	close(cpipe[0]);
125 
126 	/* The second wait() should report the exit status. */
127 	wpid = waitpid(child, &status, 0);
128 	ATF_REQUIRE(wpid == child);
129 	ATF_REQUIRE(WIFEXITED(status));
130 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
131 
132 	/* The child should no longer exist. */
133 	wpid = waitpid(child, &status, 0);
134 	ATF_REQUIRE(wpid == -1);
135 	ATF_REQUIRE(errno == ECHILD);
136 }
137 
138 /*
139  * Verify that a parent process "sees" the exit of a debugged process only
140  * after the debugger has seen it.
141  */
142 ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_child_debugger);
143 ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc)
144 {
145 	pid_t child, debugger, wpid;
146 	int cpipe[2], dpipe[2], status;
147 	char c;
148 
149 	ATF_REQUIRE(pipe(cpipe) == 0);
150 	ATF_REQUIRE((child = fork()) != -1);
151 
152 	if (child == 0) {
153 		/* Child process. */
154 		close(cpipe[0]);
155 
156 		/* Wait for parent to be ready. */
157 		ATF_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c));
158 
159 		exit(1);
160 	}
161 	close(cpipe[1]);
162 
163 	ATF_REQUIRE(pipe(dpipe) == 0);
164 	ATF_REQUIRE((debugger = fork()) != -1);
165 
166 	if (debugger == 0) {
167 		/* Debugger process. */
168 		close(dpipe[0]);
169 
170 		ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
171 
172 		wpid = waitpid(child, &status, 0);
173 		ATF_REQUIRE(wpid == child);
174 		ATF_REQUIRE(WIFSTOPPED(status));
175 		ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
176 
177 		ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
178 
179 		/* Signal parent that debugger is attached. */
180 		ATF_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c));
181 
182 		/* Wait for parent's failed wait. */
183 		ATF_REQUIRE(read(dpipe[1], &c, sizeof(c)) == 0);
184 
185 		wpid = waitpid(child, &status, 0);
186 		ATF_REQUIRE(wpid == child);
187 		ATF_REQUIRE(WIFEXITED(status));
188 		ATF_REQUIRE(WEXITSTATUS(status) == 1);
189 
190 		exit(0);
191 	}
192 	close(dpipe[1]);
193 
194 	/* Parent process. */
195 
196 	/* Wait for the debugger to attach to the child. */
197 	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c));
198 
199 	/* Release the child. */
200 	ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c));
201 	ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0);
202 	close(cpipe[0]);
203 
204 	/*
205 	 * Wait for the child to exit.  This is kind of gross, but
206 	 * there is not a better way.
207 	 */
208 	for (;;) {
209 		struct kinfo_proc kp;
210 		size_t len;
211 		int mib[4];
212 
213 		mib[0] = CTL_KERN;
214 		mib[1] = KERN_PROC;
215 		mib[2] = KERN_PROC_PID;
216 		mib[3] = child;
217 		len = sizeof(kp);
218 		if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) {
219 			/* The KERN_PROC_PID sysctl fails for zombies. */
220 			ATF_REQUIRE(errno == ESRCH);
221 			break;
222 		}
223 		usleep(5000);
224 	}
225 
226 	/*
227 	 * This wait should return a pid of 0 to indicate no status to
228 	 * report.  The parent should see the child as non-exited
229 	 * until the debugger sees the exit.
230 	 */
231 	wpid = waitpid(child, &status, WNOHANG);
232 	ATF_REQUIRE(wpid == 0);
233 
234 	/* Signal the debugger to wait for the child. */
235 	close(dpipe[0]);
236 
237 	/* Wait for the debugger. */
238 	wpid = waitpid(debugger, &status, 0);
239 	ATF_REQUIRE(wpid == debugger);
240 	ATF_REQUIRE(WIFEXITED(status));
241 	ATF_REQUIRE(WEXITSTATUS(status) == 0);
242 
243 	/* The child process should now be ready. */
244 	wpid = waitpid(child, &status, WNOHANG);
245 	ATF_REQUIRE(wpid == child);
246 	ATF_REQUIRE(WIFEXITED(status));
247 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
248 }
249 
250 /*
251  * Verify that a parent process "sees" the exit of a debugged process
252  * only after a non-direct-child debugger has seen it.  In particular,
253  * various wait() calls in the parent must avoid failing with ESRCH by
254  * checking the parent's orphan list for the debugee.
255  */
256 ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_unrelated_debugger);
257 ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc)
258 {
259 	pid_t child, debugger, fpid, wpid;
260 	int cpipe[2], dpipe[2], status;
261 	char c;
262 
263 	ATF_REQUIRE(pipe(cpipe) == 0);
264 	ATF_REQUIRE((child = fork()) != -1);
265 
266 	if (child == 0) {
267 		/* Child process. */
268 		close(cpipe[0]);
269 
270 		/* Wait for parent to be ready. */
271 		ATF_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c));
272 
273 		exit(1);
274 	}
275 	close(cpipe[1]);
276 
277 	ATF_REQUIRE(pipe(dpipe) == 0);
278 	ATF_REQUIRE((debugger = fork()) != -1);
279 
280 	if (debugger == 0) {
281 		/* Debugger parent. */
282 
283 		/*
284 		 * Fork again and drop the debugger parent so that the
285 		 * debugger is not a child of the main parent.
286 		 */
287 		ATF_REQUIRE((fpid = fork()) != -1);
288 		if (fpid != 0)
289 			exit(2);
290 
291 		/* Debugger process. */
292 		close(dpipe[0]);
293 
294 		ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
295 
296 		wpid = waitpid(child, &status, 0);
297 		ATF_REQUIRE(wpid == child);
298 		ATF_REQUIRE(WIFSTOPPED(status));
299 		ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
300 
301 		ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
302 
303 		/* Signal parent that debugger is attached. */
304 		ATF_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c));
305 
306 		/* Wait for parent's failed wait. */
307 		ATF_REQUIRE(read(dpipe[1], &c, sizeof(c)) == 0);
308 
309 		wpid = waitpid(child, &status, 0);
310 		ATF_REQUIRE(wpid == child);
311 		ATF_REQUIRE(WIFEXITED(status));
312 		ATF_REQUIRE(WEXITSTATUS(status) == 1);
313 
314 		exit(0);
315 	}
316 
317 	/* Parent process. */
318 
319 	/* Wait for the debugger parent process to exit. */
320 	wpid = waitpid(debugger, &status, 0);
321 	ATF_REQUIRE(wpid == debugger);
322 	ATF_REQUIRE(WIFEXITED(status));
323 	ATF_REQUIRE(WEXITSTATUS(status) == 2);
324 
325 	/* A WNOHANG wait here should see the non-exited child. */
326 	wpid = waitpid(child, &status, WNOHANG);
327 	ATF_REQUIRE(wpid == 0);
328 
329 	/* Wait for the debugger to attach to the child. */
330 	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c));
331 
332 	/* Release the child. */
333 	ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c));
334 	ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0);
335 	close(cpipe[0]);
336 
337 	/*
338 	 * Wait for the child to exit.  This is kind of gross, but
339 	 * there is not a better way.
340 	 */
341 	for (;;) {
342 		struct kinfo_proc kp;
343 		size_t len;
344 		int mib[4];
345 
346 		mib[0] = CTL_KERN;
347 		mib[1] = KERN_PROC;
348 		mib[2] = KERN_PROC_PID;
349 		mib[3] = child;
350 		len = sizeof(kp);
351 		if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) {
352 			/* The KERN_PROC_PID sysctl fails for zombies. */
353 			ATF_REQUIRE(errno == ESRCH);
354 			break;
355 		}
356 		usleep(5000);
357 	}
358 
359 	/*
360 	 * This wait should return a pid of 0 to indicate no status to
361 	 * report.  The parent should see the child as non-exited
362 	 * until the debugger sees the exit.
363 	 */
364 	wpid = waitpid(child, &status, WNOHANG);
365 	ATF_REQUIRE(wpid == 0);
366 
367 	/* Signal the debugger to wait for the child. */
368 	close(dpipe[0]);
369 
370 	/* Wait for the debugger. */
371 	ATF_REQUIRE(read(dpipe[1], &c, sizeof(c)) == 0);
372 
373 	/* The child process should now be ready. */
374 	wpid = waitpid(child, &status, WNOHANG);
375 	ATF_REQUIRE(wpid == child);
376 	ATF_REQUIRE(WIFEXITED(status));
377 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
378 }
379 
380 ATF_TP_ADD_TCS(tp)
381 {
382 
383 	ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me);
384 	ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach);
385 	ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_child_debugger);
386 	ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_unrelated_debugger);
387 
388 	return (atf_no_error());
389 }
390