1/*	$OpenBSD: ptrace_test.c,v 1.4 2021/12/13 16:56:50 deraadt Exp $ */
2
3/*-
4 * Copyright (c) 2015 John Baldwin <jhb@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include "macros.h"
29
30#include <sys/types.h>
31#include <sys/event.h>
32#include <sys/file.h>
33#include <sys/time.h>
34#include <sys/signal.h>
35#include <sys/proc.h>
36#include <sys/ptrace.h>
37#include <sys/queue.h>
38#include <sys/syscall.h>
39#include <sys/sysctl.h>
40#include <sys/user.h>
41#include <sys/wait.h>
42#include <errno.h>
43#include <pthread.h>
44#include <sched.h>
45#include <semaphore.h>
46#include <signal.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <unistd.h>
50#include "atf-c.h"
51
52#define nitems(_a)     (sizeof((_a)) / sizeof((_a)[0]))
53
54/*
55 * A variant of ATF_REQUIRE that is suitable for use in child
56 * processes.  This only works if the parent process is tripped up by
57 * the early exit and fails some requirement itself.
58 */
59#define	CHILD_REQUIRE(exp) do {						\
60		if (!(exp))						\
61			child_fail_require(__FILE__, __LINE__,		\
62			    #exp " not met");				\
63	} while (0)
64
65static __dead2 void
66child_fail_require(const char *file, int line, const char *str)
67{
68	char buf[128];
69
70	snprintf(buf, sizeof(buf), "%s:%d: %s\n", file, line, str);
71	write(2, buf, strlen(buf));
72	_exit(32);
73}
74
75static void
76trace_me(void)
77{
78
79	/* Attach the parent process as a tracer of this process. */
80	CHILD_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
81
82	/* Trigger a stop. */
83	raise(SIGSTOP);
84}
85
86static void
87attach_child(pid_t pid)
88{
89	pid_t wpid;
90	int status;
91
92	ATF_REQUIRE(ptrace(PT_ATTACH, pid, NULL, 0) == 0);
93
94	wpid = waitpid(pid, &status, 0);
95	ATF_REQUIRE(wpid == pid);
96	ATF_REQUIRE(WIFSTOPPED(status));
97	ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
98}
99
100static void
101wait_for_zombie(pid_t pid)
102{
103
104	/*
105	 * Wait for a process to exit.  This is kind of gross, but
106	 * there is not a better way.
107	 *
108	 * Prior to r325719, the kern.proc.pid.<pid> sysctl failed
109	 * with ESRCH.  After that change, a valid struct kinfo_proc
110	 * is returned for zombies with ki_stat set to SZOMB.
111	 */
112	for (;;) {
113		struct kinfo_proc kp;
114		size_t len;
115		int mib[6];
116
117		mib[0] = CTL_KERN;
118		mib[1] = KERN_PROC;
119		mib[2] = KERN_PROC_PID;
120		mib[3] = pid;
121		mib[4] = len = sizeof(kp);
122		mib[5] = 1;
123		if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) {
124			ATF_REQUIRE(errno == ESRCH);
125			break;
126		}
127		if (kp.p_stat == SDEAD)
128			break;
129		usleep(5000);
130	}
131}
132
133/*
134 * Verify that a parent debugger process "sees" the exit of a debugged
135 * process exactly once when attached via PT_TRACE_ME.
136 */
137ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_trace_me);
138ATF_TC_BODY(ptrace__parent_wait_after_trace_me, tc)
139{
140	pid_t child, wpid;
141	int status;
142
143	ATF_REQUIRE((child = fork()) != -1);
144	if (child == 0) {
145		/* Child process. */
146		trace_me();
147
148		_exit(1);
149	}
150
151	/* Parent process. */
152
153	/* The first wait() should report the stop from SIGSTOP. */
154	wpid = waitpid(child, &status, 0);
155	printf("first %d\n", wpid);
156	ATF_REQUIRE(wpid == child);
157	ATF_REQUIRE(WIFSTOPPED(status));
158	ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
159
160	/* Continue the child ignoring the SIGSTOP. */
161	ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
162
163	/* The second wait() should report the exit status. */
164	wpid = waitpid(child, &status, 0);
165	printf("second %d\n", wpid);
166	ATF_REQUIRE(wpid == child);
167	ATF_REQUIRE(WIFEXITED(status));
168	ATF_REQUIRE(WEXITSTATUS(status) == 1);
169
170	/* The child should no longer exist. */
171	wpid = waitpid(child, &status, 0);
172	printf("third %d\n", wpid);
173	ATF_REQUIRE(wpid == -1);
174	ATF_REQUIRE(errno == ECHILD);
175}
176
177/*
178 * Verify that a parent debugger process "sees" the exit of a debugged
179 * process exactly once when attached via PT_ATTACH.
180 */
181ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_attach);
182ATF_TC_BODY(ptrace__parent_wait_after_attach, tc)
183{
184	pid_t child, wpid;
185	int cpipe[2], status;
186	char c;
187
188	ATF_REQUIRE(pipe(cpipe) == 0);
189	ATF_REQUIRE((child = fork()) != -1);
190	if (child == 0) {
191		/* Child process. */
192		close(cpipe[0]);
193
194		/* Wait for the parent to attach. */
195		CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == 0);
196
197		_exit(1);
198	}
199	close(cpipe[1]);
200
201	/* Parent process. */
202
203	/* Attach to the child process. */
204	attach_child(child);
205
206	/* Continue the child ignoring the SIGSTOP. */
207	ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
208
209	/* Signal the child to exit. */
210	close(cpipe[0]);
211
212	/* The second wait() should report the exit status. */
213	wpid = waitpid(child, &status, 0);
214	ATF_REQUIRE(wpid == child);
215	ATF_REQUIRE(WIFEXITED(status));
216	ATF_REQUIRE(WEXITSTATUS(status) == 1);
217
218	/* The child should no longer exist. */
219	wpid = waitpid(child, &status, 0);
220	ATF_REQUIRE(wpid == -1);
221	ATF_REQUIRE(errno == ECHILD);
222}
223
224/*
225 * Verify that a parent process "sees" the exit of a debugged process only
226 * after the debugger has seen it.
227 */
228ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_child_debugger);
229ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc)
230{
231	pid_t child, debugger, wpid;
232	int cpipe[2], dpipe[2], status;
233	char c;
234
235	if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false))
236		atf_tc_skip("https://bugs.freebsd.org/239399");
237
238	ATF_REQUIRE(pipe(cpipe) == 0);
239	ATF_REQUIRE((child = fork()) != -1);
240
241	if (child == 0) {
242		/* Child process. */
243		close(cpipe[0]);
244
245		/* Wait for parent to be ready. */
246		CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c));
247
248		_exit(1);
249	}
250	close(cpipe[1]);
251
252	ATF_REQUIRE(pipe(dpipe) == 0);
253	ATF_REQUIRE((debugger = fork()) != -1);
254
255	if (debugger == 0) {
256		/* Debugger process. */
257		close(dpipe[0]);
258
259		CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
260
261		wpid = waitpid(child, &status, 0);
262		CHILD_REQUIRE(wpid == child);
263		CHILD_REQUIRE(WIFSTOPPED(status));
264		CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP);
265
266		CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
267
268		/* Signal parent that debugger is attached. */
269		CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c));
270
271		/* Wait for parent's failed wait. */
272		CHILD_REQUIRE(read(dpipe[1], &c, sizeof(c)) == 0);
273
274		wpid = waitpid(child, &status, 0);
275		CHILD_REQUIRE(wpid == child);
276		CHILD_REQUIRE(WIFEXITED(status));
277		CHILD_REQUIRE(WEXITSTATUS(status) == 1);
278
279		_exit(0);
280	}
281	close(dpipe[1]);
282
283	/* Parent process. */
284
285	/* Wait for the debugger to attach to the child. */
286	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c));
287
288	/* Release the child. */
289	ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c));
290	ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0);
291	close(cpipe[0]);
292
293	wait_for_zombie(child);
294
295	/*
296	 * This wait should return a pid of 0 to indicate no status to
297	 * report.  The parent should see the child as non-exited
298	 * until the debugger sees the exit.
299	 */
300	wpid = waitpid(child, &status, WNOHANG);
301	ATF_REQUIRE(wpid == 0);
302
303	/* Signal the debugger to wait for the child. */
304	close(dpipe[0]);
305
306	/* Wait for the debugger. */
307	wpid = waitpid(debugger, &status, 0);
308	ATF_REQUIRE(wpid == debugger);
309	ATF_REQUIRE(WIFEXITED(status));
310	ATF_REQUIRE(WEXITSTATUS(status) == 0);
311
312	/* The child process should now be ready. */
313	wpid = waitpid(child, &status, WNOHANG);
314	ATF_REQUIRE(wpid == child);
315	ATF_REQUIRE(WIFEXITED(status));
316	ATF_REQUIRE(WEXITSTATUS(status) == 1);
317}
318
319/*
320 * Verify that a parent process "sees" the exit of a debugged process
321 * only after a non-direct-child debugger has seen it.  In particular,
322 * various wait() calls in the parent must avoid failing with ESRCH by
323 * checking the parent's orphan list for the debugee.
324 */
325ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_unrelated_debugger);
326ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc)
327{
328	pid_t child, debugger, fpid, wpid;
329	int cpipe[2], dpipe[2], status;
330	char c;
331
332	ATF_REQUIRE(pipe(cpipe) == 0);
333	ATF_REQUIRE((child = fork()) != -1);
334
335	if (child == 0) {
336		/* Child process. */
337		close(cpipe[0]);
338
339		/* Wait for parent to be ready. */
340		CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c));
341
342		_exit(1);
343	}
344	close(cpipe[1]);
345
346	ATF_REQUIRE(pipe(dpipe) == 0);
347	ATF_REQUIRE((debugger = fork()) != -1);
348
349	if (debugger == 0) {
350		/* Debugger parent. */
351
352		/*
353		 * Fork again and drop the debugger parent so that the
354		 * debugger is not a child of the main parent.
355		 */
356		CHILD_REQUIRE((fpid = fork()) != -1);
357		if (fpid != 0)
358			_exit(2);
359
360		/* Debugger process. */
361		close(dpipe[0]);
362
363		CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
364
365		wpid = waitpid(child, &status, 0);
366		CHILD_REQUIRE(wpid == child);
367		CHILD_REQUIRE(WIFSTOPPED(status));
368		CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP);
369
370		CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
371
372		/* Signal parent that debugger is attached. */
373		CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c));
374
375		/* Wait for parent's failed wait. */
376		CHILD_REQUIRE(read(dpipe[1], &c, sizeof(c)) == sizeof(c));
377
378		wpid = waitpid(child, &status, 0);
379		CHILD_REQUIRE(wpid == child);
380		CHILD_REQUIRE(WIFEXITED(status));
381		CHILD_REQUIRE(WEXITSTATUS(status) == 1);
382
383		_exit(0);
384	}
385	close(dpipe[1]);
386
387	/* Parent process. */
388
389	/* Wait for the debugger parent process to exit. */
390	wpid = waitpid(debugger, &status, 0);
391	ATF_REQUIRE(wpid == debugger);
392	ATF_REQUIRE(WIFEXITED(status));
393	ATF_REQUIRE(WEXITSTATUS(status) == 2);
394
395	/* A WNOHANG wait here should see the non-exited child. */
396	wpid = waitpid(child, &status, WNOHANG);
397	ATF_REQUIRE(wpid == 0);
398
399	/* Wait for the debugger to attach to the child. */
400	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c));
401
402	/* Release the child. */
403	ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c));
404	ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0);
405	close(cpipe[0]);
406
407	wait_for_zombie(child);
408
409	/*
410	 * This wait should return a pid of 0 to indicate no status to
411	 * report.  The parent should see the child as non-exited
412	 * until the debugger sees the exit.
413	 */
414	wpid = waitpid(child, &status, WNOHANG);
415	ATF_REQUIRE(wpid == 0);
416
417	/* Signal the debugger to wait for the child. */
418	ATF_REQUIRE(write(dpipe[0], &c, sizeof(c)) == sizeof(c));
419
420	/* Wait for the debugger. */
421	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == 0);
422	close(dpipe[0]);
423
424	/* The child process should now be ready. */
425	wpid = waitpid(child, &status, WNOHANG);
426	ATF_REQUIRE(wpid == child);
427	ATF_REQUIRE(WIFEXITED(status));
428	ATF_REQUIRE(WEXITSTATUS(status) == 1);
429}
430
431ATF_TP_ADD_TCS(tp)
432{
433
434	ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me);
435	ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach);
436	ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_child_debugger);
437	ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_unrelated_debugger);
438
439	return (atf_no_error());
440}
441
442