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