xref: /aosp_15_r20/external/libcap/tests/libcap_launch_test.c (revision 2810ac1b38eead2603277920c78344c84ddf3aff)
1*2810ac1bSKiyoung Kim #include <errno.h>
2*2810ac1bSKiyoung Kim #include <stdio.h>
3*2810ac1bSKiyoung Kim #include <stdlib.h>
4*2810ac1bSKiyoung Kim #include <string.h>
5*2810ac1bSKiyoung Kim #include <sys/capability.h>
6*2810ac1bSKiyoung Kim #include <sys/types.h>
7*2810ac1bSKiyoung Kim #include <sys/wait.h>
8*2810ac1bSKiyoung Kim #include <unistd.h>
9*2810ac1bSKiyoung Kim 
10*2810ac1bSKiyoung Kim /*
11*2810ac1bSKiyoung Kim  * tests for cap_launch.
12*2810ac1bSKiyoung Kim  */
13*2810ac1bSKiyoung Kim 
14*2810ac1bSKiyoung Kim #define MORE_THAN_ENOUGH 20
15*2810ac1bSKiyoung Kim #define NO_MORE 1
16*2810ac1bSKiyoung Kim 
17*2810ac1bSKiyoung Kim struct test_case_s {
18*2810ac1bSKiyoung Kim     int pass_on;
19*2810ac1bSKiyoung Kim     const char *chroot;
20*2810ac1bSKiyoung Kim     uid_t uid;
21*2810ac1bSKiyoung Kim     gid_t gid;
22*2810ac1bSKiyoung Kim     int ngroups;
23*2810ac1bSKiyoung Kim     const gid_t groups[MORE_THAN_ENOUGH];
24*2810ac1bSKiyoung Kim     const char *args[MORE_THAN_ENOUGH];
25*2810ac1bSKiyoung Kim     const char **envp;
26*2810ac1bSKiyoung Kim     const char *iab;
27*2810ac1bSKiyoung Kim     cap_mode_t mode;
28*2810ac1bSKiyoung Kim     int launch_abort;
29*2810ac1bSKiyoung Kim     int result;
30*2810ac1bSKiyoung Kim     int (*callback_fn)(void *detail);
31*2810ac1bSKiyoung Kim };
32*2810ac1bSKiyoung Kim 
33*2810ac1bSKiyoung Kim #ifdef WITH_PTHREADS
34*2810ac1bSKiyoung Kim #include <pthread.h>
35*2810ac1bSKiyoung Kim #else /* WITH_PTHREADS */
36*2810ac1bSKiyoung Kim #endif /* WITH_PTHREADS */
37*2810ac1bSKiyoung Kim 
38*2810ac1bSKiyoung Kim /*
39*2810ac1bSKiyoung Kim  * clean_out drops all process capabilities.
40*2810ac1bSKiyoung Kim  */
clean_out(void * data)41*2810ac1bSKiyoung Kim static int clean_out(void *data) {
42*2810ac1bSKiyoung Kim     cap_t empty;
43*2810ac1bSKiyoung Kim     empty = cap_init();
44*2810ac1bSKiyoung Kim     if (cap_set_proc(empty) != 0) {
45*2810ac1bSKiyoung Kim 	_exit(1);
46*2810ac1bSKiyoung Kim     }
47*2810ac1bSKiyoung Kim     cap_free(empty);
48*2810ac1bSKiyoung Kim     return 0;
49*2810ac1bSKiyoung Kim }
50*2810ac1bSKiyoung Kim 
main(int argc,char ** argv)51*2810ac1bSKiyoung Kim int main(int argc, char **argv) {
52*2810ac1bSKiyoung Kim     static struct test_case_s vs[] = {
53*2810ac1bSKiyoung Kim 	{
54*2810ac1bSKiyoung Kim 	    .args = { "../progs/tcapsh-static", "--", "-c", "echo hello" },
55*2810ac1bSKiyoung Kim 	    .result = 0
56*2810ac1bSKiyoung Kim 	},
57*2810ac1bSKiyoung Kim 	{
58*2810ac1bSKiyoung Kim 	    .args = { "../progs/tcapsh-static", "--", "-c", "echo hello" },
59*2810ac1bSKiyoung Kim 	    .callback_fn = &clean_out,
60*2810ac1bSKiyoung Kim 	    .result = 0
61*2810ac1bSKiyoung Kim 	},
62*2810ac1bSKiyoung Kim 	{
63*2810ac1bSKiyoung Kim 	    .callback_fn = &clean_out,
64*2810ac1bSKiyoung Kim 	    .result = 0
65*2810ac1bSKiyoung Kim 	},
66*2810ac1bSKiyoung Kim 	{
67*2810ac1bSKiyoung Kim 	    .args = { "../progs/tcapsh-static", "--is-uid=123" },
68*2810ac1bSKiyoung Kim 	    .result = 256
69*2810ac1bSKiyoung Kim 	},
70*2810ac1bSKiyoung Kim 	{
71*2810ac1bSKiyoung Kim 	    .args = { "/", "won't", "work" },
72*2810ac1bSKiyoung Kim 	    .launch_abort = 1,
73*2810ac1bSKiyoung Kim 	},
74*2810ac1bSKiyoung Kim 	{
75*2810ac1bSKiyoung Kim 	    .args = { "../progs/tcapsh-static", "--is-uid=123" },
76*2810ac1bSKiyoung Kim 	    .uid = 123,
77*2810ac1bSKiyoung Kim 	    .result = 0,
78*2810ac1bSKiyoung Kim 	},
79*2810ac1bSKiyoung Kim 	{
80*2810ac1bSKiyoung Kim 	    .args = { "../progs/tcapsh-static", "--is-uid=123" },
81*2810ac1bSKiyoung Kim 	    .callback_fn = &clean_out,
82*2810ac1bSKiyoung Kim 	    .uid = 123,
83*2810ac1bSKiyoung Kim 	    .launch_abort = 1,
84*2810ac1bSKiyoung Kim 	},
85*2810ac1bSKiyoung Kim 	{
86*2810ac1bSKiyoung Kim 	    .args = { "../progs/tcapsh-static", "--is-gid=123" },
87*2810ac1bSKiyoung Kim 	    .result = 0,
88*2810ac1bSKiyoung Kim 	    .gid = 123,
89*2810ac1bSKiyoung Kim 	    .ngroups = 1,
90*2810ac1bSKiyoung Kim 	    .groups = { 456 },
91*2810ac1bSKiyoung Kim 	    .iab = "",
92*2810ac1bSKiyoung Kim 	},
93*2810ac1bSKiyoung Kim 	{
94*2810ac1bSKiyoung Kim 	    .args = { "../progs/tcapsh-static", "--dropped=cap_chown",
95*2810ac1bSKiyoung Kim 		      "--has-i=cap_chown" },
96*2810ac1bSKiyoung Kim 	    .result = 0,
97*2810ac1bSKiyoung Kim 	    .iab = "!%cap_chown"
98*2810ac1bSKiyoung Kim 	},
99*2810ac1bSKiyoung Kim 	{
100*2810ac1bSKiyoung Kim 	    .args = { "../progs/tcapsh-static", "--dropped=cap_chown",
101*2810ac1bSKiyoung Kim 		      "--has-i=cap_chown", "--is-uid=234",
102*2810ac1bSKiyoung Kim 		      "--has-a=cap_chown", "--has-p=cap_chown" },
103*2810ac1bSKiyoung Kim 	    .uid = 234,
104*2810ac1bSKiyoung Kim 	    .result = 0,
105*2810ac1bSKiyoung Kim 	    .iab = "!^cap_chown"
106*2810ac1bSKiyoung Kim 	},
107*2810ac1bSKiyoung Kim 	{
108*2810ac1bSKiyoung Kim 	    .args = { "../progs/tcapsh-static", "--inmode=NOPRIV",
109*2810ac1bSKiyoung Kim 		      "--has-no-new-privs" },
110*2810ac1bSKiyoung Kim 	    .result = 0,
111*2810ac1bSKiyoung Kim 	    .mode = CAP_MODE_NOPRIV
112*2810ac1bSKiyoung Kim 	},
113*2810ac1bSKiyoung Kim 	{
114*2810ac1bSKiyoung Kim 	    .args = { "/noop" },
115*2810ac1bSKiyoung Kim 	    .result = 0,
116*2810ac1bSKiyoung Kim 	    .chroot = ".",
117*2810ac1bSKiyoung Kim 	},
118*2810ac1bSKiyoung Kim 	{
119*2810ac1bSKiyoung Kim 	    .pass_on = NO_MORE
120*2810ac1bSKiyoung Kim 	},
121*2810ac1bSKiyoung Kim     };
122*2810ac1bSKiyoung Kim 
123*2810ac1bSKiyoung Kim     if (errno != 0) {
124*2810ac1bSKiyoung Kim 	perror("unexpected initial value for errno");
125*2810ac1bSKiyoung Kim 	exit(1);
126*2810ac1bSKiyoung Kim     }
127*2810ac1bSKiyoung Kim 
128*2810ac1bSKiyoung Kim     cap_t orig = cap_get_proc();
129*2810ac1bSKiyoung Kim     if (orig == NULL) {
130*2810ac1bSKiyoung Kim 	perror("failed to get process capabilities");
131*2810ac1bSKiyoung Kim 	exit(1);
132*2810ac1bSKiyoung Kim     }
133*2810ac1bSKiyoung Kim 
134*2810ac1bSKiyoung Kim     int success = 1, i;
135*2810ac1bSKiyoung Kim     for (i=0; vs[i].pass_on != NO_MORE; i++) {
136*2810ac1bSKiyoung Kim 	cap_launch_t attr = NULL;
137*2810ac1bSKiyoung Kim 	const struct test_case_s *v = &vs[i];
138*2810ac1bSKiyoung Kim 	if (cap_launch(attr, NULL) != -1) {
139*2810ac1bSKiyoung Kim 	    perror("NULL launch didn't fail");
140*2810ac1bSKiyoung Kim 	    exit(1);
141*2810ac1bSKiyoung Kim 	}
142*2810ac1bSKiyoung Kim 	printf("[%d] test should %s\n", i,
143*2810ac1bSKiyoung Kim 	       v->result || v->launch_abort ? "generate error" : "work");
144*2810ac1bSKiyoung Kim 	if (v->args[0] != NULL) {
145*2810ac1bSKiyoung Kim 	    attr = cap_new_launcher(v->args[0], v->args, v->envp);
146*2810ac1bSKiyoung Kim 	    if (attr == NULL) {
147*2810ac1bSKiyoung Kim 		perror("failed to obtain launcher");
148*2810ac1bSKiyoung Kim 		exit(1);
149*2810ac1bSKiyoung Kim 	    }
150*2810ac1bSKiyoung Kim 	    if (v->callback_fn != NULL) {
151*2810ac1bSKiyoung Kim 		cap_launcher_callback(attr, v->callback_fn);
152*2810ac1bSKiyoung Kim 	    }
153*2810ac1bSKiyoung Kim 	} else {
154*2810ac1bSKiyoung Kim 	    attr = cap_func_launcher(v->callback_fn);
155*2810ac1bSKiyoung Kim 	}
156*2810ac1bSKiyoung Kim 	if (v->chroot) {
157*2810ac1bSKiyoung Kim 	    cap_launcher_set_chroot(attr, v->chroot);
158*2810ac1bSKiyoung Kim 	}
159*2810ac1bSKiyoung Kim 	if (v->uid) {
160*2810ac1bSKiyoung Kim 	    cap_launcher_setuid(attr, v->uid);
161*2810ac1bSKiyoung Kim 	}
162*2810ac1bSKiyoung Kim 	if (v->gid) {
163*2810ac1bSKiyoung Kim 	    cap_launcher_setgroups(attr, v->gid, v->ngroups, v->groups);
164*2810ac1bSKiyoung Kim 	}
165*2810ac1bSKiyoung Kim 	if (v->iab) {
166*2810ac1bSKiyoung Kim 	    cap_iab_t iab = cap_iab_from_text(v->iab);
167*2810ac1bSKiyoung Kim 	    if (iab == NULL) {
168*2810ac1bSKiyoung Kim 		fprintf(stderr, "[%d] failed to decode iab [%s]", i, v->iab);
169*2810ac1bSKiyoung Kim 		perror(":");
170*2810ac1bSKiyoung Kim 		success = 0;
171*2810ac1bSKiyoung Kim 		continue;
172*2810ac1bSKiyoung Kim 	    }
173*2810ac1bSKiyoung Kim 	    cap_iab_t old = cap_launcher_set_iab(attr, iab);
174*2810ac1bSKiyoung Kim 	    if (cap_free(old)) {
175*2810ac1bSKiyoung Kim 		fprintf(stderr, "[%d] failed to decode iab [%s]", i, v->iab);
176*2810ac1bSKiyoung Kim 		perror(":");
177*2810ac1bSKiyoung Kim 		success = 0;
178*2810ac1bSKiyoung Kim 		continue;
179*2810ac1bSKiyoung Kim 	    }
180*2810ac1bSKiyoung Kim 	}
181*2810ac1bSKiyoung Kim 	if (v->mode) {
182*2810ac1bSKiyoung Kim 	    cap_launcher_set_mode(attr, v->mode);
183*2810ac1bSKiyoung Kim 	}
184*2810ac1bSKiyoung Kim 
185*2810ac1bSKiyoung Kim 	pid_t child = cap_launch(attr, NULL);
186*2810ac1bSKiyoung Kim 
187*2810ac1bSKiyoung Kim 	if (child <= 0) {
188*2810ac1bSKiyoung Kim 	    fprintf(stderr, "[%d] failed to launch: ", i);
189*2810ac1bSKiyoung Kim 	    perror("");
190*2810ac1bSKiyoung Kim 	    if (!v->launch_abort) {
191*2810ac1bSKiyoung Kim 		success = 0;
192*2810ac1bSKiyoung Kim 	    }
193*2810ac1bSKiyoung Kim 	    continue;
194*2810ac1bSKiyoung Kim 	}
195*2810ac1bSKiyoung Kim 	if (cap_free(attr)) {
196*2810ac1bSKiyoung Kim 	    fprintf(stderr, "[%d] failed to free launcher: ", i);
197*2810ac1bSKiyoung Kim 	    perror("");
198*2810ac1bSKiyoung Kim 	    success = 0;
199*2810ac1bSKiyoung Kim 	}
200*2810ac1bSKiyoung Kim 	int result;
201*2810ac1bSKiyoung Kim 	int ret = waitpid(child, &result, 0);
202*2810ac1bSKiyoung Kim 	if (ret != child) {
203*2810ac1bSKiyoung Kim 	    fprintf(stderr, "[%d] failed to wait: ", i);
204*2810ac1bSKiyoung Kim 	    perror("");
205*2810ac1bSKiyoung Kim 	    success = 0;
206*2810ac1bSKiyoung Kim 	    continue;
207*2810ac1bSKiyoung Kim 	}
208*2810ac1bSKiyoung Kim 	if (result != v->result) {
209*2810ac1bSKiyoung Kim 	    fprintf(stderr, "[%d] bad result: got=%d want=%d: ", i, result,
210*2810ac1bSKiyoung Kim 		    v->result);
211*2810ac1bSKiyoung Kim 	    perror("");
212*2810ac1bSKiyoung Kim 	    success = 0;
213*2810ac1bSKiyoung Kim 	    continue;
214*2810ac1bSKiyoung Kim 	}
215*2810ac1bSKiyoung Kim     }
216*2810ac1bSKiyoung Kim 
217*2810ac1bSKiyoung Kim     cap_t final = cap_get_proc();
218*2810ac1bSKiyoung Kim     if (final == NULL) {
219*2810ac1bSKiyoung Kim 	perror("unable to get final capabilities");
220*2810ac1bSKiyoung Kim 	exit(1);
221*2810ac1bSKiyoung Kim     }
222*2810ac1bSKiyoung Kim     if (cap_compare(orig, final)) {
223*2810ac1bSKiyoung Kim 	char *was = cap_to_text(orig, NULL);
224*2810ac1bSKiyoung Kim 	char *is = cap_to_text(final, NULL);
225*2810ac1bSKiyoung Kim 	printf("cap_launch_test: orig:'%s' != final:'%s'\n", was, is);
226*2810ac1bSKiyoung Kim 	cap_free(is);
227*2810ac1bSKiyoung Kim 	cap_free(was);
228*2810ac1bSKiyoung Kim 	success = 0;
229*2810ac1bSKiyoung Kim     }
230*2810ac1bSKiyoung Kim     cap_free(final);
231*2810ac1bSKiyoung Kim     cap_free(orig);
232*2810ac1bSKiyoung Kim 
233*2810ac1bSKiyoung Kim     if (!success) {
234*2810ac1bSKiyoung Kim 	printf("cap_launch_test: FAILED\n");
235*2810ac1bSKiyoung Kim 	exit(1);
236*2810ac1bSKiyoung Kim     }
237*2810ac1bSKiyoung Kim     printf("cap_launch_test: PASSED\n");
238*2810ac1bSKiyoung Kim     exit(0);
239*2810ac1bSKiyoung Kim }
240