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
get_proc2(pid_t pid,struct kinfo_proc2 * proc2)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
test_uids(uid_t ruid,uid_t euid,uid_t suid)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
exec89b(const char * param1,const char * param2 __unused)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
sub89b(int setnum)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
test_one_uid(int setnum,int sub)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
exec89a(const char * param1,const char * param2)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
sub89a(int setnum,int sub)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
test89a(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
test89b(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
test_gids(gid_t rgid,gid_t egid,gid_t sgid)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
exec89d(const char * param1,const char * param2 __unused)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
sub89d(int setnum)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
test_one_gid(int setnum,int sub)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
exec89c(const char * param1,const char * param2)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
sub89c(int setnum,int sub)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
test89c(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
test89d(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
exec89e(const char * param1,const char * param2)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
sub89e(int mask)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
test89e(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
exec89(const char * param0,const char * param1,const char * param2)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
test89_init(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
main(int argc,char ** argv)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