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