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 303 if (res != 0 && (res != -1 || errno != EPERM)) e(setnum); 304 305 if (res != exp) e(setnum); 306 307 /* Verify that the post-call process state is as expected as well. */ 308 if (res == 0) { 309 if (sub == SUB_EFF) 310 test_uids(set->ruid, set->uid, set->suid); 311 else 312 test_uids(set->uid, set->uid, set->uid); 313 } else 314 test_uids(set->ruid, set->euid, set->suid); 315 } 316 317 /* 318 * Test setuid(2) or seteuid(2) after a successful execve(2) call, which should 319 * have set the process's effective and saved user ID. 320 */ 321 static void 322 exec89a(const char * param1, const char * param2) 323 { 324 const struct uid_set *set; 325 int setnum, sub; 326 327 setnum = atoi(param1); 328 if (setnum < 0 || setnum >= __arraycount(uid_sets)) { 329 e(setnum); 330 return; 331 } 332 set = &uid_sets[setnum]; 333 334 sub = atoi(param2); 335 336 if (sub == SUB_RETAIN) { 337 /* Clear the set-uid bit before dropping more privileges. */ 338 if (chmod(executable, S_IXUSR | S_IXGRP | S_IXOTH) != 0) 339 e(setnum); 340 } 341 342 /* Finish setting up the initial condition. */ 343 if (set->euid != set->suid) { 344 if (set->euid != set->ruid && set->suid != 0) { 345 test_uids(set->ruid, set->suid, set->suid); 346 347 return; /* skip test */ 348 } 349 350 if (seteuid(set->euid) != 0) e(setnum); 351 } 352 353 /* Perform the actual test. */ 354 test_one_uid(setnum, sub); 355 } 356 357 /* 358 * Test setuid(2) or seteuid(2) with a certain value starting from a certain 359 * initial condition, as identified by the given uid_sets[] array element. As 360 * a side effect, test that in particular exec(2) properly sets the effective 361 * and saved user ID. 362 */ 363 static void 364 sub89a(int setnum, int sub) 365 { 366 const struct uid_set *set; 367 char param1[32], param2[32]; 368 369 set = &uid_sets[setnum]; 370 371 /* 372 * Figure out how to set the real, effective, and saved UIDs to those 373 * of the set structure. Without setresuid(2), not all combinations 374 * are possible to achieve. We silently skip the tests for which we 375 * cannot create the requested initial condition. 376 */ 377 if (set->ruid != set->suid) { 378 /* 379 * In order to set the saved UID to something other than the 380 * real UID, we must exec(2) a set-uid binary. 381 */ 382 if (chown(executable, set->suid, 0 /*anything*/) != 0) e(0); 383 if (chmod(executable, 384 S_ISUID | S_IXUSR | S_IXGRP | S_IXOTH) != 0) e(0); 385 386 if (setuid(set->ruid) != 0) e(setnum); 387 388 snprintf(param1, sizeof(param1), "%d", setnum); 389 snprintf(param2, sizeof(param2), "%d", sub); 390 391 (void)execl(executable, executable, "DO CHECK", "a", param1, 392 param2, NULL); 393 394 e(0); 395 } else { 396 /* 397 * If the real and saved user ID are to be set to the same 398 * value, we need not use exec(2). Still, we cannot achieve 399 * all combinations here either. 400 */ 401 if (set->ruid != 0 && set->ruid != set->euid) 402 return; /* skip test */ 403 404 if (sub == SUB_RETAIN) { 405 /* Clear the set-uid bit before dropping privileges. */ 406 if (chmod(executable, 407 S_IXUSR | S_IXGRP | S_IXOTH) != 0) e(setnum); 408 } 409 410 if (setuid(set->ruid) != 0) e(setnum); 411 if (seteuid(set->euid) != 0) e(setnum); 412 413 /* Perform the actual test. */ 414 test_one_uid(setnum, sub); 415 } 416 } 417 418 /* 419 * Test setuid(2) and seteuid(2) calls with various initial conditions, by 420 * setting the real, effective, and saved UIDs to different values before 421 * performing the setuid(2) or seteuid(2) call. 422 */ 423 static void 424 test89a(void) 425 { 426 unsigned int setnum; 427 int sub, status; 428 pid_t pid; 429 430 subtest = 1; 431 432 for (setnum = 0; setnum < __arraycount(uid_sets); setnum++) { 433 for (sub = SUB_REAL; sub <= SUB_EFF; sub++) { 434 pid = fork(); 435 436 switch (pid) { 437 case -1: 438 e(setnum); 439 440 break; 441 442 case 0: 443 errct = 0; 444 445 sub89a((int)setnum, sub); 446 447 exit(errct); 448 /* NOTREACHED */ 449 450 default: 451 if (waitpid(pid, &status, 0) != pid) e(setnum); 452 if (!WIFEXITED(status)) e(setnum); 453 if (WEXITSTATUS(status) != 0) e(setnum); 454 } 455 } 456 } 457 } 458 459 /* 460 * Ensure that the real, effective, and saved UIDs are fully preserved across 461 * fork(2) and non-setuid-binary exec(2) calls. 462 */ 463 static void 464 test89b(void) 465 { 466 unsigned int setnum; 467 int status; 468 pid_t pid; 469 470 subtest = 2; 471 472 for (setnum = 0; setnum < __arraycount(uid_sets); setnum++) { 473 if (uid_sets[setnum].uid != 0) 474 continue; /* no need to do the same test >1 times */ 475 476 pid = fork(); 477 478 switch (pid) { 479 case -1: 480 e(setnum); 481 482 break; 483 484 case 0: 485 errct = 0; 486 487 /* 488 * Test B uses some of the A-test code. While rather 489 * ugly, this avoids duplication of some of test A's 490 * important UID logic. 491 */ 492 sub89a((int)setnum, SUB_RETAIN); 493 494 exit(errct); 495 /* NOTREACHED */ 496 497 default: 498 if (waitpid(pid, &status, 0) != pid) e(setnum); 499 if (!WIFEXITED(status)) e(setnum); 500 if (WEXITSTATUS(status) != 0) e(setnum); 501 } 502 } 503 } 504 505 /* 506 * Verify that the current process's real, effective, and saved group IDs are 507 * set to the given respective value. 508 */ 509 static void 510 test_gids(gid_t rgid, gid_t egid, gid_t sgid) 511 { 512 struct kinfo_proc2 proc2; 513 514 if (getgid() != rgid) e(0); 515 if (getegid() != egid) e(0); 516 517 /* As above. */ 518 if (get_proc2(getpid(), &proc2) != 0) e(0); 519 520 if (proc2.p_rgid != rgid) e(0); 521 if (proc2.p_gid != egid) e(0); 522 if (proc2.p_svgid != sgid) e(0); 523 } 524 525 /* 526 * Verify that the real and effective group IDs are kept as is after an exec(2) 527 * call on a non-setgid binary, and that the saved group ID is set to the 528 * effective group ID. 529 */ 530 static void 531 exec89d(const char * param1, const char * param2 __unused) 532 { 533 const struct gid_set *set; 534 int setnum; 535 536 setnum = atoi(param1); 537 if (setnum < 0 || setnum >= __arraycount(gid_sets)) { 538 e(setnum); 539 return; 540 } 541 set = &gid_sets[setnum]; 542 543 test_gids(set->rgid, set->egid, set->egid); 544 } 545 546 /* 547 * The real, effective, and saved group IDs have been set up as indicated by 548 * the current set. Verify that fork(2) and exec(2) do not change the real and 549 * effective GID, and that only exec(2) sets the saved GID to the effective 550 * GID. 551 */ 552 static void 553 sub89d(int setnum) 554 { 555 const struct gid_set *set; 556 char param1[32]; 557 pid_t pid; 558 int status; 559 560 set = &gid_sets[setnum]; 561 562 pid = fork(); 563 564 switch (pid) { 565 case -1: 566 e(setnum); 567 break; 568 569 case 0: 570 /* 571 * Verify that all the GIDs were retained across the fork(2) 572 * call. 573 */ 574 test_gids(set->rgid, set->egid, set->sgid); 575 576 /* Clear the set-gid bit. */ 577 if (chmod(executable, S_IXUSR | S_IXGRP | S_IXOTH) != 0) 578 e(setnum); 579 580 /* Alternate between preserving and dropping user IDs. */ 581 if (set->gid != 0) { 582 if (setuid(3) != 0) e(setnum); 583 } 584 585 snprintf(param1, sizeof(param1), "%d", setnum); 586 587 (void)execl(executable, executable, "DO CHECK", "d", param1, 588 "", NULL); 589 590 e(setnum); 591 break; 592 593 default: 594 if (waitpid(pid, &status, 0) != pid) e(setnum); 595 if (!WIFEXITED(status)) e(setnum); 596 if (WEXITSTATUS(status) != 0) e(setnum); 597 } 598 } 599 600 /* 601 * The real, effective, and saved group IDs have been set up as indicated by 602 * the current set. Test one particular case for test C or D, and verify the 603 * result. 604 */ 605 static void 606 test_one_gid(int setnum, int sub) 607 { 608 const struct gid_set *set; 609 int res, exp; 610 611 set = &gid_sets[setnum]; 612 613 /* Verify that the pre-call process state is as expected. */ 614 test_gids(set->rgid, set->egid, set->sgid); 615 616 /* Perform the call, and check whether the result is as expected. */ 617 switch (sub) { 618 case SUB_REAL: 619 case SUB_REAL_E0: 620 if (sub != SUB_REAL_E0 && seteuid(1) != 0) e(0); 621 622 res = setgid(set->gid); 623 exp = (sub != SUB_REAL_E0) ? (set->res - 1) : 0; 624 break; 625 626 case SUB_EFF: 627 case SUB_EFF_E0: 628 if (sub != SUB_EFF_E0 && seteuid(1) != 0) e(0); 629 630 res = setegid(set->gid); 631 exp = (sub != SUB_EFF_E0) ? (set->eres - 1) : 0; 632 break; 633 634 case SUB_RETAIN: 635 sub89d(setnum); 636 637 return; 638 } 639 640 if (res != 0 && (res != -1 || errno != EPERM)) e(setnum); 641 642 if (res != exp) e(setnum); 643 644 /* Verify that the post-call process state is as expected as well. */ 645 if (res == 0) { 646 if (sub == SUB_EFF || sub == SUB_EFF_E0) 647 test_gids(set->rgid, set->gid, set->sgid); 648 else 649 test_gids(set->gid, set->gid, set->gid); 650 } else 651 test_gids(set->rgid, set->egid, set->sgid); 652 } 653 654 /* 655 * Test setgid(2) or setegid(2) after a successful execve(2) call, which should 656 * have set the process's effective and saved group ID. 657 */ 658 static void 659 exec89c(const char * param1, const char * param2) 660 { 661 const struct gid_set *set; 662 int setnum, sub; 663 664 setnum = atoi(param1); 665 if (setnum < 0 || setnum >= __arraycount(gid_sets)) { 666 e(setnum); 667 return; 668 } 669 set = &gid_sets[setnum]; 670 671 sub = atoi(param2); 672 673 /* Finish setting up the initial condition. */ 674 if (set->egid != set->sgid && setegid(set->egid) != 0) e(setnum); 675 676 /* Perform the actual test. */ 677 test_one_gid(setnum, sub); 678 } 679 680 /* 681 * Test setgid(2) or setegid(2) with a certain value starting from a certain 682 * initial condition, as identified by the given gid_sets[] array element. As 683 * a side effect, test that in particular exec(2) properly sets the effective 684 * and saved group ID. 685 */ 686 static void 687 sub89c(int setnum, int sub) 688 { 689 const struct gid_set *set; 690 char param1[32], param2[32]; 691 692 set = &gid_sets[setnum]; 693 694 /* 695 * Figure out how to set the real, effective, and saved GIDs to those 696 * of the set structure. In this case, all combinations are possible. 697 */ 698 if (set->rgid != set->sgid) { 699 /* 700 * In order to set the saved GID to something other than the 701 * real GID, we must exec(2) a set-gid binary. 702 */ 703 if (chown(executable, 0 /*anything*/, set->sgid) != 0) e(0); 704 if (chmod(executable, 705 S_ISGID | S_IXUSR | S_IXGRP | S_IXOTH) != 0) e(0); 706 707 if (setgid(set->rgid) != 0) e(setnum); 708 709 snprintf(param1, sizeof(param1), "%d", setnum); 710 snprintf(param2, sizeof(param2), "%d", sub); 711 712 (void)execl(executable, executable, "DO CHECK", "c", param1, 713 param2, NULL); 714 715 e(0); 716 } else { 717 /* 718 * If the real and saved group ID are to be set to the same 719 * value, we need not use exec(2). 720 */ 721 if (setgid(set->rgid) != 0) e(setnum); 722 if (setegid(set->egid) != 0) e(setnum); 723 724 /* Perform the actual test. */ 725 test_one_gid(setnum, sub); 726 } 727 } 728 729 /* 730 * Test setgid(2) and setegid(2) calls with various initial conditions, by 731 * setting the real, effective, and saved GIDs to different values before 732 * performing the setgid(2) or setegid(2) call. At the same time, verify that 733 * if the caller has an effective UID of 0, all set(e)gid calls are allowed. 734 */ 735 static void 736 test89c(void) 737 { 738 unsigned int setnum; 739 int sub, status; 740 pid_t pid; 741 742 subtest = 3; 743 744 for (setnum = 0; setnum < __arraycount(gid_sets); setnum++) { 745 for (sub = SUB_REAL; sub <= SUB_EFF_E0; sub++) { 746 pid = fork(); 747 748 switch (pid) { 749 case -1: 750 e(setnum); 751 752 break; 753 754 case 0: 755 errct = 0; 756 757 sub89c((int)setnum, sub); 758 759 exit(errct); 760 /* NOTREACHED */ 761 762 default: 763 if (waitpid(pid, &status, 0) != pid) e(setnum); 764 if (!WIFEXITED(status)) e(setnum); 765 if (WEXITSTATUS(status) != 0) e(setnum); 766 } 767 } 768 } 769 } 770 771 /* 772 * Ensure that the real, effective, and saved GIDs are fully preserved across 773 * fork(2) and non-setgid-binary exec(2) calls. 774 */ 775 static void 776 test89d(void) 777 { 778 unsigned int setnum; 779 int status; 780 pid_t pid; 781 782 subtest = 4; 783 784 for (setnum = 0; setnum < __arraycount(gid_sets); setnum++) { 785 if (gid_sets[setnum].gid == 2) 786 continue; /* no need to do the same test >1 times */ 787 788 pid = fork(); 789 790 switch (pid) { 791 case -1: 792 e(setnum); 793 794 break; 795 796 case 0: 797 errct = 0; 798 799 /* Similarly, test D uses some of the C-test code. */ 800 sub89c((int)setnum, SUB_RETAIN); 801 802 exit(errct); 803 /* NOTREACHED */ 804 805 default: 806 if (waitpid(pid, &status, 0) != pid) e(setnum); 807 if (!WIFEXITED(status)) e(setnum); 808 if (WEXITSTATUS(status) != 0) e(setnum); 809 } 810 } 811 } 812 813 /* 814 * Either perform the second step of setting up user and group IDs, or check 815 * whether the user and/or group IDs have indeed been changed appropriately as 816 * the result of the second exec(2). 817 */ 818 static void 819 exec89e(const char * param1, const char * param2) 820 { 821 int mask, step; 822 mode_t mode; 823 824 mask = atoi(param1); 825 step = atoi(param2); 826 827 if (step == 0) { 828 mode = S_IXUSR | S_IXGRP | S_IXOTH; 829 if (mask & 1) mode |= S_ISUID; 830 if (mask & 2) mode |= S_ISGID; 831 832 if (chown(executable, 6, 7) != 0) e(0); 833 if (chmod(executable, mode) != 0) e(0); 834 835 if (setegid(4) != 0) e(0); 836 if (seteuid(2) != 0) e(0); 837 838 test_uids(1, 2, 0); 839 test_gids(3, 4, 5); 840 841 (void)execl(executable, executable, "DO CHECK", "e", param1, 842 "1", NULL); 843 844 e(0); 845 } else { 846 if (mask & 1) 847 test_uids(1, 6, 6); 848 else 849 test_uids(1, 2, 2); 850 851 if (mask & 2) 852 test_gids(3, 7, 7); 853 else 854 test_gids(3, 4, 4); 855 } 856 } 857 858 /* 859 * Set up for the set-uid/set-gid execution test by initializing to different 860 * real and effective user IDs. 861 */ 862 static void 863 sub89e(int mask) 864 { 865 char param1[32]; 866 867 if (chown(executable, 0, 5) != 0) e(0); 868 if (chmod(executable, 869 S_ISUID | S_ISGID | S_IXUSR | S_IXGRP | S_IXOTH) != 0) e(0); 870 871 if (setgid(3) != 0) e(0); 872 if (setuid(1) != 0) e(0); 873 874 snprintf(param1, sizeof(param1), "%d", mask); 875 (void)execl(executable, executable, "DO CHECK", "e", param1, "0", 876 NULL); 877 } 878 879 /* 880 * Perform basic verification that the set-uid and set-gid bits on binaries are 881 * fully independent from each other. 882 */ 883 static void 884 test89e(void) 885 { 886 int mask, status; 887 pid_t pid; 888 889 subtest = 5; 890 891 for (mask = 0; mask <= 3; mask++) { 892 pid = fork(); 893 894 switch (pid) { 895 case -1: 896 e(0); 897 898 break; 899 900 case 0: 901 errct = 0; 902 903 sub89e(mask); 904 905 exit(errct); 906 /* NOTREACHED */ 907 908 default: 909 if (waitpid(pid, &status, 0) != pid) e(mask); 910 if (!WIFEXITED(status)) e(mask); 911 if (WEXITSTATUS(status) != 0) e(mask); 912 } 913 } 914 } 915 916 /* 917 * Call the right function after having executed myself. 918 */ 919 static void 920 exec89(const char * param0, const char * param1, const char * param2) 921 { 922 923 switch (param0[0]) { 924 case 'a': 925 exec89a(param1, param2); 926 break; 927 928 case 'b': 929 exec89b(param1, param2); 930 break; 931 932 case 'c': 933 exec89c(param1, param2); 934 break; 935 936 case 'd': 937 exec89d(param1, param2); 938 break; 939 940 case 'e': 941 exec89e(param1, param2); 942 break; 943 944 default: 945 e(0); 946 } 947 948 exit(errct); 949 } 950 951 /* 952 * Initialize the test. 953 */ 954 static void 955 test89_init(void) 956 { 957 char cp_cmd[PATH_MAX + 9]; 958 int status; 959 960 subtest = 0; 961 962 /* Reset all user and group IDs to known values. */ 963 if (setuid(0) != 0) e(0); 964 if (setgid(0) != 0) e(0); 965 if (setgroups(0, NULL) != 0) e(0); 966 967 test_uids(0, 0, 0); 968 test_gids(0, 0, 0); 969 970 /* Make a copy of the binary, which as of start() is one level up. */ 971 snprintf(cp_cmd, sizeof(cp_cmd), "cp ../%s .", executable); 972 973 status = system(cp_cmd); 974 if (status < 0 || !WIFEXITED(status) || 975 WEXITSTATUS(status) != EXIT_SUCCESS) e(0); 976 } 977 978 /* 979 * Test program for set[ug]id, sete[ug]id, and saved IDs. 980 */ 981 int 982 main(int argc, char ** argv) 983 { 984 int i, m; 985 986 executable = argv[0]; 987 988 /* This test executes itself. Handle that case first. */ 989 if (argc == 5 && !strcmp(argv[1], "DO CHECK")) 990 exec89(argv[2], argv[3], argv[4]); 991 992 start(89); 993 994 test89_init(); 995 996 if (argc == 2) 997 m = atoi(argv[1]); 998 else 999 m = 0xFF; 1000 1001 for (i = 0; i < ITERATIONS; i++) { 1002 if (m & 0x01) test89a(); 1003 if (m & 0x02) test89b(); 1004 if (m & 0x04) test89c(); 1005 if (m & 0x08) test89d(); 1006 if (m & 0x10) test89e(); 1007 } 1008 1009 quit(); 1010 /* NOTREACHED */ 1011 } 1012