1 /* Tests for set[ug]id, sete[ug]id, and saved IDs - by D.C. van Moolenbroek */ 2 /* This test must be run as root, as it tests privileged operations. */ 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <sys/stat.h> 6 #include <sys/wait.h> 7 #include <sys/sysctl.h> 8 #include <unistd.h> 9 10 #include "common.h" 11 12 #define ITERATIONS 2 13 14 /* These are in a specific order. */ 15 enum { 16 SUB_REAL, /* test set[ug]id(2) */ 17 SUB_EFF, /* test sete[ug]id(2) */ 18 SUB_REAL_E0, /* test setgid(2) with euid=0 */ 19 SUB_EFF_E0, /* test setegid(2) with euid=0 */ 20 SUB_RETAIN, /* test r/e/s preservation across fork(2), exec(2) */ 21 }; 22 23 static const char *executable; 24 25 /* 26 * The table below is exhaustive in terms of different combinations of real, 27 * effective, and saved user IDs (with 0 being a special value, but 1 and 2 28 * being interchangeable), but not all these combinations can actually be 29 * established in practice. The results for which there is no way to create 30 * the initial condition are set to -1. If we ever implement setresuid(2), 31 * these results can be filled in and tested as well. 32 */ 33 static const struct uid_set { 34 uid_t ruid; 35 uid_t euid; 36 uid_t suid; 37 uid_t uid; 38 int res; 39 int eres; 40 } uid_sets[] = { 41 { 0, 0, 0, 0, 1, 1 }, 42 { 0, 0, 0, 1, 1, 1 }, 43 { 0, 0, 1, 0, 1, 1 }, 44 { 0, 0, 1, 1, 1, 1 }, 45 { 0, 0, 1, 2, 1, 1 }, 46 { 0, 1, 0, 0, 1, 1 }, 47 { 0, 1, 0, 1, 0, 0 }, 48 { 0, 1, 0, 2, 0, 0 }, 49 { 0, 1, 1, 0, 1, 1 }, 50 { 0, 1, 1, 1, 0, 1 }, 51 { 0, 1, 1, 2, 0, 0 }, 52 { 0, 1, 2, 0, -1, -1 }, 53 { 0, 1, 2, 1, -1, -1 }, 54 { 0, 1, 2, 2, -1, -1 }, 55 { 1, 0, 0, 0, 1, 1 }, 56 { 1, 0, 0, 1, 1, 1 }, 57 { 1, 0, 0, 2, 1, 1 }, 58 { 1, 0, 1, 0, -1, -1 }, 59 { 1, 0, 1, 1, -1, -1 }, 60 { 1, 0, 1, 2, -1, -1 }, 61 { 1, 0, 2, 0, -1, -1 }, 62 { 1, 0, 2, 1, -1, -1 }, 63 { 1, 0, 2, 2, -1, -1 }, 64 { 1, 1, 0, 0, 0, 1 }, 65 { 1, 1, 0, 1, 1, 1 }, 66 { 1, 1, 0, 2, 0, 0 }, 67 { 1, 1, 1, 0, 0, 0 }, 68 { 1, 1, 1, 1, 1, 1 }, 69 { 1, 1, 1, 2, 0, 0 }, 70 { 1, 1, 2, 0, 0, 0 }, 71 { 1, 1, 2, 1, 1, 1 }, 72 { 1, 1, 2, 2, 0, 1 }, 73 { 1, 2, 0, 0, 0, 1 }, 74 { 1, 2, 0, 1, 1, 1 }, 75 { 1, 2, 0, 2, 0, 0 }, 76 { 1, 2, 1, 0, -1, -1 }, 77 { 1, 2, 1, 1, -1, -1 }, 78 { 1, 2, 1, 2, -1, -1 }, 79 { 1, 2, 2, 0, 0, 0 }, 80 { 1, 2, 2, 1, 1, 1 }, 81 { 1, 2, 2, 2, 0, 1 }, 82 }; 83 84 /* 85 * The same type of table but now for group identifiers. In this case, all 86 * combinations are possible to establish in practice, because the effective 87 * UID, not the GID, is used for the privilege check. GID 0 does not have any 88 * special meaning, but we still test it as though it does, in order to ensure 89 * that it in fact does not. 90 */ 91 static const struct gid_set { 92 gid_t rgid; 93 gid_t egid; 94 gid_t sgid; 95 gid_t gid; 96 int res; 97 int eres; 98 } gid_sets[] = { 99 { 0, 0, 0, 0, 1, 1 }, 100 { 0, 0, 0, 1, 0, 0 }, 101 { 0, 0, 1, 0, 1, 1 }, 102 { 0, 0, 1, 1, 0, 1 }, 103 { 0, 0, 1, 2, 0, 0 }, 104 { 0, 1, 0, 0, 1, 1 }, 105 { 0, 1, 0, 1, 0, 0 }, 106 { 0, 1, 0, 2, 0, 0 }, 107 { 0, 1, 1, 0, 1, 1 }, 108 { 0, 1, 1, 1, 0, 1 }, 109 { 0, 1, 1, 2, 0, 0 }, 110 { 0, 1, 2, 0, 1, 1 }, 111 { 0, 1, 2, 1, 0, 0 }, 112 { 0, 1, 2, 2, 0, 1 }, 113 { 1, 0, 0, 0, 0, 1 }, 114 { 1, 0, 0, 1, 1, 1 }, 115 { 1, 0, 0, 2, 0, 0 }, 116 { 1, 0, 1, 0, 0, 0 }, 117 { 1, 0, 1, 1, 1, 1 }, 118 { 1, 0, 1, 2, 0, 0 }, 119 { 1, 0, 2, 0, 0, 0 }, 120 { 1, 0, 2, 1, 1, 1 }, 121 { 1, 0, 2, 2, 0, 1 }, 122 { 1, 1, 0, 0, 0, 1 }, 123 { 1, 1, 0, 1, 1, 1 }, 124 { 1, 1, 0, 2, 0, 0 }, 125 { 1, 1, 1, 0, 0, 0 }, 126 { 1, 1, 1, 1, 1, 1 }, 127 { 1, 1, 1, 2, 0, 0 }, 128 { 1, 1, 2, 0, 0, 0 }, 129 { 1, 1, 2, 1, 1, 1 }, 130 { 1, 1, 2, 2, 0, 1 }, 131 { 1, 2, 0, 0, 0, 1 }, 132 { 1, 2, 0, 1, 1, 1 }, 133 { 1, 2, 0, 2, 0, 0 }, 134 { 1, 2, 1, 0, 0, 0 }, 135 { 1, 2, 1, 1, 1, 1 }, 136 { 1, 2, 1, 2, 0, 0 }, 137 { 1, 2, 2, 0, 0, 0 }, 138 { 1, 2, 2, 1, 1, 1 }, 139 { 1, 2, 2, 2, 0, 1 }, 140 }; 141 142 /* 143 * Obtain the kinfo_proc2 data for the given process ID. Return 0 on success, 144 * or -1 with errno set appropriately on failure. 145 */ 146 static int 147 get_proc2(pid_t pid, struct kinfo_proc2 * proc2) 148 { 149 int mib[6]; 150 size_t oldlen; 151 152 /* 153 * FIXME: for performance reasons, the MIB service updates it process 154 * tables only every clock tick. As a result, we may not be able to 155 * obtain accurate process details right away, and we need to wait. 156 * Eventually, the MIB service should retrieve more targeted subsets of 157 * the process tables, and this problem should go away at least for 158 * specific queries such as this one, which queries only a single PID. 159 */ 160 usleep((2000000 + sysconf(_SC_CLK_TCK)) / sysconf(_SC_CLK_TCK)); 161 162 mib[0] = CTL_KERN; 163 mib[1] = KERN_PROC2; 164 mib[2] = KERN_PROC_PID; 165 mib[3] = pid; 166 mib[4] = sizeof(*proc2); 167 mib[5] = 1; 168 169 oldlen = sizeof(*proc2); 170 if (sysctl(mib, __arraycount(mib), proc2, &oldlen, NULL, 0) == -1) 171 return -1; 172 if (oldlen != sizeof(*proc2)) { 173 errno = ESRCH; 174 return -1; 175 } 176 return 0; 177 } 178 179 /* 180 * Verify that the current process's real, effective, and saved user IDs are 181 * set to the given respective value. 182 */ 183 static void 184 test_uids(uid_t ruid, uid_t euid, uid_t suid) 185 { 186 struct kinfo_proc2 proc2; 187 188 if (getuid() != ruid) e(0); 189 if (geteuid() != euid) e(0); 190 191 /* 192 * There is no system call specifically to retrieve the saved user ID, 193 * so we use sysctl(2) to obtain process information. This allows us 194 * to verify the real and effective user IDs once more, too. 195 */ 196 if (get_proc2(getpid(), &proc2) != 0) e(0); 197 198 if (proc2.p_ruid != ruid) e(0); 199 if (proc2.p_uid != euid) e(0); 200 if (proc2.p_svuid != suid) e(0); 201 } 202 203 /* 204 * Verify that the real and effective user IDs are kept as is after an exec(2) 205 * call on a non-setuid binary, and that the saved user ID is set to the 206 * effective user ID. 207 */ 208 static void 209 exec89b(const char * param1, const char * param2 __unused) 210 { 211 const struct uid_set *set; 212 int setnum; 213 214 setnum = atoi(param1); 215 if (setnum < 0 || setnum >= __arraycount(uid_sets)) { 216 e(setnum); 217 return; 218 } 219 set = &uid_sets[setnum]; 220 221 test_uids(set->ruid, set->euid, set->euid); 222 } 223 224 /* 225 * The real, effective, and saved user IDs have been set up as indicated by the 226 * current set. Verify that fork(2) and exec(2) do not change the real and 227 * effective UIDs, and that only exec(2) sets the saved UID to the effective 228 * UID. 229 */ 230 static void 231 sub89b(int setnum) 232 { 233 const struct uid_set *set; 234 char param1[32]; 235 pid_t pid; 236 int status; 237 238 set = &uid_sets[setnum]; 239 240 pid = fork(); 241 242 switch (pid) { 243 case -1: 244 e(setnum); 245 break; 246 247 case 0: 248 /* 249 * Verify that all the UIDs were retained across the fork(2) 250 * call. 251 */ 252 test_uids(set->ruid, set->euid, set->suid); 253 254 snprintf(param1, sizeof(param1), "%d", setnum); 255 256 (void)execl(executable, executable, "DO CHECK", "b", param1, 257 "", NULL); 258 259 e(setnum); 260 break; 261 262 default: 263 if (waitpid(pid, &status, 0) != pid) e(setnum); 264 if (!WIFEXITED(status)) e(setnum); 265 if (WEXITSTATUS(status) != 0) e(setnum); 266 } 267 } 268 269 /* 270 * The real, effective, and saved user IDs have been set up as indicated by the 271 * current set. Test one particular case for test A or B, and verify the 272 * result. 273 */ 274 static void 275 test_one_uid(int setnum, int sub) 276 { 277 const struct uid_set *set; 278 int res, exp; 279 280 set = &uid_sets[setnum]; 281 282 /* Verify that the pre-call process state is as expected. */ 283 test_uids(set->ruid, set->euid, set->suid); 284 285 /* Perform the call, and check whether the result is as expected. */ 286 switch (sub) { 287 case SUB_REAL: 288 res = setuid(set->uid); 289 exp = set->res - 1; 290 break; 291 292 case SUB_EFF: 293 res = seteuid(set->uid); 294 exp = set->eres - 1; 295 break; 296 297 case SUB_RETAIN: 298 sub89b(setnum); 299 300 return; 301 302 default: 303 abort(); 304 } 305 306 if (res != 0 && (res != -1 || errno != EPERM)) e(setnum); 307 308 if (res != exp) e(setnum); 309 310 /* Verify that the post-call process state is as expected as well. */ 311 if (res == 0) { 312 if (sub == SUB_EFF) 313 test_uids(set->ruid, set->uid, set->suid); 314 else 315 test_uids(set->uid, set->uid, set->uid); 316 } else 317 test_uids(set->ruid, set->euid, set->suid); 318 } 319 320 /* 321 * Test setuid(2) or seteuid(2) after a successful execve(2) call, which should 322 * have set the process's effective and saved user ID. 323 */ 324 static void 325 exec89a(const char * param1, const char * param2) 326 { 327 const struct uid_set *set; 328 int setnum, sub; 329 330 setnum = atoi(param1); 331 if (setnum < 0 || setnum >= __arraycount(uid_sets)) { 332 e(setnum); 333 return; 334 } 335 set = &uid_sets[setnum]; 336 337 sub = atoi(param2); 338 339 if (sub == SUB_RETAIN) { 340 /* Clear the set-uid bit before dropping more privileges. */ 341 if (chmod(executable, S_IXUSR | S_IXGRP | S_IXOTH) != 0) 342 e(setnum); 343 } 344 345 /* Finish setting up the initial condition. */ 346 if (set->euid != set->suid) { 347 if (set->euid != set->ruid && set->suid != 0) { 348 test_uids(set->ruid, set->suid, set->suid); 349 350 return; /* skip test */ 351 } 352 353 if (seteuid(set->euid) != 0) e(setnum); 354 } 355 356 /* Perform the actual test. */ 357 test_one_uid(setnum, sub); 358 } 359 360 /* 361 * Test setuid(2) or seteuid(2) with a certain value starting from a certain 362 * initial condition, as identified by the given uid_sets[] array element. As 363 * a side effect, test that in particular exec(2) properly sets the effective 364 * and saved user ID. 365 */ 366 static void 367 sub89a(int setnum, int sub) 368 { 369 const struct uid_set *set; 370 char param1[32], param2[32]; 371 372 set = &uid_sets[setnum]; 373 374 /* 375 * Figure out how to set the real, effective, and saved UIDs to those 376 * of the set structure. Without setresuid(2), not all combinations 377 * are possible to achieve. We silently skip the tests for which we 378 * cannot create the requested initial condition. 379 */ 380 if (set->ruid != set->suid) { 381 /* 382 * In order to set the saved UID to something other than the 383 * real UID, we must exec(2) a set-uid binary. 384 */ 385 if (chown(executable, set->suid, 0 /*anything*/) != 0) e(0); 386 if (chmod(executable, 387 S_ISUID | S_IXUSR | S_IXGRP | S_IXOTH) != 0) e(0); 388 389 if (setuid(set->ruid) != 0) e(setnum); 390 391 snprintf(param1, sizeof(param1), "%d", setnum); 392 snprintf(param2, sizeof(param2), "%d", sub); 393 394 (void)execl(executable, executable, "DO CHECK", "a", param1, 395 param2, NULL); 396 397 e(0); 398 } else { 399 /* 400 * If the real and saved user ID are to be set to the same 401 * value, we need not use exec(2). Still, we cannot achieve 402 * all combinations here either. 403 */ 404 if (set->ruid != 0 && set->ruid != set->euid) 405 return; /* skip test */ 406 407 if (sub == SUB_RETAIN) { 408 /* Clear the set-uid bit before dropping privileges. */ 409 if (chmod(executable, 410 S_IXUSR | S_IXGRP | S_IXOTH) != 0) e(setnum); 411 } 412 413 if (setuid(set->ruid) != 0) e(setnum); 414 if (seteuid(set->euid) != 0) e(setnum); 415 416 /* Perform the actual test. */ 417 test_one_uid(setnum, sub); 418 } 419 } 420 421 /* 422 * Test setuid(2) and seteuid(2) calls with various initial conditions, by 423 * setting the real, effective, and saved UIDs to different values before 424 * performing the setuid(2) or seteuid(2) call. 425 */ 426 static void 427 test89a(void) 428 { 429 unsigned int setnum; 430 int sub, status; 431 pid_t pid; 432 433 subtest = 1; 434 435 for (setnum = 0; setnum < __arraycount(uid_sets); setnum++) { 436 for (sub = SUB_REAL; sub <= SUB_EFF; sub++) { 437 pid = fork(); 438 439 switch (pid) { 440 case -1: 441 e(setnum); 442 443 break; 444 445 case 0: 446 errct = 0; 447 448 sub89a((int)setnum, sub); 449 450 exit(errct); 451 /* NOTREACHED */ 452 453 default: 454 if (waitpid(pid, &status, 0) != pid) e(setnum); 455 if (!WIFEXITED(status)) e(setnum); 456 if (WEXITSTATUS(status) != 0) e(setnum); 457 } 458 } 459 } 460 } 461 462 /* 463 * Ensure that the real, effective, and saved UIDs are fully preserved across 464 * fork(2) and non-setuid-binary exec(2) calls. 465 */ 466 static void 467 test89b(void) 468 { 469 unsigned int setnum; 470 int status; 471 pid_t pid; 472 473 subtest = 2; 474 475 for (setnum = 0; setnum < __arraycount(uid_sets); setnum++) { 476 if (uid_sets[setnum].uid != 0) 477 continue; /* no need to do the same test >1 times */ 478 479 pid = fork(); 480 481 switch (pid) { 482 case -1: 483 e(setnum); 484 485 break; 486 487 case 0: 488 errct = 0; 489 490 /* 491 * Test B uses some of the A-test code. While rather 492 * ugly, this avoids duplication of some of test A's 493 * important UID logic. 494 */ 495 sub89a((int)setnum, SUB_RETAIN); 496 497 exit(errct); 498 /* NOTREACHED */ 499 500 default: 501 if (waitpid(pid, &status, 0) != pid) e(setnum); 502 if (!WIFEXITED(status)) e(setnum); 503 if (WEXITSTATUS(status) != 0) e(setnum); 504 } 505 } 506 } 507 508 /* 509 * Verify that the current process's real, effective, and saved group IDs are 510 * set to the given respective value. 511 */ 512 static void 513 test_gids(gid_t rgid, gid_t egid, gid_t sgid) 514 { 515 struct kinfo_proc2 proc2; 516 517 if (getgid() != rgid) e(0); 518 if (getegid() != egid) e(0); 519 520 /* As above. */ 521 if (get_proc2(getpid(), &proc2) != 0) e(0); 522 523 if (proc2.p_rgid != rgid) e(0); 524 if (proc2.p_gid != egid) e(0); 525 if (proc2.p_svgid != sgid) e(0); 526 } 527 528 /* 529 * Verify that the real and effective group IDs are kept as is after an exec(2) 530 * call on a non-setgid binary, and that the saved group ID is set to the 531 * effective group ID. 532 */ 533 static void 534 exec89d(const char * param1, const char * param2 __unused) 535 { 536 const struct gid_set *set; 537 int setnum; 538 539 setnum = atoi(param1); 540 if (setnum < 0 || setnum >= __arraycount(gid_sets)) { 541 e(setnum); 542 return; 543 } 544 set = &gid_sets[setnum]; 545 546 test_gids(set->rgid, set->egid, set->egid); 547 } 548 549 /* 550 * The real, effective, and saved group IDs have been set up as indicated by 551 * the current set. Verify that fork(2) and exec(2) do not change the real and 552 * effective GID, and that only exec(2) sets the saved GID to the effective 553 * GID. 554 */ 555 static void 556 sub89d(int setnum) 557 { 558 const struct gid_set *set; 559 char param1[32]; 560 pid_t pid; 561 int status; 562 563 set = &gid_sets[setnum]; 564 565 pid = fork(); 566 567 switch (pid) { 568 case -1: 569 e(setnum); 570 break; 571 572 case 0: 573 /* 574 * Verify that all the GIDs were retained across the fork(2) 575 * call. 576 */ 577 test_gids(set->rgid, set->egid, set->sgid); 578 579 /* Clear the set-gid bit. */ 580 if (chmod(executable, S_IXUSR | S_IXGRP | S_IXOTH) != 0) 581 e(setnum); 582 583 /* Alternate between preserving and dropping user IDs. */ 584 if (set->gid != 0) { 585 if (setuid(3) != 0) e(setnum); 586 } 587 588 snprintf(param1, sizeof(param1), "%d", setnum); 589 590 (void)execl(executable, executable, "DO CHECK", "d", param1, 591 "", NULL); 592 593 e(setnum); 594 break; 595 596 default: 597 if (waitpid(pid, &status, 0) != pid) e(setnum); 598 if (!WIFEXITED(status)) e(setnum); 599 if (WEXITSTATUS(status) != 0) e(setnum); 600 } 601 } 602 603 /* 604 * The real, effective, and saved group IDs have been set up as indicated by 605 * the current set. Test one particular case for test C or D, and verify the 606 * result. 607 */ 608 static void 609 test_one_gid(int setnum, int sub) 610 { 611 const struct gid_set *set; 612 int res, exp; 613 614 set = &gid_sets[setnum]; 615 616 /* Verify that the pre-call process state is as expected. */ 617 test_gids(set->rgid, set->egid, set->sgid); 618 619 /* Perform the call, and check whether the result is as expected. */ 620 switch (sub) { 621 case SUB_REAL: 622 case SUB_REAL_E0: 623 if (sub != SUB_REAL_E0 && seteuid(1) != 0) e(0); 624 625 res = setgid(set->gid); 626 exp = (sub != SUB_REAL_E0) ? (set->res - 1) : 0; 627 break; 628 629 case SUB_EFF: 630 case SUB_EFF_E0: 631 if (sub != SUB_EFF_E0 && seteuid(1) != 0) e(0); 632 633 res = setegid(set->gid); 634 exp = (sub != SUB_EFF_E0) ? (set->eres - 1) : 0; 635 break; 636 637 case SUB_RETAIN: 638 sub89d(setnum); 639 640 return; 641 642 default: 643 abort(); 644 } 645 646 if (res != 0 && (res != -1 || errno != EPERM)) e(setnum); 647 648 if (res != exp) e(setnum); 649 650 /* Verify that the post-call process state is as expected as well. */ 651 if (res == 0) { 652 if (sub == SUB_EFF || sub == SUB_EFF_E0) 653 test_gids(set->rgid, set->gid, set->sgid); 654 else 655 test_gids(set->gid, set->gid, set->gid); 656 } else 657 test_gids(set->rgid, set->egid, set->sgid); 658 } 659 660 /* 661 * Test setgid(2) or setegid(2) after a successful execve(2) call, which should 662 * have set the process's effective and saved group ID. 663 */ 664 static void 665 exec89c(const char * param1, const char * param2) 666 { 667 const struct gid_set *set; 668 int setnum, sub; 669 670 setnum = atoi(param1); 671 if (setnum < 0 || setnum >= __arraycount(gid_sets)) { 672 e(setnum); 673 return; 674 } 675 set = &gid_sets[setnum]; 676 677 sub = atoi(param2); 678 679 /* Finish setting up the initial condition. */ 680 if (set->egid != set->sgid && setegid(set->egid) != 0) e(setnum); 681 682 /* Perform the actual test. */ 683 test_one_gid(setnum, sub); 684 } 685 686 /* 687 * Test setgid(2) or setegid(2) with a certain value starting from a certain 688 * initial condition, as identified by the given gid_sets[] array element. As 689 * a side effect, test that in particular exec(2) properly sets the effective 690 * and saved group ID. 691 */ 692 static void 693 sub89c(int setnum, int sub) 694 { 695 const struct gid_set *set; 696 char param1[32], param2[32]; 697 698 set = &gid_sets[setnum]; 699 700 /* 701 * Figure out how to set the real, effective, and saved GIDs to those 702 * of the set structure. In this case, all combinations are possible. 703 */ 704 if (set->rgid != set->sgid) { 705 /* 706 * In order to set the saved GID to something other than the 707 * real GID, we must exec(2) a set-gid binary. 708 */ 709 if (chown(executable, 0 /*anything*/, set->sgid) != 0) e(0); 710 if (chmod(executable, 711 S_ISGID | S_IXUSR | S_IXGRP | S_IXOTH) != 0) e(0); 712 713 if (setgid(set->rgid) != 0) e(setnum); 714 715 snprintf(param1, sizeof(param1), "%d", setnum); 716 snprintf(param2, sizeof(param2), "%d", sub); 717 718 (void)execl(executable, executable, "DO CHECK", "c", param1, 719 param2, NULL); 720 721 e(0); 722 } else { 723 /* 724 * If the real and saved group ID are to be set to the same 725 * value, we need not use exec(2). 726 */ 727 if (setgid(set->rgid) != 0) e(setnum); 728 if (setegid(set->egid) != 0) e(setnum); 729 730 /* Perform the actual test. */ 731 test_one_gid(setnum, sub); 732 } 733 } 734 735 /* 736 * Test setgid(2) and setegid(2) calls with various initial conditions, by 737 * setting the real, effective, and saved GIDs to different values before 738 * performing the setgid(2) or setegid(2) call. At the same time, verify that 739 * if the caller has an effective UID of 0, all set(e)gid calls are allowed. 740 */ 741 static void 742 test89c(void) 743 { 744 unsigned int setnum; 745 int sub, status; 746 pid_t pid; 747 748 subtest = 3; 749 750 for (setnum = 0; setnum < __arraycount(gid_sets); setnum++) { 751 for (sub = SUB_REAL; sub <= SUB_EFF_E0; sub++) { 752 pid = fork(); 753 754 switch (pid) { 755 case -1: 756 e(setnum); 757 758 break; 759 760 case 0: 761 errct = 0; 762 763 sub89c((int)setnum, sub); 764 765 exit(errct); 766 /* NOTREACHED */ 767 768 default: 769 if (waitpid(pid, &status, 0) != pid) e(setnum); 770 if (!WIFEXITED(status)) e(setnum); 771 if (WEXITSTATUS(status) != 0) e(setnum); 772 } 773 } 774 } 775 } 776 777 /* 778 * Ensure that the real, effective, and saved GIDs are fully preserved across 779 * fork(2) and non-setgid-binary exec(2) calls. 780 */ 781 static void 782 test89d(void) 783 { 784 unsigned int setnum; 785 int status; 786 pid_t pid; 787 788 subtest = 4; 789 790 for (setnum = 0; setnum < __arraycount(gid_sets); setnum++) { 791 if (gid_sets[setnum].gid == 2) 792 continue; /* no need to do the same test >1 times */ 793 794 pid = fork(); 795 796 switch (pid) { 797 case -1: 798 e(setnum); 799 800 break; 801 802 case 0: 803 errct = 0; 804 805 /* Similarly, test D uses some of the C-test code. */ 806 sub89c((int)setnum, SUB_RETAIN); 807 808 exit(errct); 809 /* NOTREACHED */ 810 811 default: 812 if (waitpid(pid, &status, 0) != pid) e(setnum); 813 if (!WIFEXITED(status)) e(setnum); 814 if (WEXITSTATUS(status) != 0) e(setnum); 815 } 816 } 817 } 818 819 /* 820 * Either perform the second step of setting up user and group IDs, or check 821 * whether the user and/or group IDs have indeed been changed appropriately as 822 * the result of the second exec(2). 823 */ 824 static void 825 exec89e(const char * param1, const char * param2) 826 { 827 int mask, step; 828 mode_t mode; 829 830 mask = atoi(param1); 831 step = atoi(param2); 832 833 if (step == 0) { 834 mode = S_IXUSR | S_IXGRP | S_IXOTH; 835 if (mask & 1) mode |= S_ISUID; 836 if (mask & 2) mode |= S_ISGID; 837 838 if (chown(executable, 6, 7) != 0) e(0); 839 if (chmod(executable, mode) != 0) e(0); 840 841 if (setegid(4) != 0) e(0); 842 if (seteuid(2) != 0) e(0); 843 844 test_uids(1, 2, 0); 845 test_gids(3, 4, 5); 846 847 (void)execl(executable, executable, "DO CHECK", "e", param1, 848 "1", NULL); 849 850 e(0); 851 } else { 852 if (mask & 1) 853 test_uids(1, 6, 6); 854 else 855 test_uids(1, 2, 2); 856 857 if (mask & 2) 858 test_gids(3, 7, 7); 859 else 860 test_gids(3, 4, 4); 861 } 862 } 863 864 /* 865 * Set up for the set-uid/set-gid execution test by initializing to different 866 * real and effective user IDs. 867 */ 868 static void 869 sub89e(int mask) 870 { 871 char param1[32]; 872 873 if (chown(executable, 0, 5) != 0) e(0); 874 if (chmod(executable, 875 S_ISUID | S_ISGID | S_IXUSR | S_IXGRP | S_IXOTH) != 0) e(0); 876 877 if (setgid(3) != 0) e(0); 878 if (setuid(1) != 0) e(0); 879 880 snprintf(param1, sizeof(param1), "%d", mask); 881 (void)execl(executable, executable, "DO CHECK", "e", param1, "0", 882 NULL); 883 } 884 885 /* 886 * Perform basic verification that the set-uid and set-gid bits on binaries are 887 * fully independent from each other. 888 */ 889 static void 890 test89e(void) 891 { 892 int mask, status; 893 pid_t pid; 894 895 subtest = 5; 896 897 for (mask = 0; mask <= 3; mask++) { 898 pid = fork(); 899 900 switch (pid) { 901 case -1: 902 e(0); 903 904 break; 905 906 case 0: 907 errct = 0; 908 909 sub89e(mask); 910 911 exit(errct); 912 /* NOTREACHED */ 913 914 default: 915 if (waitpid(pid, &status, 0) != pid) e(mask); 916 if (!WIFEXITED(status)) e(mask); 917 if (WEXITSTATUS(status) != 0) e(mask); 918 } 919 } 920 } 921 922 /* 923 * Call the right function after having executed myself. 924 */ 925 static void 926 exec89(const char * param0, const char * param1, const char * param2) 927 { 928 929 switch (param0[0]) { 930 case 'a': 931 exec89a(param1, param2); 932 break; 933 934 case 'b': 935 exec89b(param1, param2); 936 break; 937 938 case 'c': 939 exec89c(param1, param2); 940 break; 941 942 case 'd': 943 exec89d(param1, param2); 944 break; 945 946 case 'e': 947 exec89e(param1, param2); 948 break; 949 950 default: 951 e(0); 952 } 953 954 exit(errct); 955 } 956 957 /* 958 * Initialize the test. 959 */ 960 static void 961 test89_init(void) 962 { 963 char cp_cmd[PATH_MAX + 9]; 964 int status; 965 966 subtest = 0; 967 968 /* Reset all user and group IDs to known values. */ 969 if (setuid(0) != 0) e(0); 970 if (setgid(0) != 0) e(0); 971 if (setgroups(0, NULL) != 0) e(0); 972 973 test_uids(0, 0, 0); 974 test_gids(0, 0, 0); 975 976 /* Make a copy of the binary, which as of start() is one level up. */ 977 snprintf(cp_cmd, sizeof(cp_cmd), "cp ../%s .", executable); 978 979 status = system(cp_cmd); 980 if (status < 0 || !WIFEXITED(status) || 981 WEXITSTATUS(status) != EXIT_SUCCESS) e(0); 982 } 983 984 /* 985 * Test program for set[ug]id, sete[ug]id, and saved IDs. 986 */ 987 int 988 main(int argc, char ** argv) 989 { 990 int i, m; 991 992 executable = argv[0]; 993 994 /* This test executes itself. Handle that case first. */ 995 if (argc == 5 && !strcmp(argv[1], "DO CHECK")) 996 exec89(argv[2], argv[3], argv[4]); 997 998 start(89); 999 1000 test89_init(); 1001 1002 if (argc == 2) 1003 m = atoi(argv[1]); 1004 else 1005 m = 0xFF; 1006 1007 for (i = 0; i < ITERATIONS; i++) { 1008 if (m & 0x01) test89a(); 1009 if (m & 0x02) test89b(); 1010 if (m & 0x04) test89c(); 1011 if (m & 0x08) test89d(); 1012 if (m & 0x10) test89e(); 1013 } 1014 1015 quit(); 1016 /* NOTREACHED */ 1017 } 1018