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