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. */
7 #include <sys/sysctl.h>
14 /* These are in a specific order. */
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) */
23 static const char *executable
;
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.
33 static const struct uid_set
{
52 { 0, 1, 2, 0, -1, -1 },
53 { 0, 1, 2, 1, -1, -1 },
54 { 0, 1, 2, 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 },
76 { 1, 2, 1, 0, -1, -1 },
77 { 1, 2, 1, 1, -1, -1 },
78 { 1, 2, 1, 2, -1, -1 },
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.
91 static const struct gid_set
{
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 },
143 * Obtain the kinfo_proc2 data for the given process ID. Return 0 on success,
144 * or -1 with errno set appropriately on failure.
147 get_proc2(pid_t pid
, struct kinfo_proc2
* proc2
)
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.
160 usleep((2000000 + sysconf(_SC_CLK_TCK
)) / sysconf(_SC_CLK_TCK
));
164 mib
[2] = KERN_PROC_PID
;
166 mib
[4] = sizeof(*proc2
);
169 oldlen
= sizeof(*proc2
);
170 if (sysctl(mib
, __arraycount(mib
), proc2
, &oldlen
, NULL
, 0) == -1)
172 if (oldlen
!= sizeof(*proc2
)) {
180 * Verify that the current process's real, effective, and saved user IDs are
181 * set to the given respective value.
184 test_uids(uid_t ruid
, uid_t euid
, uid_t suid
)
186 struct kinfo_proc2 proc2
;
188 if (getuid() != ruid
) e(0);
189 if (geteuid() != euid
) e(0);
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.
196 if (get_proc2(getpid(), &proc2
) != 0) e(0);
198 if (proc2
.p_ruid
!= ruid
) e(0);
199 if (proc2
.p_uid
!= euid
) e(0);
200 if (proc2
.p_svuid
!= suid
) e(0);
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
209 exec89b(const char * param1
, const char * param2 __unused
)
211 const struct uid_set
*set
;
214 setnum
= atoi(param1
);
215 if (setnum
< 0 || setnum
>= __arraycount(uid_sets
)) {
219 set
= &uid_sets
[setnum
];
221 test_uids(set
->ruid
, set
->euid
, set
->euid
);
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
233 const struct uid_set
*set
;
238 set
= &uid_sets
[setnum
];
249 * Verify that all the UIDs were retained across the fork(2)
252 test_uids(set
->ruid
, set
->euid
, set
->suid
);
254 snprintf(param1
, sizeof(param1
), "%d", setnum
);
256 (void)execl(executable
, executable
, "DO CHECK", "b", param1
,
263 if (waitpid(pid
, &status
, 0) != pid
) e(setnum
);
264 if (!WIFEXITED(status
)) e(setnum
);
265 if (WEXITSTATUS(status
) != 0) e(setnum
);
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
275 test_one_uid(int setnum
, int sub
)
277 const struct uid_set
*set
;
280 set
= &uid_sets
[setnum
];
282 /* Verify that the pre-call process state is as expected. */
283 test_uids(set
->ruid
, set
->euid
, set
->suid
);
285 /* Perform the call, and check whether the result is as expected. */
288 res
= setuid(set
->uid
);
293 res
= seteuid(set
->uid
);
306 if (res
!= 0 && (res
!= -1 || errno
!= EPERM
)) e(setnum
);
308 if (res
!= exp
) e(setnum
);
310 /* Verify that the post-call process state is as expected as well. */
313 test_uids(set
->ruid
, set
->uid
, set
->suid
);
315 test_uids(set
->uid
, set
->uid
, set
->uid
);
317 test_uids(set
->ruid
, set
->euid
, set
->suid
);
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.
325 exec89a(const char * param1
, const char * param2
)
327 const struct uid_set
*set
;
330 setnum
= atoi(param1
);
331 if (setnum
< 0 || setnum
>= __arraycount(uid_sets
)) {
335 set
= &uid_sets
[setnum
];
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)
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
);
350 return; /* skip test */
353 if (seteuid(set
->euid
) != 0) e(setnum
);
356 /* Perform the actual test. */
357 test_one_uid(setnum
, sub
);
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
367 sub89a(int setnum
, int sub
)
369 const struct uid_set
*set
;
370 char param1
[32], param2
[32];
372 set
= &uid_sets
[setnum
];
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.
380 if (set
->ruid
!= set
->suid
) {
382 * In order to set the saved UID to something other than the
383 * real UID, we must exec(2) a set-uid binary.
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);
389 if (setuid(set
->ruid
) != 0) e(setnum
);
391 snprintf(param1
, sizeof(param1
), "%d", setnum
);
392 snprintf(param2
, sizeof(param2
), "%d", sub
);
394 (void)execl(executable
, executable
, "DO CHECK", "a", param1
,
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.
404 if (set
->ruid
!= 0 && set
->ruid
!= set
->euid
)
405 return; /* skip test */
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
);
413 if (setuid(set
->ruid
) != 0) e(setnum
);
414 if (seteuid(set
->euid
) != 0) e(setnum
);
416 /* Perform the actual test. */
417 test_one_uid(setnum
, sub
);
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.
435 for (setnum
= 0; setnum
< __arraycount(uid_sets
); setnum
++) {
436 for (sub
= SUB_REAL
; sub
<= SUB_EFF
; sub
++) {
448 sub89a((int)setnum
, sub
);
454 if (waitpid(pid
, &status
, 0) != pid
) e(setnum
);
455 if (!WIFEXITED(status
)) e(setnum
);
456 if (WEXITSTATUS(status
) != 0) e(setnum
);
463 * Ensure that the real, effective, and saved UIDs are fully preserved across
464 * fork(2) and non-setuid-binary exec(2) calls.
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 */
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.
495 sub89a((int)setnum
, SUB_RETAIN
);
501 if (waitpid(pid
, &status
, 0) != pid
) e(setnum
);
502 if (!WIFEXITED(status
)) e(setnum
);
503 if (WEXITSTATUS(status
) != 0) e(setnum
);
509 * Verify that the current process's real, effective, and saved group IDs are
510 * set to the given respective value.
513 test_gids(gid_t rgid
, gid_t egid
, gid_t sgid
)
515 struct kinfo_proc2 proc2
;
517 if (getgid() != rgid
) e(0);
518 if (getegid() != egid
) e(0);
521 if (get_proc2(getpid(), &proc2
) != 0) e(0);
523 if (proc2
.p_rgid
!= rgid
) e(0);
524 if (proc2
.p_gid
!= egid
) e(0);
525 if (proc2
.p_svgid
!= sgid
) e(0);
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.
534 exec89d(const char * param1
, const char * param2 __unused
)
536 const struct gid_set
*set
;
539 setnum
= atoi(param1
);
540 if (setnum
< 0 || setnum
>= __arraycount(gid_sets
)) {
544 set
= &gid_sets
[setnum
];
546 test_gids(set
->rgid
, set
->egid
, set
->egid
);
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
558 const struct gid_set
*set
;
563 set
= &gid_sets
[setnum
];
574 * Verify that all the GIDs were retained across the fork(2)
577 test_gids(set
->rgid
, set
->egid
, set
->sgid
);
579 /* Clear the set-gid bit. */
580 if (chmod(executable
, S_IXUSR
| S_IXGRP
| S_IXOTH
) != 0)
583 /* Alternate between preserving and dropping user IDs. */
585 if (setuid(3) != 0) e(setnum
);
588 snprintf(param1
, sizeof(param1
), "%d", setnum
);
590 (void)execl(executable
, executable
, "DO CHECK", "d", param1
,
597 if (waitpid(pid
, &status
, 0) != pid
) e(setnum
);
598 if (!WIFEXITED(status
)) e(setnum
);
599 if (WEXITSTATUS(status
) != 0) e(setnum
);
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
609 test_one_gid(int setnum
, int sub
)
611 const struct gid_set
*set
;
614 set
= &gid_sets
[setnum
];
616 /* Verify that the pre-call process state is as expected. */
617 test_gids(set
->rgid
, set
->egid
, set
->sgid
);
619 /* Perform the call, and check whether the result is as expected. */
623 if (sub
!= SUB_REAL_E0
&& seteuid(1) != 0) e(0);
625 res
= setgid(set
->gid
);
626 exp
= (sub
!= SUB_REAL_E0
) ? (set
->res
- 1) : 0;
631 if (sub
!= SUB_EFF_E0
&& seteuid(1) != 0) e(0);
633 res
= setegid(set
->gid
);
634 exp
= (sub
!= SUB_EFF_E0
) ? (set
->eres
- 1) : 0;
646 if (res
!= 0 && (res
!= -1 || errno
!= EPERM
)) e(setnum
);
648 if (res
!= exp
) e(setnum
);
650 /* Verify that the post-call process state is as expected as well. */
652 if (sub
== SUB_EFF
|| sub
== SUB_EFF_E0
)
653 test_gids(set
->rgid
, set
->gid
, set
->sgid
);
655 test_gids(set
->gid
, set
->gid
, set
->gid
);
657 test_gids(set
->rgid
, set
->egid
, set
->sgid
);
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.
665 exec89c(const char * param1
, const char * param2
)
667 const struct gid_set
*set
;
670 setnum
= atoi(param1
);
671 if (setnum
< 0 || setnum
>= __arraycount(gid_sets
)) {
675 set
= &gid_sets
[setnum
];
679 /* Finish setting up the initial condition. */
680 if (set
->egid
!= set
->sgid
&& setegid(set
->egid
) != 0) e(setnum
);
682 /* Perform the actual test. */
683 test_one_gid(setnum
, sub
);
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.
693 sub89c(int setnum
, int sub
)
695 const struct gid_set
*set
;
696 char param1
[32], param2
[32];
698 set
= &gid_sets
[setnum
];
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.
704 if (set
->rgid
!= set
->sgid
) {
706 * In order to set the saved GID to something other than the
707 * real GID, we must exec(2) a set-gid binary.
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);
713 if (setgid(set
->rgid
) != 0) e(setnum
);
715 snprintf(param1
, sizeof(param1
), "%d", setnum
);
716 snprintf(param2
, sizeof(param2
), "%d", sub
);
718 (void)execl(executable
, executable
, "DO CHECK", "c", param1
,
724 * If the real and saved group ID are to be set to the same
725 * value, we need not use exec(2).
727 if (setgid(set
->rgid
) != 0) e(setnum
);
728 if (setegid(set
->egid
) != 0) e(setnum
);
730 /* Perform the actual test. */
731 test_one_gid(setnum
, sub
);
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.
750 for (setnum
= 0; setnum
< __arraycount(gid_sets
); setnum
++) {
751 for (sub
= SUB_REAL
; sub
<= SUB_EFF_E0
; sub
++) {
763 sub89c((int)setnum
, sub
);
769 if (waitpid(pid
, &status
, 0) != pid
) e(setnum
);
770 if (!WIFEXITED(status
)) e(setnum
);
771 if (WEXITSTATUS(status
) != 0) e(setnum
);
778 * Ensure that the real, effective, and saved GIDs are fully preserved across
779 * fork(2) and non-setgid-binary exec(2) calls.
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 */
805 /* Similarly, test D uses some of the C-test code. */
806 sub89c((int)setnum
, SUB_RETAIN
);
812 if (waitpid(pid
, &status
, 0) != pid
) e(setnum
);
813 if (!WIFEXITED(status
)) e(setnum
);
814 if (WEXITSTATUS(status
) != 0) e(setnum
);
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).
825 exec89e(const char * param1
, const char * param2
)
834 mode
= S_IXUSR
| S_IXGRP
| S_IXOTH
;
835 if (mask
& 1) mode
|= S_ISUID
;
836 if (mask
& 2) mode
|= S_ISGID
;
838 if (chown(executable
, 6, 7) != 0) e(0);
839 if (chmod(executable
, mode
) != 0) e(0);
841 if (setegid(4) != 0) e(0);
842 if (seteuid(2) != 0) e(0);
847 (void)execl(executable
, executable
, "DO CHECK", "e", param1
,
865 * Set up for the set-uid/set-gid execution test by initializing to different
866 * real and effective user IDs.
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);
877 if (setgid(3) != 0) e(0);
878 if (setuid(1) != 0) e(0);
880 snprintf(param1
, sizeof(param1
), "%d", mask
);
881 (void)execl(executable
, executable
, "DO CHECK", "e", param1
, "0",
886 * Perform basic verification that the set-uid and set-gid bits on binaries are
887 * fully independent from each other.
897 for (mask
= 0; mask
<= 3; mask
++) {
915 if (waitpid(pid
, &status
, 0) != pid
) e(mask
);
916 if (!WIFEXITED(status
)) e(mask
);
917 if (WEXITSTATUS(status
) != 0) e(mask
);
923 * Call the right function after having executed myself.
926 exec89(const char * param0
, const char * param1
, const char * param2
)
931 exec89a(param1
, param2
);
935 exec89b(param1
, param2
);
939 exec89c(param1
, param2
);
943 exec89d(param1
, param2
);
947 exec89e(param1
, param2
);
958 * Initialize the test.
963 char cp_cmd
[PATH_MAX
+ 9];
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);
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
);
979 status
= system(cp_cmd
);
980 if (status
< 0 || !WIFEXITED(status
) ||
981 WEXITSTATUS(status
) != EXIT_SUCCESS
) e(0);
985 * Test program for set[ug]id, sete[ug]id, and saved IDs.
988 main(int argc
, char ** argv
)
992 executable
= argv
[0];
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]);
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();