1 /*- 2 * Copyright (c) 2018 Thomas Munro 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 <assert.h> 31 #include <atf-c.h> 32 #include <errno.h> 33 #include <signal.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <time.h> 37 #include <unistd.h> 38 #include <sys/procctl.h> 39 #include <sys/ptrace.h> 40 #include <sys/signal.h> 41 #include <sys/types.h> 42 43 static void 44 dummy_signal_handler(int signum) 45 { 46 } 47 48 ATF_TC_WITHOUT_HEAD(arg_validation); 49 ATF_TC_BODY(arg_validation, tc) 50 { 51 int signum; 52 int rc; 53 54 /* bad signal */ 55 signum = 8888; 56 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum); 57 ATF_CHECK_EQ(-1, rc); 58 ATF_CHECK_EQ(EINVAL, errno); 59 60 /* bad id type */ 61 signum = SIGINFO; 62 rc = procctl(8888, 0, PROC_PDEATHSIG_CTL, &signum); 63 ATF_CHECK_EQ(-1, rc); 64 ATF_CHECK_EQ(EINVAL, errno); 65 66 /* bad id (pid that doesn't match mine or zero) */ 67 signum = SIGINFO; 68 rc = procctl(P_PID, (((getpid() + 1) % 10) + 100), 69 PROC_PDEATHSIG_CTL, &signum); 70 ATF_CHECK_EQ(-1, rc); 71 ATF_CHECK_EQ(EINVAL, errno); 72 73 /* null pointer */ 74 signum = SIGINFO; 75 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, NULL); 76 ATF_CHECK_EQ(-1, rc); 77 ATF_CHECK_EQ(EFAULT, errno); 78 79 /* good (pid == 0) */ 80 signum = SIGINFO; 81 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum); 82 ATF_CHECK_EQ(0, rc); 83 84 /* good (pid == my pid) */ 85 signum = SIGINFO; 86 rc = procctl(P_PID, getpid(), PROC_PDEATHSIG_CTL, &signum); 87 ATF_CHECK_EQ(0, rc); 88 89 /* check that we can read the signal number back */ 90 signum = 0xdeadbeef; 91 rc = procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &signum); 92 ATF_CHECK_EQ(0, rc); 93 ATF_CHECK_EQ(SIGINFO, signum); 94 } 95 96 ATF_TC_WITHOUT_HEAD(fork_no_inherit); 97 ATF_TC_BODY(fork_no_inherit, tc) 98 { 99 int status; 100 int signum; 101 int rc; 102 103 /* request a signal on parent death in the parent */ 104 signum = SIGINFO; 105 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum); 106 107 rc = fork(); 108 ATF_REQUIRE(rc != -1); 109 if (rc == 0) { 110 /* check that we didn't inherit the setting */ 111 signum = 0xdeadbeef; 112 rc = procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &signum); 113 assert(rc == 0); 114 assert(signum == 0); 115 _exit(0); 116 } 117 118 /* wait for the child to exit successfully */ 119 waitpid(rc, &status, 0); 120 ATF_CHECK_EQ(0, status); 121 } 122 123 ATF_TC_WITHOUT_HEAD(exec_inherit); 124 ATF_TC_BODY(exec_inherit, tc) 125 { 126 int status; 127 int rc; 128 129 rc = fork(); 130 ATF_REQUIRE(rc != -1); 131 if (rc == 0) { 132 char exec_path[1024]; 133 int signum; 134 135 /* compute the path of the helper executable */ 136 snprintf(exec_path, sizeof(exec_path), "%s/pdeathsig_helper", 137 atf_tc_get_config_var(tc, "srcdir")); 138 139 /* request a signal on parent death and register a handler */ 140 signum = SIGINFO; 141 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum); 142 assert(rc == 0); 143 144 /* execute helper program: it asserts that it has the setting */ 145 rc = execl(exec_path, exec_path, NULL); 146 assert(rc == 0); 147 _exit(0); 148 } 149 150 /* wait for the child to exit successfully */ 151 waitpid(rc, &status, 0); 152 ATF_CHECK_EQ(0, status); 153 } 154 155 ATF_TC_WITHOUT_HEAD(signal_delivered); 156 ATF_TC_BODY(signal_delivered, tc) 157 { 158 sigset_t sigset; 159 int signum; 160 int rc; 161 int pipe_ca[2]; 162 int pipe_cb[2]; 163 char buffer; 164 165 rc = pipe(pipe_ca); 166 ATF_REQUIRE(rc == 0); 167 rc = pipe(pipe_cb); 168 ATF_REQUIRE(rc == 0); 169 170 rc = fork(); 171 ATF_REQUIRE(rc != -1); 172 if (rc == 0) { 173 rc = fork(); 174 assert(rc >= 0); 175 if (rc == 0) { 176 /* process C */ 177 signum = SIGINFO; 178 179 /* block signals so we can handle them synchronously */ 180 rc = sigfillset(&sigset); 181 assert(rc == 0); 182 rc = sigprocmask(SIG_SETMASK, &sigset, NULL); 183 assert(rc == 0); 184 185 /* register a dummy handler or the kernel will not queue it */ 186 signal(signum, dummy_signal_handler); 187 188 /* request a signal on death of our parent B */ 189 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum); 190 assert(rc == 0); 191 192 /* tell B that we're ready for it to exit now */ 193 rc = write(pipe_cb[1], ".", 1); 194 assert(rc == 1); 195 196 /* wait for B to die and signal us... */ 197 signum = 0xdeadbeef; 198 rc = sigwait(&sigset, &signum); 199 assert(rc == 0); 200 assert(signum == SIGINFO); 201 202 /* tell A the test passed */ 203 rc = write(pipe_ca[1], ".", 1); 204 assert(rc == 1); 205 _exit(0); 206 } 207 208 /* process B */ 209 210 /* wait for C to tell us it is ready for us to exit */ 211 rc = read(pipe_cb[0], &buffer, 1); 212 assert(rc == 1); 213 214 /* now we exit so that C gets a signal */ 215 _exit(0); 216 } 217 /* process A */ 218 219 /* wait for C to tell us the test passed */ 220 rc = read(pipe_ca[0], &buffer, 1); 221 ATF_CHECK_EQ(1, rc); 222 } 223 224 ATF_TC_WITHOUT_HEAD(signal_delivered_ptrace); 225 ATF_TC_BODY(signal_delivered_ptrace, tc) 226 { 227 sigset_t sigset; 228 int signum; 229 int rc; 230 int pipe_ca[2]; 231 int pipe_db[2]; 232 int pipe_cd[2]; 233 char buffer; 234 int status; 235 236 rc = pipe(pipe_ca); 237 ATF_REQUIRE(rc == 0); 238 rc = pipe(pipe_db); 239 ATF_REQUIRE(rc == 0); 240 rc = pipe(pipe_cd); 241 assert(rc == 0); 242 243 rc = fork(); 244 ATF_REQUIRE(rc != -1); 245 if (rc == 0) { 246 pid_t c_pid; 247 248 /* process B */ 249 250 rc = fork(); 251 assert(rc >= 0); 252 if (rc == 0) { 253 /* process C */ 254 signum = SIGINFO; 255 256 /* block signals so we can handle them synchronously */ 257 rc = sigfillset(&sigset); 258 assert(rc == 0); 259 rc = sigprocmask(SIG_SETMASK, &sigset, NULL); 260 assert(rc == 0); 261 262 /* register a dummy handler or the kernel will not queue it */ 263 signal(signum, dummy_signal_handler); 264 265 /* request a signal on parent death and register a handler */ 266 rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum); 267 assert(rc == 0); 268 269 rc = write(pipe_cd[1], "x", 1); 270 assert(rc == 1); 271 272 /* wait for B to die and signal us... */ 273 signum = 0xdeadbeef; 274 rc = sigwait(&sigset, &signum); 275 assert(rc == 0); 276 assert(signum == SIGINFO); 277 278 /* tell A the test passed */ 279 rc = write(pipe_ca[1], ".", 1); 280 assert(rc == 1); 281 _exit(0); 282 } 283 c_pid = rc; 284 285 286 /* fork another process to ptrace C */ 287 rc = fork(); 288 assert(rc >= 0); 289 if (rc == 0) { 290 291 /* process D */ 292 rc = ptrace(PT_ATTACH, c_pid, 0, 0); 293 assert(rc == 0); 294 295 waitpid(c_pid, &status, 0); 296 assert(WIFSTOPPED(status)); 297 assert(WSTOPSIG(status) == SIGSTOP); 298 299 rc = ptrace(PT_CONTINUE, c_pid, (caddr_t) 1, 0); 300 assert(rc == 0); 301 302 rc = read(pipe_cd[0], &buffer, 1); 303 assert(rc == 1); 304 305 /* tell B that we're ready for it to exit now */ 306 rc = write(pipe_db[1], ".", 1); 307 assert(rc == 1); 308 309 waitpid(c_pid, &status, 0); 310 assert(WIFSTOPPED(status)); 311 assert(WSTOPSIG(status) == SIGINFO); 312 313 rc = ptrace(PT_CONTINUE, c_pid, (caddr_t) 1, 314 WSTOPSIG(status)); 315 assert(rc == 0); 316 317 waitpid(c_pid, &status, 0); 318 if (!WIFEXITED(status)) 319 ptrace(PT_DETACH, c_pid, 0, 0); 320 321 _exit(0); 322 } 323 324 /* wait for D to tell us it is ready for us to exit */ 325 rc = read(pipe_db[0], &buffer, 1); 326 assert(rc == 1); 327 328 /* now we exit so that C gets a signal */ 329 _exit(0); 330 } 331 332 /* process A */ 333 334 /* wait for C to tell us the test passed */ 335 rc = read(pipe_ca[0], &buffer, 1); 336 ATF_CHECK_EQ(1, rc); 337 } 338 339 ATF_TP_ADD_TCS(tp) 340 { 341 ATF_TP_ADD_TC(tp, arg_validation); 342 ATF_TP_ADD_TC(tp, fork_no_inherit); 343 ATF_TP_ADD_TC(tp, exec_inherit); 344 ATF_TP_ADD_TC(tp, signal_delivered); 345 ATF_TP_ADD_TC(tp, signal_delivered_ptrace); 346 return (atf_no_error()); 347 } 348