t_ptrace_topology_wait.h revision 1.1 1 1.1 kamil /* $NetBSD: t_ptrace_topology_wait.h,v 1.1 2020/05/05 00:33:37 kamil Exp $ */
2 1.1 kamil
3 1.1 kamil /*-
4 1.1 kamil * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
5 1.1 kamil * All rights reserved.
6 1.1 kamil *
7 1.1 kamil * Redistribution and use in source and binary forms, with or without
8 1.1 kamil * modification, are permitted provided that the following conditions
9 1.1 kamil * are met:
10 1.1 kamil * 1. Redistributions of source code must retain the above copyright
11 1.1 kamil * notice, this list of conditions and the following disclaimer.
12 1.1 kamil * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 kamil * notice, this list of conditions and the following disclaimer in the
14 1.1 kamil * documentation and/or other materials provided with the distribution.
15 1.1 kamil *
16 1.1 kamil * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 kamil * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 kamil * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 kamil * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 kamil * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 kamil * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 kamil * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 kamil * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 kamil * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 kamil * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 kamil * POSSIBILITY OF SUCH DAMAGE.
27 1.1 kamil */
28 1.1 kamil
29 1.1 kamil
30 1.1 kamil ATF_TC(traceme_pid1_parent);
31 1.1 kamil ATF_TC_HEAD(traceme_pid1_parent, tc)
32 1.1 kamil {
33 1.1 kamil atf_tc_set_md_var(tc, "descr",
34 1.1 kamil "Verify that PT_TRACE_ME is not allowed when our parent is PID1");
35 1.1 kamil }
36 1.1 kamil
37 1.1 kamil ATF_TC_BODY(traceme_pid1_parent, tc)
38 1.1 kamil {
39 1.1 kamil struct msg_fds parent_child;
40 1.1 kamil int exitval_child1 = 1, exitval_child2 = 2;
41 1.1 kamil pid_t child1, child2, wpid;
42 1.1 kamil uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
43 1.1 kamil #if defined(TWAIT_HAVE_STATUS)
44 1.1 kamil int status;
45 1.1 kamil #endif
46 1.1 kamil
47 1.1 kamil SYSCALL_REQUIRE(msg_open(&parent_child) == 0);
48 1.1 kamil
49 1.1 kamil DPRINTF("Before forking process PID=%d\n", getpid());
50 1.1 kamil SYSCALL_REQUIRE((child1 = fork()) != -1);
51 1.1 kamil if (child1 == 0) {
52 1.1 kamil DPRINTF("Before forking process PID=%d\n", getpid());
53 1.1 kamil SYSCALL_REQUIRE((child2 = fork()) != -1);
54 1.1 kamil if (child2 != 0) {
55 1.1 kamil DPRINTF("Parent process PID=%d, child2's PID=%d\n",
56 1.1 kamil getpid(), child2);
57 1.1 kamil _exit(exitval_child1);
58 1.1 kamil }
59 1.1 kamil CHILD_FROM_PARENT("exit child1", parent_child, msg);
60 1.1 kamil
61 1.1 kamil DPRINTF("Assert that our parent is PID1 (initproc)\n");
62 1.1 kamil FORKEE_ASSERT_EQ(getppid(), 1);
63 1.1 kamil
64 1.1 kamil DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
65 1.1 kamil FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) == -1);
66 1.1 kamil SYSCALL_REQUIRE_ERRNO(errno, EPERM);
67 1.1 kamil
68 1.1 kamil CHILD_TO_PARENT("child2 exiting", parent_child, msg);
69 1.1 kamil
70 1.1 kamil _exit(exitval_child2);
71 1.1 kamil }
72 1.1 kamil DPRINTF("Parent process PID=%d, child1's PID=%d\n", getpid(), child1);
73 1.1 kamil
74 1.1 kamil DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75 1.1 kamil TWAIT_REQUIRE_SUCCESS(
76 1.1 kamil wpid = TWAIT_GENERIC(child1, &status, WEXITED), child1);
77 1.1 kamil
78 1.1 kamil validate_status_exited(status, exitval_child1);
79 1.1 kamil
80 1.1 kamil DPRINTF("Notify that child1 is dead\n");
81 1.1 kamil PARENT_TO_CHILD("exit child1", parent_child, msg);
82 1.1 kamil
83 1.1 kamil DPRINTF("Wait for exiting of child2\n");
84 1.1 kamil PARENT_FROM_CHILD("child2 exiting", parent_child, msg);
85 1.1 kamil }
86 1.1 kamil
87 1.1 kamil /// ----------------------------------------------------------------------------
88 1.1 kamil
89 1.1 kamil #if defined(TWAIT_HAVE_PID)
90 1.1 kamil static void
91 1.1 kamil tracer_sees_terminaton_before_the_parent_raw(bool notimeout, bool unrelated,
92 1.1 kamil bool stopped)
93 1.1 kamil {
94 1.1 kamil /*
95 1.1 kamil * notimeout - disable timeout in await zombie function
96 1.1 kamil * unrelated - attach from unrelated tracer reparented to initproc
97 1.1 kamil * stopped - attach to a stopped process
98 1.1 kamil */
99 1.1 kamil
100 1.1 kamil struct msg_fds parent_tracee, parent_tracer;
101 1.1 kamil const int exitval_tracee = 5;
102 1.1 kamil const int exitval_tracer = 10;
103 1.1 kamil pid_t tracee, tracer, wpid;
104 1.1 kamil uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
105 1.1 kamil #if defined(TWAIT_HAVE_STATUS)
106 1.1 kamil int status;
107 1.1 kamil #endif
108 1.1 kamil
109 1.1 kamil /*
110 1.1 kamil * Only a subset of options are supported.
111 1.1 kamil */
112 1.1 kamil ATF_REQUIRE((!notimeout && !unrelated && !stopped) ||
113 1.1 kamil (!notimeout && unrelated && !stopped) ||
114 1.1 kamil (notimeout && !unrelated && !stopped) ||
115 1.1 kamil (!notimeout && unrelated && stopped));
116 1.1 kamil
117 1.1 kamil DPRINTF("Spawn tracee\n");
118 1.1 kamil SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
119 1.1 kamil tracee = atf_utils_fork();
120 1.1 kamil if (tracee == 0) {
121 1.1 kamil if (stopped) {
122 1.1 kamil DPRINTF("Stop self PID %d\n", getpid());
123 1.1 kamil raise(SIGSTOP);
124 1.1 kamil }
125 1.1 kamil
126 1.1 kamil // Wait for parent to let us exit
127 1.1 kamil CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
128 1.1 kamil _exit(exitval_tracee);
129 1.1 kamil }
130 1.1 kamil
131 1.1 kamil DPRINTF("Spawn debugger\n");
132 1.1 kamil SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
133 1.1 kamil tracer = atf_utils_fork();
134 1.1 kamil if (tracer == 0) {
135 1.1 kamil if(unrelated) {
136 1.1 kamil /* Fork again and drop parent to reattach to PID 1 */
137 1.1 kamil tracer = atf_utils_fork();
138 1.1 kamil if (tracer != 0)
139 1.1 kamil _exit(exitval_tracer);
140 1.1 kamil }
141 1.1 kamil
142 1.1 kamil if (stopped) {
143 1.1 kamil DPRINTF("Await for a stopped parent PID %d\n", tracee);
144 1.1 kamil await_stopped(tracee);
145 1.1 kamil }
146 1.1 kamil
147 1.1 kamil DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
148 1.1 kamil FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
149 1.1 kamil
150 1.1 kamil /* Wait for tracee and assert that it was stopped w/ SIGSTOP */
151 1.1 kamil FORKEE_REQUIRE_SUCCESS(
152 1.1 kamil wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
153 1.1 kamil
154 1.1 kamil forkee_status_stopped(status, SIGSTOP);
155 1.1 kamil
156 1.1 kamil /* Resume tracee with PT_CONTINUE */
157 1.1 kamil FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
158 1.1 kamil
159 1.1 kamil /* Inform parent that tracer has attached to tracee */
160 1.1 kamil CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
161 1.1 kamil
162 1.1 kamil /* Wait for parent to tell use that tracee should have exited */
163 1.1 kamil CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
164 1.1 kamil
165 1.1 kamil /* Wait for tracee and assert that it exited */
166 1.1 kamil FORKEE_REQUIRE_SUCCESS(
167 1.1 kamil wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
168 1.1 kamil
169 1.1 kamil forkee_status_exited(status, exitval_tracee);
170 1.1 kamil DPRINTF("Tracee %d exited with %d\n", tracee, exitval_tracee);
171 1.1 kamil
172 1.1 kamil DPRINTF("Before exiting of the tracer process\n");
173 1.1 kamil _exit(unrelated ? 0 /* collect by initproc */ : exitval_tracer);
174 1.1 kamil }
175 1.1 kamil
176 1.1 kamil if (unrelated) {
177 1.1 kamil DPRINTF("Wait for the tracer process (direct child) to exit "
178 1.1 kamil "calling %s()\n", TWAIT_FNAME);
179 1.1 kamil TWAIT_REQUIRE_SUCCESS(
180 1.1 kamil wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
181 1.1 kamil
182 1.1 kamil validate_status_exited(status, exitval_tracer);
183 1.1 kamil
184 1.1 kamil DPRINTF("Wait for the non-exited tracee process with %s()\n",
185 1.1 kamil TWAIT_FNAME);
186 1.1 kamil TWAIT_REQUIRE_SUCCESS(
187 1.1 kamil wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
188 1.1 kamil }
189 1.1 kamil
190 1.1 kamil DPRINTF("Wait for the tracer to attach to the tracee\n");
191 1.1 kamil PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
192 1.1 kamil
193 1.1 kamil DPRINTF("Resume the tracee and let it exit\n");
194 1.1 kamil PARENT_TO_CHILD("exit tracee", parent_tracee, msg);
195 1.1 kamil
196 1.1 kamil DPRINTF("Detect that tracee is zombie\n");
197 1.1 kamil if (notimeout)
198 1.1 kamil await_zombie_raw(tracee, 0);
199 1.1 kamil else
200 1.1 kamil await_zombie(tracee);
201 1.1 kamil
202 1.1 kamil DPRINTF("Assert that there is no status about tracee %d - "
203 1.1 kamil "Tracer must detect zombie first - calling %s()\n", tracee,
204 1.1 kamil TWAIT_FNAME);
205 1.1 kamil TWAIT_REQUIRE_SUCCESS(
206 1.1 kamil wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
207 1.1 kamil
208 1.1 kamil if (unrelated) {
209 1.1 kamil DPRINTF("Resume the tracer and let it detect exited tracee\n");
210 1.1 kamil PARENT_TO_CHILD("Message 2", parent_tracer, msg);
211 1.1 kamil } else {
212 1.1 kamil DPRINTF("Tell the tracer child should have exited\n");
213 1.1 kamil PARENT_TO_CHILD("wait for tracee exit", parent_tracer, msg);
214 1.1 kamil DPRINTF("Wait for tracer to finish its job and exit - calling "
215 1.1 kamil "%s()\n", TWAIT_FNAME);
216 1.1 kamil
217 1.1 kamil DPRINTF("Wait from tracer child to complete waiting for "
218 1.1 kamil "tracee\n");
219 1.1 kamil TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
220 1.1 kamil tracer);
221 1.1 kamil
222 1.1 kamil validate_status_exited(status, exitval_tracer);
223 1.1 kamil }
224 1.1 kamil
225 1.1 kamil DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
226 1.1 kamil TWAIT_FNAME);
227 1.1 kamil TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
228 1.1 kamil
229 1.1 kamil validate_status_exited(status, exitval_tracee);
230 1.1 kamil
231 1.1 kamil msg_close(&parent_tracer);
232 1.1 kamil msg_close(&parent_tracee);
233 1.1 kamil }
234 1.1 kamil
235 1.1 kamil ATF_TC(tracer_sees_terminaton_before_the_parent);
236 1.1 kamil ATF_TC_HEAD(tracer_sees_terminaton_before_the_parent, tc)
237 1.1 kamil {
238 1.1 kamil atf_tc_set_md_var(tc, "descr",
239 1.1 kamil "Assert that tracer sees process termination before the parent");
240 1.1 kamil }
241 1.1 kamil
242 1.1 kamil ATF_TC_BODY(tracer_sees_terminaton_before_the_parent, tc)
243 1.1 kamil {
244 1.1 kamil
245 1.1 kamil tracer_sees_terminaton_before_the_parent_raw(false, false, false);
246 1.1 kamil }
247 1.1 kamil
248 1.1 kamil ATF_TC(tracer_sysctl_lookup_without_duplicates);
249 1.1 kamil ATF_TC_HEAD(tracer_sysctl_lookup_without_duplicates, tc)
250 1.1 kamil {
251 1.1 kamil atf_tc_set_md_var(tc, "timeout", "15");
252 1.1 kamil atf_tc_set_md_var(tc, "descr",
253 1.1 kamil "Assert that await_zombie() in attach1 always finds a single "
254 1.1 kamil "process and no other error is reported");
255 1.1 kamil }
256 1.1 kamil
257 1.1 kamil ATF_TC_BODY(tracer_sysctl_lookup_without_duplicates, tc)
258 1.1 kamil {
259 1.1 kamil time_t start, end;
260 1.1 kamil double diff;
261 1.1 kamil unsigned long N = 0;
262 1.1 kamil
263 1.1 kamil /*
264 1.1 kamil * Reuse this test with tracer_sees_terminaton_before_the_parent_raw().
265 1.1 kamil * This test body isn't specific to this race, however it's just good
266 1.1 kamil * enough for this purposes, no need to invent a dedicated code flow.
267 1.1 kamil */
268 1.1 kamil
269 1.1 kamil start = time(NULL);
270 1.1 kamil while (true) {
271 1.1 kamil DPRINTF("Step: %lu\n", N);
272 1.1 kamil tracer_sees_terminaton_before_the_parent_raw(true, false,
273 1.1 kamil false);
274 1.1 kamil end = time(NULL);
275 1.1 kamil diff = difftime(end, start);
276 1.1 kamil if (diff >= 5.0)
277 1.1 kamil break;
278 1.1 kamil ++N;
279 1.1 kamil }
280 1.1 kamil DPRINTF("Iterations: %lu\n", N);
281 1.1 kamil }
282 1.1 kamil
283 1.1 kamil ATF_TC(unrelated_tracer_sees_terminaton_before_the_parent);
284 1.1 kamil ATF_TC_HEAD(unrelated_tracer_sees_terminaton_before_the_parent, tc)
285 1.1 kamil {
286 1.1 kamil atf_tc_set_md_var(tc, "descr",
287 1.1 kamil "Assert that tracer sees process termination before the parent");
288 1.1 kamil }
289 1.1 kamil
290 1.1 kamil ATF_TC_BODY(unrelated_tracer_sees_terminaton_before_the_parent, tc)
291 1.1 kamil {
292 1.1 kamil
293 1.1 kamil tracer_sees_terminaton_before_the_parent_raw(false, true, false);
294 1.1 kamil }
295 1.1 kamil
296 1.1 kamil ATF_TC(tracer_attach_to_unrelated_stopped_process);
297 1.1 kamil ATF_TC_HEAD(tracer_attach_to_unrelated_stopped_process, tc)
298 1.1 kamil {
299 1.1 kamil atf_tc_set_md_var(tc, "descr",
300 1.1 kamil "Assert that tracer can attach to an unrelated stopped process");
301 1.1 kamil }
302 1.1 kamil
303 1.1 kamil ATF_TC_BODY(tracer_attach_to_unrelated_stopped_process, tc)
304 1.1 kamil {
305 1.1 kamil
306 1.1 kamil tracer_sees_terminaton_before_the_parent_raw(false, true, true);
307 1.1 kamil }
308 1.1 kamil #endif
309 1.1 kamil
310 1.1 kamil /// ----------------------------------------------------------------------------
311 1.1 kamil
312 1.1 kamil static void
313 1.1 kamil parent_attach_to_its_child(bool stopped)
314 1.1 kamil {
315 1.1 kamil struct msg_fds parent_tracee;
316 1.1 kamil const int exitval_tracee = 5;
317 1.1 kamil pid_t tracee, wpid;
318 1.1 kamil uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
319 1.1 kamil #if defined(TWAIT_HAVE_STATUS)
320 1.1 kamil int status;
321 1.1 kamil #endif
322 1.1 kamil
323 1.1 kamil DPRINTF("Spawn tracee\n");
324 1.1 kamil SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
325 1.1 kamil tracee = atf_utils_fork();
326 1.1 kamil if (tracee == 0) {
327 1.1 kamil CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
328 1.1 kamil DPRINTF("Parent should now attach to tracee\n");
329 1.1 kamil
330 1.1 kamil if (stopped) {
331 1.1 kamil DPRINTF("Stop self PID %d\n", getpid());
332 1.1 kamil SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
333 1.1 kamil }
334 1.1 kamil
335 1.1 kamil CHILD_FROM_PARENT("Message 2", parent_tracee, msg);
336 1.1 kamil /* Wait for message from the parent */
337 1.1 kamil _exit(exitval_tracee);
338 1.1 kamil }
339 1.1 kamil PARENT_TO_CHILD("Message 1", parent_tracee, msg);
340 1.1 kamil
341 1.1 kamil if (stopped) {
342 1.1 kamil DPRINTF("Await for a stopped tracee PID %d\n", tracee);
343 1.1 kamil await_stopped(tracee);
344 1.1 kamil }
345 1.1 kamil
346 1.1 kamil DPRINTF("Before calling PT_ATTACH for tracee %d\n", tracee);
347 1.1 kamil SYSCALL_REQUIRE(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
348 1.1 kamil
349 1.1 kamil DPRINTF("Wait for the stopped tracee process with %s()\n",
350 1.1 kamil TWAIT_FNAME);
351 1.1 kamil TWAIT_REQUIRE_SUCCESS(
352 1.1 kamil wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
353 1.1 kamil
354 1.1 kamil validate_status_stopped(status, SIGSTOP);
355 1.1 kamil
356 1.1 kamil DPRINTF("Resume tracee with PT_CONTINUE\n");
357 1.1 kamil SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
358 1.1 kamil
359 1.1 kamil DPRINTF("Let the tracee exit now\n");
360 1.1 kamil PARENT_TO_CHILD("Message 2", parent_tracee, msg);
361 1.1 kamil
362 1.1 kamil DPRINTF("Wait for tracee to exit with %s()\n", TWAIT_FNAME);
363 1.1 kamil TWAIT_REQUIRE_SUCCESS(
364 1.1 kamil wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
365 1.1 kamil
366 1.1 kamil validate_status_exited(status, exitval_tracee);
367 1.1 kamil
368 1.1 kamil DPRINTF("Before calling %s() for tracee\n", TWAIT_FNAME);
369 1.1 kamil TWAIT_REQUIRE_FAILURE(ECHILD,
370 1.1 kamil wpid = TWAIT_GENERIC(tracee, &status, 0));
371 1.1 kamil
372 1.1 kamil msg_close(&parent_tracee);
373 1.1 kamil }
374 1.1 kamil
375 1.1 kamil ATF_TC(parent_attach_to_its_child);
376 1.1 kamil ATF_TC_HEAD(parent_attach_to_its_child, tc)
377 1.1 kamil {
378 1.1 kamil atf_tc_set_md_var(tc, "descr",
379 1.1 kamil "Assert that tracer parent can PT_ATTACH to its child");
380 1.1 kamil }
381 1.1 kamil
382 1.1 kamil ATF_TC_BODY(parent_attach_to_its_child, tc)
383 1.1 kamil {
384 1.1 kamil
385 1.1 kamil parent_attach_to_its_child(false);
386 1.1 kamil }
387 1.1 kamil
388 1.1 kamil ATF_TC(parent_attach_to_its_stopped_child);
389 1.1 kamil ATF_TC_HEAD(parent_attach_to_its_stopped_child, tc)
390 1.1 kamil {
391 1.1 kamil atf_tc_set_md_var(tc, "descr",
392 1.1 kamil "Assert that tracer parent can PT_ATTACH to its stopped child");
393 1.1 kamil }
394 1.1 kamil
395 1.1 kamil ATF_TC_BODY(parent_attach_to_its_stopped_child, tc)
396 1.1 kamil {
397 1.1 kamil
398 1.1 kamil parent_attach_to_its_child(true);
399 1.1 kamil }
400 1.1 kamil
401 1.1 kamil /// ----------------------------------------------------------------------------
402 1.1 kamil
403 1.1 kamil static void
404 1.1 kamil child_attach_to_its_parent(bool stopped)
405 1.1 kamil {
406 1.1 kamil struct msg_fds parent_tracee;
407 1.1 kamil const int exitval_tracer = 5;
408 1.1 kamil pid_t tracer, wpid;
409 1.1 kamil uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
410 1.1 kamil #if defined(TWAIT_HAVE_STATUS)
411 1.1 kamil int status;
412 1.1 kamil #endif
413 1.1 kamil
414 1.1 kamil DPRINTF("Spawn tracer\n");
415 1.1 kamil SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
416 1.1 kamil tracer = atf_utils_fork();
417 1.1 kamil if (tracer == 0) {
418 1.1 kamil /* Wait for message from the parent */
419 1.1 kamil CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
420 1.1 kamil
421 1.1 kamil if (stopped) {
422 1.1 kamil DPRINTF("Await for a stopped parent PID %d\n",
423 1.1 kamil getppid());
424 1.1 kamil await_stopped(getppid());
425 1.1 kamil }
426 1.1 kamil
427 1.1 kamil DPRINTF("Attach to parent PID %d with PT_ATTACH from child\n",
428 1.1 kamil getppid());
429 1.1 kamil FORKEE_ASSERT(ptrace(PT_ATTACH, getppid(), NULL, 0) != -1);
430 1.1 kamil
431 1.1 kamil DPRINTF("Wait for the stopped parent process with %s()\n",
432 1.1 kamil TWAIT_FNAME);
433 1.1 kamil FORKEE_REQUIRE_SUCCESS(
434 1.1 kamil wpid = TWAIT_GENERIC(getppid(), &status, 0), getppid());
435 1.1 kamil
436 1.1 kamil forkee_status_stopped(status, SIGSTOP);
437 1.1 kamil
438 1.1 kamil DPRINTF("Resume parent with PT_DETACH\n");
439 1.1 kamil FORKEE_ASSERT(ptrace(PT_DETACH, getppid(), (void *)1, 0)
440 1.1 kamil != -1);
441 1.1 kamil
442 1.1 kamil /* Tell parent we are ready */
443 1.1 kamil CHILD_TO_PARENT("Message 1", parent_tracee, msg);
444 1.1 kamil
445 1.1 kamil _exit(exitval_tracer);
446 1.1 kamil }
447 1.1 kamil
448 1.1 kamil DPRINTF("Wait for the tracer to become ready\n");
449 1.1 kamil PARENT_TO_CHILD("Message 1", parent_tracee, msg);
450 1.1 kamil
451 1.1 kamil if (stopped) {
452 1.1 kamil DPRINTF("Stop self PID %d\n", getpid());
453 1.1 kamil SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
454 1.1 kamil }
455 1.1 kamil
456 1.1 kamil DPRINTF("Allow the tracer to exit now\n");
457 1.1 kamil PARENT_FROM_CHILD("Message 1", parent_tracee, msg);
458 1.1 kamil
459 1.1 kamil DPRINTF("Wait for tracer to exit with %s()\n", TWAIT_FNAME);
460 1.1 kamil TWAIT_REQUIRE_SUCCESS(
461 1.1 kamil wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
462 1.1 kamil
463 1.1 kamil validate_status_exited(status, exitval_tracer);
464 1.1 kamil
465 1.1 kamil DPRINTF("Before calling %s() for tracer\n", TWAIT_FNAME);
466 1.1 kamil TWAIT_REQUIRE_FAILURE(ECHILD,
467 1.1 kamil wpid = TWAIT_GENERIC(tracer, &status, 0));
468 1.1 kamil
469 1.1 kamil msg_close(&parent_tracee);
470 1.1 kamil }
471 1.1 kamil
472 1.1 kamil ATF_TC(child_attach_to_its_parent);
473 1.1 kamil ATF_TC_HEAD(child_attach_to_its_parent, tc)
474 1.1 kamil {
475 1.1 kamil atf_tc_set_md_var(tc, "descr",
476 1.1 kamil "Assert that tracer child can PT_ATTACH to its parent");
477 1.1 kamil }
478 1.1 kamil
479 1.1 kamil ATF_TC_BODY(child_attach_to_its_parent, tc)
480 1.1 kamil {
481 1.1 kamil
482 1.1 kamil child_attach_to_its_parent(false);
483 1.1 kamil }
484 1.1 kamil
485 1.1 kamil ATF_TC(child_attach_to_its_stopped_parent);
486 1.1 kamil ATF_TC_HEAD(child_attach_to_its_stopped_parent, tc)
487 1.1 kamil {
488 1.1 kamil atf_tc_set_md_var(tc, "descr",
489 1.1 kamil "Assert that tracer child can PT_ATTACH to its stopped parent");
490 1.1 kamil }
491 1.1 kamil
492 1.1 kamil ATF_TC_BODY(child_attach_to_its_stopped_parent, tc)
493 1.1 kamil {
494 1.1 kamil /*
495 1.1 kamil * The ATF framework (atf-run) does not tolerate raise(SIGSTOP), as
496 1.1 kamil * this causes a pipe (established from atf-run) to be broken.
497 1.1 kamil * atf-run uses this mechanism to monitor whether a test is alive.
498 1.1 kamil *
499 1.1 kamil * As a workaround spawn this test as a subprocess.
500 1.1 kamil */
501 1.1 kamil
502 1.1 kamil const int exitval = 15;
503 1.1 kamil pid_t child, wpid;
504 1.1 kamil #if defined(TWAIT_HAVE_STATUS)
505 1.1 kamil int status;
506 1.1 kamil #endif
507 1.1 kamil
508 1.1 kamil SYSCALL_REQUIRE((child = fork()) != -1);
509 1.1 kamil if (child == 0) {
510 1.1 kamil child_attach_to_its_parent(true);
511 1.1 kamil _exit(exitval);
512 1.1 kamil } else {
513 1.1 kamil DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
514 1.1 kamil TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
515 1.1 kamil
516 1.1 kamil validate_status_exited(status, exitval);
517 1.1 kamil
518 1.1 kamil DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
519 1.1 kamil TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
520 1.1 kamil }
521 1.1 kamil }
522 1.1 kamil
523 1.1 kamil /// ----------------------------------------------------------------------------
524 1.1 kamil
525 1.1 kamil #if defined(TWAIT_HAVE_PID)
526 1.1 kamil
527 1.1 kamil enum tracee_sees_its_original_parent_type {
528 1.1 kamil TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
529 1.1 kamil TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
530 1.1 kamil TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS
531 1.1 kamil };
532 1.1 kamil
533 1.1 kamil static void
534 1.1 kamil tracee_sees_its_original_parent(enum tracee_sees_its_original_parent_type type)
535 1.1 kamil {
536 1.1 kamil struct msg_fds parent_tracer, parent_tracee;
537 1.1 kamil const int exitval_tracee = 5;
538 1.1 kamil const int exitval_tracer = 10;
539 1.1 kamil pid_t parent, tracee, tracer, wpid;
540 1.1 kamil uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
541 1.1 kamil #if defined(TWAIT_HAVE_STATUS)
542 1.1 kamil int status;
543 1.1 kamil #endif
544 1.1 kamil /* sysctl(3) - kinfo_proc2 */
545 1.1 kamil int name[CTL_MAXNAME];
546 1.1 kamil struct kinfo_proc2 kp;
547 1.1 kamil size_t len = sizeof(kp);
548 1.1 kamil unsigned int namelen;
549 1.1 kamil
550 1.1 kamil /* procfs - status */
551 1.1 kamil FILE *fp;
552 1.1 kamil struct stat st;
553 1.1 kamil const char *fname = "/proc/curproc/status";
554 1.1 kamil char s_executable[MAXPATHLEN];
555 1.1 kamil int s_pid, s_ppid;
556 1.1 kamil int rv;
557 1.1 kamil
558 1.1 kamil if (type == TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS) {
559 1.1 kamil SYSCALL_REQUIRE(
560 1.1 kamil (rv = stat(fname, &st)) == 0 || (errno == ENOENT));
561 1.1 kamil if (rv != 0)
562 1.1 kamil atf_tc_skip("/proc/curproc/status not found");
563 1.1 kamil }
564 1.1 kamil
565 1.1 kamil DPRINTF("Spawn tracee\n");
566 1.1 kamil SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
567 1.1 kamil SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
568 1.1 kamil tracee = atf_utils_fork();
569 1.1 kamil if (tracee == 0) {
570 1.1 kamil parent = getppid();
571 1.1 kamil
572 1.1 kamil /* Emit message to the parent */
573 1.1 kamil CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
574 1.1 kamil CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
575 1.1 kamil
576 1.1 kamil switch (type) {
577 1.1 kamil case TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID:
578 1.1 kamil FORKEE_ASSERT_EQ(parent, getppid());
579 1.1 kamil break;
580 1.1 kamil case TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2:
581 1.1 kamil namelen = 0;
582 1.1 kamil name[namelen++] = CTL_KERN;
583 1.1 kamil name[namelen++] = KERN_PROC2;
584 1.1 kamil name[namelen++] = KERN_PROC_PID;
585 1.1 kamil name[namelen++] = getpid();
586 1.1 kamil name[namelen++] = len;
587 1.1 kamil name[namelen++] = 1;
588 1.1 kamil
589 1.1 kamil FORKEE_ASSERT_EQ(
590 1.1 kamil sysctl(name, namelen, &kp, &len, NULL, 0), 0);
591 1.1 kamil FORKEE_ASSERT_EQ(parent, kp.p_ppid);
592 1.1 kamil break;
593 1.1 kamil case TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS:
594 1.1 kamil /*
595 1.1 kamil * Format:
596 1.1 kamil * EXECUTABLE PID PPID ...
597 1.1 kamil */
598 1.1 kamil FORKEE_ASSERT((fp = fopen(fname, "r")) != NULL);
599 1.1 kamil fscanf(fp, "%s %d %d", s_executable, &s_pid, &s_ppid);
600 1.1 kamil FORKEE_ASSERT_EQ(fclose(fp), 0);
601 1.1 kamil FORKEE_ASSERT_EQ(parent, s_ppid);
602 1.1 kamil break;
603 1.1 kamil }
604 1.1 kamil
605 1.1 kamil _exit(exitval_tracee);
606 1.1 kamil }
607 1.1 kamil DPRINTF("Wait for child to record its parent identifier (pid)\n");
608 1.1 kamil PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
609 1.1 kamil
610 1.1 kamil DPRINTF("Spawn debugger\n");
611 1.1 kamil tracer = atf_utils_fork();
612 1.1 kamil if (tracer == 0) {
613 1.1 kamil /* No IPC to communicate with the child */
614 1.1 kamil DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
615 1.1 kamil FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
616 1.1 kamil
617 1.1 kamil /* Wait for tracee and assert that it was stopped w/ SIGSTOP */
618 1.1 kamil FORKEE_REQUIRE_SUCCESS(
619 1.1 kamil wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
620 1.1 kamil
621 1.1 kamil forkee_status_stopped(status, SIGSTOP);
622 1.1 kamil
623 1.1 kamil /* Resume tracee with PT_CONTINUE */
624 1.1 kamil FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
625 1.1 kamil
626 1.1 kamil /* Inform parent that tracer has attached to tracee */
627 1.1 kamil CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
628 1.1 kamil
629 1.1 kamil /* Wait for parent to tell use that tracee should have exited */
630 1.1 kamil CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
631 1.1 kamil
632 1.1 kamil /* Wait for tracee and assert that it exited */
633 1.1 kamil FORKEE_REQUIRE_SUCCESS(
634 1.1 kamil wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
635 1.1 kamil
636 1.1 kamil forkee_status_exited(status, exitval_tracee);
637 1.1 kamil
638 1.1 kamil DPRINTF("Before exiting of the tracer process\n");
639 1.1 kamil _exit(exitval_tracer);
640 1.1 kamil }
641 1.1 kamil
642 1.1 kamil DPRINTF("Wait for the tracer to attach to the tracee\n");
643 1.1 kamil PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
644 1.1 kamil
645 1.1 kamil DPRINTF("Resume the tracee and let it exit\n");
646 1.1 kamil PARENT_TO_CHILD("exit tracee", parent_tracee, msg);
647 1.1 kamil
648 1.1 kamil DPRINTF("Detect that tracee is zombie\n");
649 1.1 kamil await_zombie(tracee);
650 1.1 kamil
651 1.1 kamil DPRINTF("Assert that there is no status about tracee - "
652 1.1 kamil "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
653 1.1 kamil TWAIT_REQUIRE_SUCCESS(
654 1.1 kamil wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
655 1.1 kamil
656 1.1 kamil DPRINTF("Tell the tracer child should have exited\n");
657 1.1 kamil PARENT_TO_CHILD("wait for tracee exit", parent_tracer, msg);
658 1.1 kamil
659 1.1 kamil DPRINTF("Wait from tracer child to complete waiting for tracee\n");
660 1.1 kamil TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
661 1.1 kamil tracer);
662 1.1 kamil
663 1.1 kamil validate_status_exited(status, exitval_tracer);
664 1.1 kamil
665 1.1 kamil DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
666 1.1 kamil TWAIT_FNAME);
667 1.1 kamil TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
668 1.1 kamil tracee);
669 1.1 kamil
670 1.1 kamil validate_status_exited(status, exitval_tracee);
671 1.1 kamil
672 1.1 kamil msg_close(&parent_tracer);
673 1.1 kamil msg_close(&parent_tracee);
674 1.1 kamil }
675 1.1 kamil
676 1.1 kamil #define TRACEE_SEES_ITS_ORIGINAL_PARENT(test, type, descr) \
677 1.1 kamil ATF_TC(test); \
678 1.1 kamil ATF_TC_HEAD(test, tc) \
679 1.1 kamil { \
680 1.1 kamil atf_tc_set_md_var(tc, "descr", \
681 1.1 kamil "Assert that tracee sees its original parent when being traced " \
682 1.1 kamil "(check " descr ")"); \
683 1.1 kamil } \
684 1.1 kamil \
685 1.1 kamil ATF_TC_BODY(test, tc) \
686 1.1 kamil { \
687 1.1 kamil \
688 1.1 kamil tracee_sees_its_original_parent(type); \
689 1.1 kamil }
690 1.1 kamil
691 1.1 kamil TRACEE_SEES_ITS_ORIGINAL_PARENT(
692 1.1 kamil tracee_sees_its_original_parent_getppid,
693 1.1 kamil TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
694 1.1 kamil "getppid(2)");
695 1.1 kamil TRACEE_SEES_ITS_ORIGINAL_PARENT(
696 1.1 kamil tracee_sees_its_original_parent_sysctl_kinfo_proc2,
697 1.1 kamil TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
698 1.1 kamil "sysctl(3) and kinfo_proc2");
699 1.1 kamil TRACEE_SEES_ITS_ORIGINAL_PARENT(
700 1.1 kamil tracee_sees_its_original_parent_procfs_status,
701 1.1 kamil TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS,
702 1.1 kamil "the status file in procfs");
703 1.1 kamil #endif
704 1.1 kamil
705 1.1 kamil #define ATF_TP_ADD_TCS_PTRACE_WAIT_TOPOLOGY() \
706 1.1 kamil ATF_TP_ADD_TC(tp, traceme_pid1_parent); \
707 1.1 kamil ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sees_terminaton_before_the_parent); \
708 1.1 kamil ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sysctl_lookup_without_duplicates); \
709 1.1 kamil ATF_TP_ADD_TC_HAVE_PID(tp, \
710 1.1 kamil unrelated_tracer_sees_terminaton_before_the_parent); \
711 1.1 kamil ATF_TP_ADD_TC_HAVE_PID(tp, tracer_attach_to_unrelated_stopped_process); \
712 1.1 kamil ATF_TP_ADD_TC(tp, parent_attach_to_its_child); \
713 1.1 kamil ATF_TP_ADD_TC(tp, parent_attach_to_its_stopped_child); \
714 1.1 kamil ATF_TP_ADD_TC(tp, child_attach_to_its_parent); \
715 1.1 kamil ATF_TP_ADD_TC(tp, child_attach_to_its_stopped_parent); \
716 1.1 kamil ATF_TP_ADD_TC_HAVE_PID(tp, \
717 1.1 kamil tracee_sees_its_original_parent_getppid); \
718 1.1 kamil ATF_TP_ADD_TC_HAVE_PID(tp, \
719 1.1 kamil tracee_sees_its_original_parent_sysctl_kinfo_proc2); \
720 1.1 kamil ATF_TP_ADD_TC_HAVE_PID(tp, \
721 1.1 kamil tracee_sees_its_original_parent_procfs_status);
722