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