1274f7445SRobert Watson /*- 2274f7445SRobert Watson * Copyright (c) 2001 Robert N. M. Watson 3274f7445SRobert Watson * All rights reserved. 4274f7445SRobert Watson * 5274f7445SRobert Watson * Redistribution and use in source and binary forms, with or without 6274f7445SRobert Watson * modification, are permitted provided that the following conditions 7274f7445SRobert Watson * are met: 8274f7445SRobert Watson * 1. Redistributions of source code must retain the above copyright 9274f7445SRobert Watson * notice, this list of conditions and the following disclaimer. 10274f7445SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 11274f7445SRobert Watson * notice, this list of conditions and the following disclaimer in the 12274f7445SRobert Watson * documentation and/or other materials provided with the distribution. 13274f7445SRobert Watson * 14274f7445SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15274f7445SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16274f7445SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17274f7445SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18274f7445SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19274f7445SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20274f7445SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21274f7445SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22274f7445SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23274f7445SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24274f7445SRobert Watson * SUCH DAMAGE. 25274f7445SRobert Watson * 26274f7445SRobert Watson * $FreeBSD$ 27274f7445SRobert Watson */ 28274f7445SRobert Watson 29274f7445SRobert Watson #include <sys/types.h> 30274f7445SRobert Watson #include <sys/ptrace.h> 31274f7445SRobert Watson #include <sys/time.h> 32274f7445SRobert Watson #include <sys/resource.h> 33274f7445SRobert Watson #include <sys/syscall.h> 34274f7445SRobert Watson #include <sys/wait.h> 35274f7445SRobert Watson 36274f7445SRobert Watson #include <assert.h> 37274f7445SRobert Watson #include <errno.h> 38274f7445SRobert Watson #include <signal.h> 39274f7445SRobert Watson #include <stdio.h> 40274f7445SRobert Watson #include <string.h> 41274f7445SRobert Watson #include <unistd.h> 42274f7445SRobert Watson 43274f7445SRobert Watson /* 44274f7445SRobert Watson * Relevant parts of a process credential. 45274f7445SRobert Watson */ 46274f7445SRobert Watson struct cred { 47274f7445SRobert Watson uid_t cr_euid, cr_ruid, cr_svuid; 48274f7445SRobert Watson int cr_issetugid; 49274f7445SRobert Watson }; 50274f7445SRobert Watson 51274f7445SRobert Watson /* 52274f7445SRobert Watson * Description of a scenario. 53274f7445SRobert Watson */ 54274f7445SRobert Watson struct scenario { 55274f7445SRobert Watson struct cred *sc_cred1, *sc_cred2; /* credentials of p1 and p2 */ 56274f7445SRobert Watson int sc_candebug_errno; /* desired ptrace failure */ 57274f7445SRobert Watson int sc_cansignal_errno; /* desired SIGHUP failure */ 58274f7445SRobert Watson int sc_cansee_errno; /* desired getprio failure */ 59274f7445SRobert Watson int sc_cansched_errno; /* desired setprio failure */ 60274f7445SRobert Watson char *sc_name; /* test name */ 61274f7445SRobert Watson }; 62274f7445SRobert Watson 63274f7445SRobert Watson /* 64274f7445SRobert Watson * Table of relevant credential combinations. 65274f7445SRobert Watson */ 66274f7445SRobert Watson static struct cred creds[] = { 67274f7445SRobert Watson /* euid ruid svuid issetugid */ 68274f7445SRobert Watson /* 0 */ { 0, 0, 0, 0 }, /* privileged */ 69274f7445SRobert Watson /* 1 */ { 0, 0, 0, 1 }, /* privileged + issetugid */ 70274f7445SRobert Watson /* 2 */ { 1000, 1000, 1000, 0 }, /* unprivileged1 */ 71274f7445SRobert Watson /* 3 */ { 1000, 1000, 1000, 1 }, /* unprivileged1 + issetugid */ 72274f7445SRobert Watson /* 4 */ { 1001, 1001, 1001, 0 }, /* unprivileged2 */ 73274f7445SRobert Watson /* 5 */ { 1001, 1001, 1001, 1 }, /* unprivileged2 + issetugid */ 74274f7445SRobert Watson /* 6 */ { 1000, 0, 0, 0 }, /* daemon1 */ 75274f7445SRobert Watson /* 7 */ { 1000, 0, 0, 1 }, /* daemon1 + issetugid */ 76274f7445SRobert Watson /* 8 */ { 1001, 0, 0, 0 }, /* daemon2 */ 77274f7445SRobert Watson /* 9 */ { 1001, 0, 0, 1 }, /* daemon2 + issetugid */ 78274f7445SRobert Watson /* 10 */{ 0, 1000, 1000, 0 }, /* setuid1 */ 79274f7445SRobert Watson /* 11 */{ 0, 1000, 1000, 1 }, /* setuid1 + issetugid */ 80274f7445SRobert Watson /* 12 */{ 0, 1001, 1001, 0 }, /* setuid2 */ 81274f7445SRobert Watson /* 13 */{ 0, 1001, 1001, 1 }, /* setuid2 + issetugid */ 82274f7445SRobert Watson }; 83274f7445SRobert Watson 84274f7445SRobert Watson /* 85274f7445SRobert Watson * Table of scenarios. 86274f7445SRobert Watson */ 87274f7445SRobert Watson static const struct scenario scenarios[] = { 88274f7445SRobert Watson /* cred1 cred2 debug signal see sched name */ 89274f7445SRobert Watson { &creds[0], &creds[0], 0, 0, 0, 0, "0. priv on priv"}, 90274f7445SRobert Watson { &creds[0], &creds[1], 0, 0, 0, 0, "1. priv on priv"}, 91274f7445SRobert Watson { &creds[1], &creds[0], 0, 0, 0, 0, "2. priv on priv"}, 92274f7445SRobert Watson { &creds[1], &creds[1], 0, 0, 0, 0, "3. priv on priv"}, 93274f7445SRobert Watson /* privileged on unprivileged */ 94274f7445SRobert Watson { &creds[0], &creds[2], 0, 0, 0, 0, "4. priv on unpriv1"}, 95274f7445SRobert Watson { &creds[0], &creds[3], 0, 0, 0, 0, "5. priv on unpriv1"}, 96274f7445SRobert Watson { &creds[1], &creds[2], 0, 0, 0, 0, "6. priv on unpriv1"}, 97274f7445SRobert Watson { &creds[1], &creds[3], 0, 0, 0, 0, "7. priv on unpriv1"}, 98274f7445SRobert Watson /* unprivileged on privileged */ 99274f7445SRobert Watson { &creds[2], &creds[0], EPERM, EPERM, 0, EPERM, "8. unpriv1 on priv"}, 100274f7445SRobert Watson { &creds[2], &creds[1], EPERM, EPERM, 0, EPERM, "9. unpriv1 on priv"}, 101274f7445SRobert Watson { &creds[3], &creds[0], EPERM, EPERM, 0, EPERM, "10. unpriv1 on priv"}, 102274f7445SRobert Watson { &creds[3], &creds[1], EPERM, EPERM, 0, EPERM, "11. unpriv1 on priv"}, 103274f7445SRobert Watson /* unprivileged on same unprivileged */ 104274f7445SRobert Watson { &creds[2], &creds[2], 0, 0, 0, 0, "12. unpriv1 on unpriv1"}, 105274f7445SRobert Watson { &creds[2], &creds[3], EPERM, 0, 0, 0, "13. unpriv1 on unpriv1"}, 106274f7445SRobert Watson { &creds[3], &creds[2], 0, 0, 0, 0, "14. unpriv1 on unpriv1"}, 107274f7445SRobert Watson { &creds[3], &creds[3], EPERM, 0, 0, 0, "15. unpriv1 on unpriv1"}, 108274f7445SRobert Watson /* unprivileged on different unprivileged */ 109274f7445SRobert Watson { &creds[2], &creds[4], EPERM, EPERM, 0, EPERM, "16. unpriv1 on unpriv2"}, 110274f7445SRobert Watson { &creds[2], &creds[5], EPERM, EPERM, 0, EPERM, "17. unpriv1 on unpriv2"}, 111274f7445SRobert Watson { &creds[3], &creds[4], EPERM, EPERM, 0, EPERM, "18. unpriv1 on unpriv2"}, 112274f7445SRobert Watson { &creds[3], &creds[5], EPERM, EPERM, 0, EPERM, "19. unpriv1 on unpriv2"}, 113274f7445SRobert Watson /* unprivileged on daemon, same */ 114274f7445SRobert Watson { &creds[2], &creds[6], EPERM, EPERM, 0, EPERM, "20. unpriv1 on daemon1"}, 115274f7445SRobert Watson { &creds[2], &creds[7], EPERM, EPERM, 0, EPERM, "21. unpriv1 on daemon1"}, 116274f7445SRobert Watson { &creds[3], &creds[6], EPERM, EPERM, 0, EPERM, "22. unpriv1 on daemon1"}, 117274f7445SRobert Watson { &creds[3], &creds[7], EPERM, EPERM, 0, EPERM, "23. unpriv1 on daemon1"}, 118274f7445SRobert Watson /* unprivileged on daemon, different */ 119274f7445SRobert Watson { &creds[2], &creds[8], EPERM, EPERM, 0, EPERM, "24. unpriv1 on daemon2"}, 120274f7445SRobert Watson { &creds[2], &creds[9], EPERM, EPERM, 0, EPERM, "25. unpriv1 on daemon2"}, 121274f7445SRobert Watson { &creds[3], &creds[8], EPERM, EPERM, 0, EPERM, "26. unpriv1 on daemon2"}, 122274f7445SRobert Watson { &creds[3], &creds[9], EPERM, EPERM, 0, EPERM, "27. unpriv1 on daemon2"}, 123274f7445SRobert Watson /* unprivileged on setuid, same */ 124274f7445SRobert Watson { &creds[2], &creds[10], EPERM, 0, 0, 0, "28. unpriv1 on setuid1"}, 125274f7445SRobert Watson { &creds[2], &creds[11], EPERM, 0, 0, 0, "29. unpriv1 on setuid1"}, 126274f7445SRobert Watson { &creds[3], &creds[10], EPERM, 0, 0, 0, "30. unpriv1 on setuid1"}, 127274f7445SRobert Watson { &creds[3], &creds[11], EPERM, 0, 0, 0, "31. unpriv1 on setuid1"}, 128274f7445SRobert Watson /* unprivileged on setuid, different */ 129274f7445SRobert Watson { &creds[2], &creds[12], EPERM, EPERM, 0, EPERM, "32. unpriv1 on setuid2"}, 130274f7445SRobert Watson { &creds[2], &creds[13], EPERM, EPERM, 0, EPERM, "33. unpriv1 on setuid2"}, 131274f7445SRobert Watson { &creds[3], &creds[12], EPERM, EPERM, 0, EPERM, "34. unpriv1 on setuid2"}, 132274f7445SRobert Watson { &creds[3], &creds[13], EPERM, EPERM, 0, EPERM, "35. unpriv1 on setuid2"}, 133274f7445SRobert Watson }; 134274f7445SRobert Watson int scenarios_count = sizeof(scenarios) / sizeof(struct scenario); 135274f7445SRobert Watson 136274f7445SRobert Watson /* 137274f7445SRobert Watson * Convert an error number to a compact string representation. For now, 138274f7445SRobert Watson * implement only the error numbers we are likely to see. 139274f7445SRobert Watson */ 140274f7445SRobert Watson static char * 141274f7445SRobert Watson errno_to_string(int error) 142274f7445SRobert Watson { 143274f7445SRobert Watson 144274f7445SRobert Watson switch (error) { 145274f7445SRobert Watson case EPERM: 146274f7445SRobert Watson return ("EPERM"); 147274f7445SRobert Watson case EACCES: 148274f7445SRobert Watson return ("EACCES"); 149274f7445SRobert Watson case EINVAL: 150274f7445SRobert Watson return ("EINVAL"); 151274f7445SRobert Watson case ENOSYS: 152274f7445SRobert Watson return ("ENOSYS"); 153274f7445SRobert Watson case ESRCH: 154274f7445SRobert Watson return ("ESRCH"); 155274f7445SRobert Watson case 0: 156274f7445SRobert Watson return ("0"); 157274f7445SRobert Watson default: 158274f7445SRobert Watson return ("unknown"); 159274f7445SRobert Watson } 160274f7445SRobert Watson } 161274f7445SRobert Watson 162274f7445SRobert Watson /* 163274f7445SRobert Watson * Return a process credential describing the current process. 164274f7445SRobert Watson */ 165274f7445SRobert Watson static int 166274f7445SRobert Watson cred_get(struct cred *cred) 167274f7445SRobert Watson { 168274f7445SRobert Watson int error; 169274f7445SRobert Watson 170274f7445SRobert Watson error = getresuid(&cred->cr_ruid, &cred->cr_euid, &cred->cr_svuid); 171274f7445SRobert Watson if (error) 172274f7445SRobert Watson return (error); 173274f7445SRobert Watson 174274f7445SRobert Watson cred->cr_issetugid = issetugid(); 175274f7445SRobert Watson 176274f7445SRobert Watson return (0); 177274f7445SRobert Watson } 178274f7445SRobert Watson 179274f7445SRobert Watson /* 180274f7445SRobert Watson * Userland stub for __setsugid() to take into account possible presence 181274f7445SRobert Watson * in C library, kernel, et al. 182274f7445SRobert Watson */ 183274f7445SRobert Watson int 184274f7445SRobert Watson setugid(int flag) 185274f7445SRobert Watson { 186274f7445SRobert Watson 187274f7445SRobert Watson #ifdef SETSUGID_SUPPORTED 188274f7445SRobert Watson return (__setugid(flag)); 189274f7445SRobert Watson #else 190274f7445SRobert Watson #ifdef SETSUGID_SUPPORTED_BUT_NO_LIBC_STUB 191274f7445SRobert Watson return (syscall(374, flag)); 192274f7445SRobert Watson #else 193274f7445SRobert Watson return (ENOSYS); 194274f7445SRobert Watson #endif 195274f7445SRobert Watson #endif 196274f7445SRobert Watson } 197274f7445SRobert Watson 198274f7445SRobert Watson /* 199274f7445SRobert Watson * Set the current process's credentials to match the passed credential. 200274f7445SRobert Watson */ 201274f7445SRobert Watson static int 202274f7445SRobert Watson cred_set(struct cred *cred) 203274f7445SRobert Watson { 204274f7445SRobert Watson int error; 205274f7445SRobert Watson 206274f7445SRobert Watson error = setresuid(cred->cr_ruid, cred->cr_euid, cred->cr_svuid); 207274f7445SRobert Watson if (error) 208274f7445SRobert Watson return (error); 209274f7445SRobert Watson 210274f7445SRobert Watson error = setugid(cred->cr_issetugid); 211274f7445SRobert Watson if (error) { 212274f7445SRobert Watson perror("__setugid"); 213274f7445SRobert Watson return (error); 214274f7445SRobert Watson } 215274f7445SRobert Watson 216274f7445SRobert Watson #ifdef CHECK_CRED_SET 217274f7445SRobert Watson { 218274f7445SRobert Watson uid_t ruid, euid, svuid; 219274f7445SRobert Watson error = getresuid(&ruid, &euid, &svuid); 220274f7445SRobert Watson if (error) { 221274f7445SRobert Watson perror("getresuid"); 222274f7445SRobert Watson return (-1); 223274f7445SRobert Watson } 224274f7445SRobert Watson assert(ruid == cred->cr_ruid); 225274f7445SRobert Watson assert(euid == cred->cr_euid); 226274f7445SRobert Watson assert(svuid == cred->cr_svuid); 227274f7445SRobert Watson assert(cred->cr_issetugid == issetugid()); 228274f7445SRobert Watson } 229274f7445SRobert Watson #endif /* !CHECK_CRED_SET */ 230274f7445SRobert Watson 231274f7445SRobert Watson return (0); 232274f7445SRobert Watson } 233274f7445SRobert Watson 234274f7445SRobert Watson /* 235274f7445SRobert Watson * Print the passed process credential to the passed I/O stream. 236274f7445SRobert Watson */ 237274f7445SRobert Watson static void 238274f7445SRobert Watson cred_print(FILE *output, struct cred *cred) 239274f7445SRobert Watson { 240274f7445SRobert Watson 241274f7445SRobert Watson fprintf(output, "(e:%d r:%d s:%d P_SUGID:%d)", cred->cr_euid, 242274f7445SRobert Watson cred->cr_ruid, cred->cr_svuid, cred->cr_issetugid); 243274f7445SRobert Watson } 244274f7445SRobert Watson 245274f7445SRobert Watson #define LOOP_PTRACE 0 246274f7445SRobert Watson #define LOOP_SIGNAL 1 247274f7445SRobert Watson #define LOOP_SEE 2 248274f7445SRobert Watson #define LOOP_SCHED 3 249274f7445SRobert Watson #define LOOP_MAX LOOP_SCHED 250274f7445SRobert Watson 251274f7445SRobert Watson /* 252274f7445SRobert Watson * Enact a scenario by looping through the four test cases for the scenario, 253274f7445SRobert Watson * spawning off pairs of processes with the desired credentials, and 254274f7445SRobert Watson * reporting results to stdout. 255274f7445SRobert Watson */ 256274f7445SRobert Watson static int 257274f7445SRobert Watson enact_scenario(int scenario) 258274f7445SRobert Watson { 259274f7445SRobert Watson pid_t pid1, pid2; 260274f7445SRobert Watson char *name; 261274f7445SRobert Watson int error, desirederror, loop; 262274f7445SRobert Watson 263274f7445SRobert Watson for (loop = 0; loop < LOOP_MAX+1; loop++) { 264274f7445SRobert Watson /* 265274f7445SRobert Watson * Spawn the first child, target of the operation. 266274f7445SRobert Watson */ 267274f7445SRobert Watson pid1 = fork(); 268274f7445SRobert Watson switch (pid1) { 269274f7445SRobert Watson case -1: 270274f7445SRobert Watson return (-1); 271274f7445SRobert Watson case 0: 272274f7445SRobert Watson /* child */ 273274f7445SRobert Watson error = cred_set(scenarios[scenario].sc_cred2); 274274f7445SRobert Watson if (error) { 275274f7445SRobert Watson perror("cred_set"); 276274f7445SRobert Watson return (error); 277274f7445SRobert Watson } 278274f7445SRobert Watson /* 200 seconds should be plenty of time. */ 279274f7445SRobert Watson sleep(200); 280274f7445SRobert Watson exit(0); 281274f7445SRobert Watson default: 282274f7445SRobert Watson /* parent */ 283274f7445SRobert Watson } 284274f7445SRobert Watson 285274f7445SRobert Watson /* 286274f7445SRobert Watson * XXX 287274f7445SRobert Watson * This really isn't ideal -- give proc 1 a chance to set 288274f7445SRobert Watson * its credentials, or we may get spurious errors. Really, 289274f7445SRobert Watson * some for of IPC should be used to allow the parent to 290274f7445SRobert Watson * wait for the first child to be ready before spawning 291274f7445SRobert Watson * the second child. 292274f7445SRobert Watson */ 293274f7445SRobert Watson sleep(1); 294274f7445SRobert Watson 295274f7445SRobert Watson /* 296274f7445SRobert Watson * Spawn the second child, source of the operation. 297274f7445SRobert Watson */ 298274f7445SRobert Watson pid2 = fork(); 299274f7445SRobert Watson switch (pid2) { 300274f7445SRobert Watson case -1: 301274f7445SRobert Watson return (-1); 302274f7445SRobert Watson 303274f7445SRobert Watson case 0: 304274f7445SRobert Watson /* child */ 305274f7445SRobert Watson error = cred_set(scenarios[scenario].sc_cred1); 306274f7445SRobert Watson if (error) { 307274f7445SRobert Watson perror("cred_set"); 308274f7445SRobert Watson return (error); 309274f7445SRobert Watson } 310274f7445SRobert Watson 311274f7445SRobert Watson /* 312274f7445SRobert Watson * Initialize errno to zero so as to catch any 313274f7445SRobert Watson * generated errors. In each case, perform the 314274f7445SRobert Watson * operation. Preserve the error number for later 315274f7445SRobert Watson * use so it doesn't get stomped on by any I/O. 316274f7445SRobert Watson * Determine the desired error for the given case 317274f7445SRobert Watson * by extracting it from the scenario table. 318274f7445SRobert Watson * Initialize a function name string for output 319274f7445SRobert Watson * prettiness. 320274f7445SRobert Watson */ 321274f7445SRobert Watson errno = 0; 322274f7445SRobert Watson switch (loop) { 323274f7445SRobert Watson case LOOP_PTRACE: 324274f7445SRobert Watson error = ptrace(PT_ATTACH, pid1, NULL, 0); 325274f7445SRobert Watson error = errno; 326274f7445SRobert Watson name = "ptrace"; 327274f7445SRobert Watson desirederror = 328274f7445SRobert Watson scenarios[scenario].sc_candebug_errno; 329274f7445SRobert Watson break; 330274f7445SRobert Watson case LOOP_SIGNAL: 331274f7445SRobert Watson error = kill(pid1, SIGHUP); 332274f7445SRobert Watson error = errno; 333274f7445SRobert Watson name = "signal"; 334274f7445SRobert Watson desirederror = 335274f7445SRobert Watson scenarios[scenario].sc_cansignal_errno; 336274f7445SRobert Watson break; 337274f7445SRobert Watson case LOOP_SEE: 338274f7445SRobert Watson getpriority(PRIO_PROCESS, pid1); 339274f7445SRobert Watson error = errno; 340274f7445SRobert Watson name = "see"; 341274f7445SRobert Watson desirederror = 342274f7445SRobert Watson scenarios[scenario].sc_cansee_errno; 343274f7445SRobert Watson break; 344274f7445SRobert Watson case LOOP_SCHED: 345274f7445SRobert Watson error = setpriority(PRIO_PROCESS, pid1, 346274f7445SRobert Watson 0); 347274f7445SRobert Watson error = errno; 348274f7445SRobert Watson name = "sched"; 349274f7445SRobert Watson desirederror = 350274f7445SRobert Watson scenarios[scenario].sc_cansched_errno; 351274f7445SRobert Watson break; 352274f7445SRobert Watson default: 353274f7445SRobert Watson name = "broken"; 354274f7445SRobert Watson } 355274f7445SRobert Watson 356274f7445SRobert Watson if (error != desirederror) { 357274f7445SRobert Watson fprintf(stdout, 358274f7445SRobert Watson "[%s].%s: expected %s, got %s\n ", 359274f7445SRobert Watson scenarios[scenario].sc_name, name, 360274f7445SRobert Watson errno_to_string(desirederror), 361274f7445SRobert Watson errno_to_string(error)); 362274f7445SRobert Watson cred_print(stdout, 363274f7445SRobert Watson scenarios[scenario].sc_cred1); 364274f7445SRobert Watson cred_print(stdout, 365274f7445SRobert Watson scenarios[scenario].sc_cred2); 366274f7445SRobert Watson fprintf(stdout, "\n"); 367274f7445SRobert Watson } 368274f7445SRobert Watson 369274f7445SRobert Watson exit(0); 370274f7445SRobert Watson 371274f7445SRobert Watson default: 372274f7445SRobert Watson /* parent */ 373274f7445SRobert Watson } 374274f7445SRobert Watson 375274f7445SRobert Watson error = waitpid(pid2, NULL, 0); 376274f7445SRobert Watson /* 377274f7445SRobert Watson * Once pid2 has died, it's safe to kill pid1, if it's still 378274f7445SRobert Watson * alive. Mask signal failure in case the test actually 379274f7445SRobert Watson * killed pid1 (not unlikely: can occur in both signal and 380274f7445SRobert Watson * ptrace cases). 381274f7445SRobert Watson */ 382274f7445SRobert Watson kill(pid1, SIGKILL); 383274f7445SRobert Watson error = waitpid(pid2, NULL, 0); 384274f7445SRobert Watson } 385274f7445SRobert Watson 386274f7445SRobert Watson return (0); 387274f7445SRobert Watson } 388274f7445SRobert Watson 389274f7445SRobert Watson void 390274f7445SRobert Watson enact_scenarios(void) 391274f7445SRobert Watson { 392274f7445SRobert Watson int i, error; 393274f7445SRobert Watson 394274f7445SRobert Watson for (i = 0; i < scenarios_count; i++) { 395274f7445SRobert Watson error = enact_scenario(i); 396274f7445SRobert Watson if (error) 397274f7445SRobert Watson perror("enact_scenario"); 398274f7445SRobert Watson } 399274f7445SRobert Watson } 400