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