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