1*433d6423SLionel Sambuc #include <sys/types.h>
2*433d6423SLionel Sambuc #include <sys/wait.h>
3*433d6423SLionel Sambuc #include <stdio.h>
4*433d6423SLionel Sambuc #include <unistd.h>
5*433d6423SLionel Sambuc
6*433d6423SLionel Sambuc int max_error = 5;
7*433d6423SLionel Sambuc #include "common.h"
8*433d6423SLionel Sambuc
9*433d6423SLionel Sambuc
10*433d6423SLionel Sambuc int subtest = -1;
11*433d6423SLionel Sambuc
12*433d6423SLionel Sambuc void test_self(void);
13*433d6423SLionel Sambuc void test_setnone(void);
14*433d6423SLionel Sambuc void test_setuid(void);
15*433d6423SLionel Sambuc void test_setgid(void);
16*433d6423SLionel Sambuc void test_effugid(void);
17*433d6423SLionel Sambuc int execute(const char *prog, const char *arg);
18*433d6423SLionel Sambuc
execute(const char * prog,const char * arg)19*433d6423SLionel Sambuc int execute(const char *prog, const char *arg)
20*433d6423SLionel Sambuc {
21*433d6423SLionel Sambuc pid_t childpid;
22*433d6423SLionel Sambuc int status;
23*433d6423SLionel Sambuc char cmd[30];
24*433d6423SLionel Sambuc
25*433d6423SLionel Sambuc snprintf(cmd, sizeof(cmd), "./%s", prog);
26*433d6423SLionel Sambuc
27*433d6423SLionel Sambuc childpid = fork();
28*433d6423SLionel Sambuc if (childpid == (pid_t) -1) {
29*433d6423SLionel Sambuc return(-2);
30*433d6423SLionel Sambuc } else if (childpid == 0) {
31*433d6423SLionel Sambuc if (execl(cmd, prog, arg, NULL) == -1) {
32*433d6423SLionel Sambuc exit(-2);
33*433d6423SLionel Sambuc }
34*433d6423SLionel Sambuc return(-2); /* Never reached */
35*433d6423SLionel Sambuc } else {
36*433d6423SLionel Sambuc wait(&status);
37*433d6423SLionel Sambuc }
38*433d6423SLionel Sambuc
39*433d6423SLionel Sambuc return(WEXITSTATUS(status));
40*433d6423SLionel Sambuc }
41*433d6423SLionel Sambuc
test_setgid(void)42*433d6423SLionel Sambuc void test_setgid(void)
43*433d6423SLionel Sambuc {
44*433d6423SLionel Sambuc /* Execve a new process that has setgid bits set */
45*433d6423SLionel Sambuc subtest = 3;
46*433d6423SLionel Sambuc
47*433d6423SLionel Sambuc /* When we exec a new process which has setgid set, that process should
48*433d6423SLionel Sambuc * be tainted.
49*433d6423SLionel Sambuc */
50*433d6423SLionel Sambuc system("chmod 2755 setgid");
51*433d6423SLionel Sambuc if (execute("setgid", "0000") != 1) e(2);
52*433d6423SLionel Sambuc
53*433d6423SLionel Sambuc /* When we exec a new process which has setgid set, but unsets that bit
54*433d6423SLionel Sambuc * before calling issetugid() should still be tainted
55*433d6423SLionel Sambuc */
56*433d6423SLionel Sambuc system("chmod 2755 setgid");
57*433d6423SLionel Sambuc if (execute("setgid", "0755") != 1) e(3);
58*433d6423SLionel Sambuc
59*433d6423SLionel Sambuc /* When we exec a new process which has setgid set, and then also sets
60*433d6423SLionel Sambuc * setuid before calling issetugid() should still be tainted
61*433d6423SLionel Sambuc */
62*433d6423SLionel Sambuc system("chmod 2755 setgid");
63*433d6423SLionel Sambuc if (execute("setgid", "06755") != 1) e(4);
64*433d6423SLionel Sambuc
65*433d6423SLionel Sambuc /* When we exec a new process that has setgid set, and which upon
66*433d6423SLionel Sambuc * execution forks, the forked child should also be tainted */
67*433d6423SLionel Sambuc system("chmod 2755 setgidfork");
68*433d6423SLionel Sambuc if (execute("setgidfork", "0000") != 1) e(5);
69*433d6423SLionel Sambuc }
70*433d6423SLionel Sambuc
test_setuid(void)71*433d6423SLionel Sambuc void test_setuid(void)
72*433d6423SLionel Sambuc {
73*433d6423SLionel Sambuc /* Execve a new process that has setuid bits set */
74*433d6423SLionel Sambuc subtest = 4;
75*433d6423SLionel Sambuc
76*433d6423SLionel Sambuc /* When we exec a new process which has setuid set, that process should
77*433d6423SLionel Sambuc * be tainted.
78*433d6423SLionel Sambuc */
79*433d6423SLionel Sambuc system("chmod 4755 setuid");
80*433d6423SLionel Sambuc if (execute("setuid", "0000") != 1) e(1);
81*433d6423SLionel Sambuc
82*433d6423SLionel Sambuc /* When we exec a new process which has setuid set, but unsets that bit
83*433d6423SLionel Sambuc * before calling issetugid() should still be tainted
84*433d6423SLionel Sambuc */
85*433d6423SLionel Sambuc system("chmod 4755 setuid");
86*433d6423SLionel Sambuc if (execute("setuid", "0755") != 1) e(2);
87*433d6423SLionel Sambuc
88*433d6423SLionel Sambuc /* When we exec a new process which has setuid set, and then also sets
89*433d6423SLionel Sambuc * setgid before calling issetugid() should still be tainted
90*433d6423SLionel Sambuc */
91*433d6423SLionel Sambuc system("chmod 4755 setuid");
92*433d6423SLionel Sambuc if (execute("setuid", "06755") != 1) e(3);
93*433d6423SLionel Sambuc
94*433d6423SLionel Sambuc /* When we exec a new process that has setgid set, and which upon
95*433d6423SLionel Sambuc * execution forks, the forked child should also be tainted */
96*433d6423SLionel Sambuc system("chmod 4755 setuidfork");
97*433d6423SLionel Sambuc if (execute("setuidfork", "0000") != 1) e(4);
98*433d6423SLionel Sambuc
99*433d6423SLionel Sambuc }
100*433d6423SLionel Sambuc
test_setugid(void)101*433d6423SLionel Sambuc static void test_setugid(void)
102*433d6423SLionel Sambuc {
103*433d6423SLionel Sambuc /* Execve a new process that has setuid and setgid bits set */
104*433d6423SLionel Sambuc subtest = 5;
105*433d6423SLionel Sambuc
106*433d6423SLionel Sambuc /* When we exec a new process which has setugid set, that
107*433d6423SLionel Sambuc * process should be tainted.
108*433d6423SLionel Sambuc */
109*433d6423SLionel Sambuc system("chmod 6755 setugid");
110*433d6423SLionel Sambuc if (execute("setugid", "0000") != 1) e(1);
111*433d6423SLionel Sambuc
112*433d6423SLionel Sambuc /* When we exec a new process which has setugid set, but unsets those bits
113*433d6423SLionel Sambuc * before calling issetugid() should still be tainted
114*433d6423SLionel Sambuc */
115*433d6423SLionel Sambuc system("chmod 6755 setugid");
116*433d6423SLionel Sambuc if (execute("setugid", "0755") != 1) e(2);
117*433d6423SLionel Sambuc
118*433d6423SLionel Sambuc /* When we exec a new process that has setugid set, and which upon
119*433d6423SLionel Sambuc * execution forks, the forked child should also be tainted */
120*433d6423SLionel Sambuc system("chmod 6755 setugidfork");
121*433d6423SLionel Sambuc if (execute("setugidfork", "0000") != 1) e(4);
122*433d6423SLionel Sambuc
123*433d6423SLionel Sambuc }
124*433d6423SLionel Sambuc
test_effugid(void)125*433d6423SLionel Sambuc void test_effugid(void)
126*433d6423SLionel Sambuc {
127*433d6423SLionel Sambuc /* Test taint status with different effective uid and gid */
128*433d6423SLionel Sambuc pid_t childpid;
129*433d6423SLionel Sambuc int status;
130*433d6423SLionel Sambuc
131*433d6423SLionel Sambuc subtest = 6;
132*433d6423SLionel Sambuc
133*433d6423SLionel Sambuc /* Start with effective uid */
134*433d6423SLionel Sambuc childpid = fork();
135*433d6423SLionel Sambuc if (childpid == (pid_t) -1) e(1);
136*433d6423SLionel Sambuc else if (childpid == 0) {
137*433d6423SLionel Sambuc /* We're the child */
138*433d6423SLionel Sambuc
139*433d6423SLionel Sambuc /* We should be tainted */
140*433d6423SLionel Sambuc if (issetugid() != 1) e(2);
141*433d6423SLionel Sambuc
142*433d6423SLionel Sambuc /* Now execute a program without set{u,g}id; should not be tainted */
143*433d6423SLionel Sambuc system("chmod 755 nobits");
144*433d6423SLionel Sambuc if (execute("nobits", "0000") != 0) e(3);
145*433d6423SLionel Sambuc
146*433d6423SLionel Sambuc /* Change effective uid into current+42 and try nobits again. This time
147*433d6423SLionel Sambuc * it should be tainted */
148*433d6423SLionel Sambuc if (seteuid(geteuid() + 42) != 0) e(4);
149*433d6423SLionel Sambuc if (execute("nobits", "0000") != 1) e(5);
150*433d6423SLionel Sambuc exit(EXIT_SUCCESS);
151*433d6423SLionel Sambuc } else {
152*433d6423SLionel Sambuc /* We're the parent, wait for the child to finish */
153*433d6423SLionel Sambuc wait(&status);
154*433d6423SLionel Sambuc }
155*433d6423SLionel Sambuc
156*433d6423SLionel Sambuc /* Now test effective gid */
157*433d6423SLionel Sambuc childpid = fork();
158*433d6423SLionel Sambuc if (childpid == (pid_t) -1) e(1);
159*433d6423SLionel Sambuc else if (childpid == 0) {
160*433d6423SLionel Sambuc /* We're the child */
161*433d6423SLionel Sambuc
162*433d6423SLionel Sambuc /* We should be tainted */
163*433d6423SLionel Sambuc if (issetugid() != 1) e(2);
164*433d6423SLionel Sambuc
165*433d6423SLionel Sambuc /* Now execute a program without set{u,g}id; should not be tainted */
166*433d6423SLionel Sambuc system("chmod 755 nobits");
167*433d6423SLionel Sambuc if (execute("nobits", "0000") != 0) e(3);
168*433d6423SLionel Sambuc
169*433d6423SLionel Sambuc /* Change effective gid into current+42 and try nobits again. This time
170*433d6423SLionel Sambuc * it should be tainted */
171*433d6423SLionel Sambuc if (seteuid(getegid() + 42) != 0) e(4);
172*433d6423SLionel Sambuc if (execute("nobits", "0000") != 1) e(5);
173*433d6423SLionel Sambuc exit(EXIT_SUCCESS);
174*433d6423SLionel Sambuc } else {
175*433d6423SLionel Sambuc /* We're the parent, wait for the child to finish */
176*433d6423SLionel Sambuc wait(&status);
177*433d6423SLionel Sambuc }
178*433d6423SLionel Sambuc }
179*433d6423SLionel Sambuc
test_setnone(void)180*433d6423SLionel Sambuc void test_setnone(void)
181*433d6423SLionel Sambuc {
182*433d6423SLionel Sambuc /* Execve a new process that does not have setuid or setgid bits set */
183*433d6423SLionel Sambuc subtest = 2;
184*433d6423SLionel Sambuc
185*433d6423SLionel Sambuc /* When we exec a new process which doesn't have set{u,g}id set, that
186*433d6423SLionel Sambuc * process should not be tainted */
187*433d6423SLionel Sambuc system("chmod 755 nobits");
188*433d6423SLionel Sambuc if (execute("nobits", "0000") != 0) e(2);
189*433d6423SLionel Sambuc
190*433d6423SLionel Sambuc /* When we exec a new process which doesn't have set{u,g}id set, but
191*433d6423SLionel Sambuc * sets them after execution, the process should still not be tainted
192*433d6423SLionel Sambuc */
193*433d6423SLionel Sambuc system("chmod 755 nobits");
194*433d6423SLionel Sambuc if (execute("nobits", "02755") != 0) e(4);
195*433d6423SLionel Sambuc system("chmod 755 nobits");
196*433d6423SLionel Sambuc if (execute("nobits", "04755") != 0) e(3);
197*433d6423SLionel Sambuc system("chmod 755 nobits");
198*433d6423SLionel Sambuc if (execute("nobits", "06755") != 0) e(5);
199*433d6423SLionel Sambuc
200*433d6423SLionel Sambuc /* When we exec a new process that doesn't have setugid set, and which upon
201*433d6423SLionel Sambuc * execution forks, the forked child should not be tainted either */
202*433d6423SLionel Sambuc system("chmod 755 nobitsfork");
203*433d6423SLionel Sambuc if (execute("nobitsfork", "0000") != 0) e(6);
204*433d6423SLionel Sambuc }
205*433d6423SLionel Sambuc
test_self(void)206*433d6423SLionel Sambuc void test_self(void)
207*433d6423SLionel Sambuc {
208*433d6423SLionel Sambuc /* We're supposed to be setuid. Verify. */
209*433d6423SLionel Sambuc
210*433d6423SLionel Sambuc int status;
211*433d6423SLionel Sambuc pid_t childpid;
212*433d6423SLionel Sambuc
213*433d6423SLionel Sambuc subtest = 1;
214*433d6423SLionel Sambuc
215*433d6423SLionel Sambuc if (issetugid() != 1) e(1);
216*433d6423SLionel Sambuc childpid = fork();
217*433d6423SLionel Sambuc if (childpid == -1) e(2);
218*433d6423SLionel Sambuc else if (childpid == 0) {
219*433d6423SLionel Sambuc /* We're the child and should inherit the tainted status of the parent
220*433d6423SLionel Sambuc */
221*433d6423SLionel Sambuc if (issetugid() != 1) e(3);
222*433d6423SLionel Sambuc
223*433d6423SLionel Sambuc /* Let's change to the bin user */
224*433d6423SLionel Sambuc if (setuid((uid_t) 2) != 0) e(4);
225*433d6423SLionel Sambuc if (getuid() != (uid_t) 2) e(5);
226*433d6423SLionel Sambuc
227*433d6423SLionel Sambuc /* At this point, taint status should not have changed. */
228*433d6423SLionel Sambuc if (issetugid() != 1) e(6);
229*433d6423SLionel Sambuc
230*433d6423SLionel Sambuc exit(EXIT_SUCCESS);
231*433d6423SLionel Sambuc } else {
232*433d6423SLionel Sambuc /* We're the parent. Wait for the child to finish */
233*433d6423SLionel Sambuc wait(&status);
234*433d6423SLionel Sambuc }
235*433d6423SLionel Sambuc }
236*433d6423SLionel Sambuc
switch_to_su(void)237*433d6423SLionel Sambuc static void switch_to_su(void)
238*433d6423SLionel Sambuc {
239*433d6423SLionel Sambuc subtest = 0;
240*433d6423SLionel Sambuc if (setuid(0) != 0) e(1);
241*433d6423SLionel Sambuc }
242*433d6423SLionel Sambuc
main(int argc,char ** argv)243*433d6423SLionel Sambuc int main(int argc, char **argv)
244*433d6423SLionel Sambuc {
245*433d6423SLionel Sambuc start(60);
246*433d6423SLionel Sambuc system("cp ../t60a nobits");
247*433d6423SLionel Sambuc system("cp ../t60a setgid");
248*433d6423SLionel Sambuc system("cp ../t60a setuid");
249*433d6423SLionel Sambuc system("cp ../t60a setugid");
250*433d6423SLionel Sambuc system("cp ../t60b nobitsfork");
251*433d6423SLionel Sambuc system("cp ../t60b setuidfork");
252*433d6423SLionel Sambuc system("cp ../t60b setgidfork");
253*433d6423SLionel Sambuc system("cp ../t60b setugidfork");
254*433d6423SLionel Sambuc
255*433d6423SLionel Sambuc switch_to_su(); /* We have to be root to perform this test */
256*433d6423SLionel Sambuc test_self();
257*433d6423SLionel Sambuc test_setnone();
258*433d6423SLionel Sambuc test_setuid();
259*433d6423SLionel Sambuc test_setgid();
260*433d6423SLionel Sambuc test_setugid();
261*433d6423SLionel Sambuc test_effugid();
262*433d6423SLionel Sambuc
263*433d6423SLionel Sambuc quit();
264*433d6423SLionel Sambuc
265*433d6423SLionel Sambuc return(-1); /* Never reached */
266*433d6423SLionel Sambuc }
267