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