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