diff options
30 files changed, 578 insertions, 306 deletions
diff --git a/Makefile.in b/Makefile.in index d1f03c788..8251f9882 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -249,6 +249,10 @@ test: test-profiles test-fcopy test-fs test-utils test-environment test-apps te | |||
249 | # with them you will need to restart your computer. | 249 | # with them you will need to restart your computer. |
250 | ########################################## | 250 | ########################################## |
251 | 251 | ||
252 | # requires root access | ||
253 | test-chroot: | ||
254 | cd test/chroot; ./chroot.sh | grep testing | ||
255 | |||
252 | # Huge appimage files, not included in "make dist" archive | 256 | # Huge appimage files, not included in "make dist" archive |
253 | test-appimage: | 257 | test-appimage: |
254 | cd test/appimage; ./appimage.sh | grep TESTING | 258 | cd test/appimage; ./appimage.sh | grep TESTING |
@@ -268,6 +272,6 @@ test-overlay: | |||
268 | 272 | ||
269 | # For testing hidepid system, the command to set it up is "mount -o remount,rw,hidepid=2 /proc" | 273 | # For testing hidepid system, the command to set it up is "mount -o remount,rw,hidepid=2 /proc" |
270 | 274 | ||
271 | test-all: test-root test-network test-appimage test-overlay test-fcopy test | 275 | test-all: test-root test-chroot test-network test-appimage test-overlay |
272 | echo "TEST COMPLETE" | 276 | echo "TEST COMPLETE" |
273 | \ No newline at end of file | 277 | \ No newline at end of file |
@@ -13,9 +13,9 @@ gcov_init() { | |||
13 | } | 13 | } |
14 | 14 | ||
15 | generate() { | 15 | generate() { |
16 | lcov --capture -d src/firejail -d src/firemon -d src/fcopy -d src/fseccomp -d src/fnet -d src/ftee -d src/lib -d src/firecfg --output-file gcov-file | 16 | lcov -q --capture -d src/firejail -d src/firemon -d src/fcopy -d src/fseccomp -d src/fnet -d src/ftee -d src/lib -d src/firecfg --output-file gcov-file |
17 | rm -fr gcov-dir | 17 | rm -fr gcov-dir |
18 | genhtml gcov-file --output-directory gcov-dir | 18 | genhtml -q gcov-file --output-directory gcov-dir |
19 | } | 19 | } |
20 | 20 | ||
21 | gcov_init | 21 | gcov_init |
@@ -29,6 +29,10 @@ make test-root | |||
29 | generate | 29 | generate |
30 | sleep 2 | 30 | sleep 2 |
31 | 31 | ||
32 | make test-chroot | ||
33 | generate | ||
34 | sleep 2 | ||
35 | |||
32 | make test-network | 36 | make test-network |
33 | generate | 37 | generate |
34 | sleep 2 | 38 | sleep 2 |
diff --git a/src/firejail/caps.c b/src/firejail/caps.c index ba811cada..6cfa36629 100644 --- a/src/firejail/caps.c +++ b/src/firejail/caps.c | |||
@@ -181,12 +181,10 @@ static int caps_find_name(const char *name) { | |||
181 | } | 181 | } |
182 | 182 | ||
183 | // return 1 if error, 0 if OK | 183 | // return 1 if error, 0 if OK |
184 | int caps_check_list(const char *clist, void (*callback)(int)) { | 184 | void caps_check_list(const char *clist, void (*callback)(int)) { |
185 | // don't allow empty lists | 185 | // don't allow empty lists |
186 | if (clist == NULL || *clist == '\0') { | 186 | if (clist == NULL || *clist == '\0') |
187 | fprintf(stderr, "Error: empty capabilities lists are not allowed\n"); | 187 | goto errexit; |
188 | return -1; | ||
189 | } | ||
190 | 188 | ||
191 | // work on a copy of the string | 189 | // work on a copy of the string |
192 | char *str = strdup(clist); | 190 | char *str = strdup(clist); |
@@ -201,11 +199,8 @@ int caps_check_list(const char *clist, void (*callback)(int)) { | |||
201 | else if (*ptr == ',') { | 199 | else if (*ptr == ',') { |
202 | *ptr = '\0'; | 200 | *ptr = '\0'; |
203 | int nr = caps_find_name(start); | 201 | int nr = caps_find_name(start); |
204 | if (nr == -1) { | 202 | if (nr == -1) |
205 | fprintf(stderr, "Error: capability %s not found\n", start); | 203 | goto errexit; |
206 | free(str); | ||
207 | return -1; | ||
208 | } | ||
209 | else if (callback != NULL) | 204 | else if (callback != NULL) |
210 | callback(nr); | 205 | callback(nr); |
211 | 206 | ||
@@ -215,17 +210,18 @@ int caps_check_list(const char *clist, void (*callback)(int)) { | |||
215 | } | 210 | } |
216 | if (*start != '\0') { | 211 | if (*start != '\0') { |
217 | int nr = caps_find_name(start); | 212 | int nr = caps_find_name(start); |
218 | if (nr == -1) { | 213 | if (nr == -1) |
219 | fprintf(stderr, "Error: capability %s not found\n", start); | 214 | goto errexit; |
220 | free(str); | ||
221 | return -1; | ||
222 | } | ||
223 | else if (callback != NULL) | 215 | else if (callback != NULL) |
224 | callback(nr); | 216 | callback(nr); |
225 | } | 217 | } |
226 | 218 | ||
227 | free(str); | 219 | free(str); |
228 | return 0; | 220 | return; |
221 | |||
222 | errexit: | ||
223 | fprintf(stderr, "Error: capability \"%s\" not found\n", start); | ||
224 | exit(1); | ||
229 | } | 225 | } |
230 | 226 | ||
231 | void caps_print(void) { | 227 | void caps_print(void) { |
@@ -256,49 +252,53 @@ void caps_print(void) { | |||
256 | // enabled by default | 252 | // enabled by default |
257 | int caps_default_filter(void) { | 253 | int caps_default_filter(void) { |
258 | // drop capabilities | 254 | // drop capabilities |
259 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_MODULE, 0, 0, 0) && arg_debug) | 255 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_MODULE, 0, 0, 0)) |
260 | fprintf(stderr, "Warning: cannot drop CAP_SYS_MODULE"); | 256 | goto errexit; |
261 | else if (arg_debug) | 257 | else if (arg_debug) |
262 | printf("Drop CAP_SYS_MODULE\n"); | 258 | printf("Drop CAP_SYS_MODULE\n"); |
263 | 259 | ||
264 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_RAWIO, 0, 0, 0) && arg_debug) | 260 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_RAWIO, 0, 0, 0)) |
265 | fprintf(stderr, "Warning: cannot drop CAP_SYS_RAWIO"); | 261 | goto errexit; |
266 | else if (arg_debug) | 262 | else if (arg_debug) |
267 | printf("Drop CAP_SYS_RAWIO\n"); | 263 | printf("Drop CAP_SYS_RAWIO\n"); |
268 | 264 | ||
269 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0) && arg_debug) | 265 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) |
270 | fprintf(stderr, "Warning: cannot drop CAP_SYS_BOOT"); | 266 | goto errexit; |
271 | else if (arg_debug) | 267 | else if (arg_debug) |
272 | printf("Drop CAP_SYS_BOOT\n"); | 268 | printf("Drop CAP_SYS_BOOT\n"); |
273 | 269 | ||
274 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_NICE, 0, 0, 0) && arg_debug) | 270 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_NICE, 0, 0, 0)) |
275 | fprintf(stderr, "Warning: cannot drop CAP_SYS_NICE"); | 271 | goto errexit; |
276 | else if (arg_debug) | 272 | else if (arg_debug) |
277 | printf("Drop CAP_SYS_NICE\n"); | 273 | printf("Drop CAP_SYS_NICE\n"); |
278 | 274 | ||
279 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_TTY_CONFIG, 0, 0, 0) && arg_debug) | 275 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_TTY_CONFIG, 0, 0, 0)) |
280 | fprintf(stderr, "Warning: cannot drop CAP_SYS_TTY_CONFIG"); | 276 | goto errexit; |
281 | else if (arg_debug) | 277 | else if (arg_debug) |
282 | printf("Drop CAP_SYS_TTY_CONFIG\n"); | 278 | printf("Drop CAP_SYS_TTY_CONFIG\n"); |
283 | 279 | ||
284 | #ifdef CAP_SYSLOG | 280 | #ifdef CAP_SYSLOG |
285 | if (prctl(PR_CAPBSET_DROP, CAP_SYSLOG, 0, 0, 0) && arg_debug) | 281 | if (prctl(PR_CAPBSET_DROP, CAP_SYSLOG, 0, 0, 0)) |
286 | fprintf(stderr, "Warning: cannot drop CAP_SYSLOG"); | 282 | goto errexit; |
287 | else if (arg_debug) | 283 | else if (arg_debug) |
288 | printf("Drop CAP_SYSLOG\n"); | 284 | printf("Drop CAP_SYSLOG\n"); |
289 | #endif | 285 | #endif |
290 | 286 | ||
291 | if (prctl(PR_CAPBSET_DROP, CAP_MKNOD, 0, 0, 0) && arg_debug) | 287 | if (prctl(PR_CAPBSET_DROP, CAP_MKNOD, 0, 0, 0)) |
292 | fprintf(stderr, "Warning: cannot drop CAP_MKNOD"); | 288 | goto errexit; |
293 | else if (arg_debug) | 289 | else if (arg_debug) |
294 | printf("Drop CAP_MKNOD\n"); | 290 | printf("Drop CAP_MKNOD\n"); |
295 | 291 | ||
296 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_ADMIN, 0, 0, 0) && arg_debug) | 292 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_ADMIN, 0, 0, 0)) |
297 | fprintf(stderr, "Warning: cannot drop CAP_SYS_ADMIN"); | 293 | goto errexit; |
298 | else if (arg_debug) | 294 | else if (arg_debug) |
299 | printf("Drop CAP_SYS_ADMIN\n"); | 295 | printf("Drop CAP_SYS_ADMIN\n"); |
300 | 296 | ||
301 | return 0; | 297 | return 0; |
298 | |||
299 | errexit: | ||
300 | fprintf(stderr, "Error: cannot drop capabilities\n"); | ||
301 | exit(1); | ||
302 | } | 302 | } |
303 | 303 | ||
304 | void caps_drop_all(void) { | 304 | void caps_drop_all(void) { |
@@ -359,19 +359,14 @@ static uint64_t extract_caps(int pid) { | |||
359 | EUID_ASSERT(); | 359 | EUID_ASSERT(); |
360 | 360 | ||
361 | char *file; | 361 | char *file; |
362 | if (asprintf(&file, "/proc/%d/status", pid) == -1) { | 362 | if (asprintf(&file, "/proc/%d/status", pid) == -1) |
363 | errExit("asprintf"); | 363 | errExit("asprintf"); |
364 | exit(1); | ||
365 | } | ||
366 | 364 | ||
367 | EUID_ROOT(); // grsecurity | 365 | EUID_ROOT(); // grsecurity |
368 | FILE *fp = fopen(file, "r"); | 366 | FILE *fp = fopen(file, "r"); |
369 | EUID_USER(); // grsecurity | 367 | EUID_USER(); // grsecurity |
370 | if (!fp) { | 368 | if (!fp) |
371 | printf("Error: cannot open %s\n", file); | 369 | goto errexit; |
372 | free(file); | ||
373 | exit(1); | ||
374 | } | ||
375 | 370 | ||
376 | char buf[MAXBUF]; | 371 | char buf[MAXBUF]; |
377 | while (fgets(buf, MAXBUF, fp)) { | 372 | while (fgets(buf, MAXBUF, fp)) { |
@@ -385,6 +380,8 @@ static uint64_t extract_caps(int pid) { | |||
385 | } | 380 | } |
386 | } | 381 | } |
387 | fclose(fp); | 382 | fclose(fp); |
383 | |||
384 | errexit: | ||
388 | free(file); | 385 | free(file); |
389 | fprintf(stderr, "Error: cannot read caps configuration\n"); | 386 | fprintf(stderr, "Error: cannot read caps configuration\n"); |
390 | exit(1); | 387 | exit(1); |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 2e031ce04..4ae3cfd9f 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -508,7 +508,7 @@ int caps_default_filter(void); | |||
508 | void caps_print(void); | 508 | void caps_print(void); |
509 | void caps_drop_all(void); | 509 | void caps_drop_all(void); |
510 | void caps_set(uint64_t caps); | 510 | void caps_set(uint64_t caps); |
511 | int caps_check_list(const char *clist, void (*callback)(int)); | 511 | void caps_check_list(const char *clist, void (*callback)(int)); |
512 | void caps_drop_list(const char *clist); | 512 | void caps_drop_list(const char *clist); |
513 | void caps_keep_list(const char *clist); | 513 | void caps_keep_list(const char *clist); |
514 | void caps_print_filter(pid_t pid); | 514 | void caps_print_filter(pid_t pid); |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 5774ebf6a..8c776bad5 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -1042,6 +1042,9 @@ void fs_chroot(const char *rootdir) { | |||
1042 | if (chroot(rootdir) < 0) | 1042 | if (chroot(rootdir) < 0) |
1043 | errExit("chroot"); | 1043 | errExit("chroot"); |
1044 | 1044 | ||
1045 | // create all other /run/firejail files and directories | ||
1046 | preproc_build_firejail_dir(); | ||
1047 | |||
1045 | if (checkcfg(CFG_CHROOT_DESKTOP)) { | 1048 | if (checkcfg(CFG_CHROOT_DESKTOP)) { |
1046 | // update /var directory in order to support multiple sandboxes running on the same root directory | 1049 | // update /var directory in order to support multiple sandboxes running on the same root directory |
1047 | // if (!arg_private_dev) | 1050 | // if (!arg_private_dev) |
diff --git a/src/firejail/main.c b/src/firejail/main.c index ff7b762cd..111a1d751 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -1186,8 +1186,7 @@ int main(int argc, char **argv) { | |||
1186 | if (!arg_caps_list) | 1186 | if (!arg_caps_list) |
1187 | errExit("strdup"); | 1187 | errExit("strdup"); |
1188 | // verify caps list and exit if problems | 1188 | // verify caps list and exit if problems |
1189 | if (caps_check_list(arg_caps_list, NULL)) | 1189 | caps_check_list(arg_caps_list, NULL); |
1190 | return 1; | ||
1191 | } | 1190 | } |
1192 | else if (strncmp(argv[i], "--caps.keep=", 12) == 0) { | 1191 | else if (strncmp(argv[i], "--caps.keep=", 12) == 0) { |
1193 | arg_caps_keep = 1; | 1192 | arg_caps_keep = 1; |
@@ -1195,8 +1194,7 @@ int main(int argc, char **argv) { | |||
1195 | if (!arg_caps_list) | 1194 | if (!arg_caps_list) |
1196 | errExit("strdup"); | 1195 | errExit("strdup"); |
1197 | // verify caps list and exit if problems | 1196 | // verify caps list and exit if problems |
1198 | if (caps_check_list(arg_caps_list, NULL)) | 1197 | caps_check_list(arg_caps_list, NULL); |
1199 | return 1; | ||
1200 | } | 1198 | } |
1201 | 1199 | ||
1202 | 1200 | ||
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 688fa9609..abb8bd9b6 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -570,8 +570,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
570 | if (!arg_caps_list) | 570 | if (!arg_caps_list) |
571 | errExit("strdup"); | 571 | errExit("strdup"); |
572 | // verify caps list and exit if problems | 572 | // verify caps list and exit if problems |
573 | if (caps_check_list(arg_caps_list, NULL)) | 573 | caps_check_list(arg_caps_list, NULL); |
574 | exit(1); | ||
575 | return 0; | 574 | return 0; |
576 | } | 575 | } |
577 | 576 | ||
@@ -582,8 +581,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
582 | if (!arg_caps_list) | 581 | if (!arg_caps_list) |
583 | errExit("strdup"); | 582 | errExit("strdup"); |
584 | // verify caps list and exit if problems | 583 | // verify caps list and exit if problems |
585 | if (caps_check_list(arg_caps_list, NULL)) | 584 | caps_check_list(arg_caps_list, NULL); |
586 | exit(1); | ||
587 | return 0; | 585 | return 0; |
588 | } | 586 | } |
589 | 587 | ||
diff --git a/src/lib/common.c b/src/lib/common.c index 2f2340963..add4ff087 100644 --- a/src/lib/common.c +++ b/src/lib/common.c | |||
@@ -39,22 +39,23 @@ int join_namespace(pid_t pid, char *type) { | |||
39 | errExit("asprintf"); | 39 | errExit("asprintf"); |
40 | 40 | ||
41 | int fd = open(path, O_RDONLY); | 41 | int fd = open(path, O_RDONLY); |
42 | if (fd < 0) { | 42 | if (fd < 0) |
43 | free(path); | 43 | goto errout; |
44 | fprintf(stderr, "Error: cannot open /proc/%u/ns/%s.\n", pid, type); | ||
45 | return -1; | ||
46 | } | ||
47 | 44 | ||
48 | if (syscall(__NR_setns, fd, 0) < 0) { | 45 | if (syscall(__NR_setns, fd, 0) < 0) { |
49 | free(path); | ||
50 | fprintf(stderr, "Error: cannot join namespace %s.\n", type); | ||
51 | close(fd); | 46 | close(fd); |
52 | return -1; | 47 | goto errout; |
53 | } | 48 | } |
54 | 49 | ||
55 | close(fd); | 50 | close(fd); |
56 | free(path); | 51 | free(path); |
57 | return 0; | 52 | return 0; |
53 | |||
54 | errout: | ||
55 | free(path); | ||
56 | fprintf(stderr, "Error: cannot join namespace %s\\n", type); | ||
57 | return -1; | ||
58 | |||
58 | } | 59 | } |
59 | 60 | ||
60 | // return 1 if error | 61 | // return 1 if error |
@@ -187,8 +188,6 @@ char *pid_proc_cmdline(const pid_t pid) { | |||
187 | for (i = 0; i < len; i++) { | 188 | for (i = 0; i < len; i++) { |
188 | if (buffer[i] == '\0') | 189 | if (buffer[i] == '\0') |
189 | buffer[i] = ' '; | 190 | buffer[i] = ' '; |
190 | // if (buffer[i] >= 0x80) // execv in progress!!! | ||
191 | // return NULL; | ||
192 | } | 191 | } |
193 | 192 | ||
194 | // return a malloc copy of the command line | 193 | // return a malloc copy of the command line |
diff --git a/src/lib/libnetlink.c b/src/lib/libnetlink.c index 836cf417d..417ef2c5f 100644 --- a/src/lib/libnetlink.c +++ b/src/lib/libnetlink.c | |||
@@ -105,6 +105,7 @@ int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) | |||
105 | return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); | 105 | return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); |
106 | } | 106 | } |
107 | 107 | ||
108 | #if 0 | ||
108 | int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) | 109 | int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) |
109 | { | 110 | { |
110 | return rtnl_wilddump_req_filter(rth, family, type, RTEXT_FILTER_VF); | 111 | return rtnl_wilddump_req_filter(rth, family, type, RTEXT_FILTER_VF); |
@@ -303,6 +304,7 @@ int rtnl_dump_filter(struct rtnl_handle *rth, | |||
303 | 304 | ||
304 | return rtnl_dump_filter_l(rth, a); | 305 | return rtnl_dump_filter_l(rth, a); |
305 | } | 306 | } |
307 | #endif | ||
306 | 308 | ||
307 | int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, | 309 | int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, |
308 | unsigned groups, struct nlmsghdr *answer) | 310 | unsigned groups, struct nlmsghdr *answer) |
@@ -422,6 +424,7 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, | |||
422 | } | 424 | } |
423 | } | 425 | } |
424 | 426 | ||
427 | #if 0 | ||
425 | int rtnl_listen(struct rtnl_handle *rtnl, | 428 | int rtnl_listen(struct rtnl_handle *rtnl, |
426 | rtnl_filter_t handler, | 429 | rtnl_filter_t handler, |
427 | void *jarg) | 430 | void *jarg) |
@@ -580,7 +583,7 @@ int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str) | |||
580 | { | 583 | { |
581 | return addattr_l(n, maxlen, type, str, strlen(str)+1); | 584 | return addattr_l(n, maxlen, type, str, strlen(str)+1); |
582 | } | 585 | } |
583 | 586 | #endif | |
584 | 587 | ||
585 | 588 | ||
586 | int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, | 589 | int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, |
@@ -632,46 +635,8 @@ printf("\tdata length: %d\n", alen); | |||
632 | return 0; | 635 | return 0; |
633 | } | 636 | } |
634 | 637 | ||
635 | #if 0 | ||
636 | int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, | ||
637 | int alen) | ||
638 | { | ||
639 | printf("%s: adding type %d, length %d ", __FUNCTION__, type, alen); | ||
640 | if (type == IFLA_INFO_KIND) { | ||
641 | if (alen) | ||
642 | printf("(IFLA_INFO_KIND %s)\n", (char *)data); | ||
643 | else | ||
644 | printf("(VETH_INFO_PEER)\n"); | ||
645 | } | ||
646 | else if (type == IFLA_IFNAME) { | ||
647 | printf("(IFLA_IFNAME %s)\n", (char *) data); | ||
648 | } | ||
649 | else if (type == IFLA_NET_NS_PID) { | ||
650 | printf("(IFLA_NET_NS_PID %u)\n", *((unsigned *) data)); | ||
651 | } | ||
652 | else if (type == IFLA_LINKINFO) | ||
653 | printf("(IFLA_LINKINFO)\n"); | ||
654 | else if (type == IFLA_INFO_DATA) | ||
655 | printf("(IFLA_INFO_DATA)\n"); | ||
656 | else | ||
657 | printf("\n"); | ||
658 | |||
659 | int len = RTA_LENGTH(alen); | ||
660 | struct rtattr *rta; | ||
661 | |||
662 | if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { | ||
663 | fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen); | ||
664 | return -1; | ||
665 | } | ||
666 | rta = NLMSG_TAIL(n); | ||
667 | rta->rta_type = type; | ||
668 | rta->rta_len = len; | ||
669 | memcpy(RTA_DATA(rta), data, alen); | ||
670 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); | ||
671 | return 0; | ||
672 | } | ||
673 | #endif | ||
674 | 638 | ||
639 | #if 0 | ||
675 | int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len) | 640 | int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len) |
676 | { | 641 | { |
677 | if ((int)(NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len)) > maxlen) { | 642 | if ((int)(NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len)) > maxlen) { |
@@ -802,3 +767,4 @@ int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rt | |||
802 | memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); | 767 | memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); |
803 | return 0; | 768 | return 0; |
804 | } | 769 | } |
770 | #endif | ||
diff --git a/src/lib/pid.c b/src/lib/pid.c index ed583c51d..42687274e 100644 --- a/src/lib/pid.c +++ b/src/lib/pid.c | |||
@@ -34,10 +34,9 @@ int max_pids=32769; | |||
34 | void pid_getmem(unsigned pid, unsigned *rss, unsigned *shared) { | 34 | void pid_getmem(unsigned pid, unsigned *rss, unsigned *shared) { |
35 | // open stat file | 35 | // open stat file |
36 | char *file; | 36 | char *file; |
37 | if (asprintf(&file, "/proc/%u/statm", pid) == -1) { | 37 | if (asprintf(&file, "/proc/%u/statm", pid) == -1) |
38 | perror("asprintf"); | 38 | errExit("asprintf"); |
39 | exit(1); | 39 | |
40 | } | ||
41 | FILE *fp = fopen(file, "r"); | 40 | FILE *fp = fopen(file, "r"); |
42 | if (!fp) { | 41 | if (!fp) { |
43 | free(file); | 42 | free(file); |
@@ -59,10 +58,9 @@ void pid_getmem(unsigned pid, unsigned *rss, unsigned *shared) { | |||
59 | void pid_get_cpu_time(unsigned pid, unsigned *utime, unsigned *stime) { | 58 | void pid_get_cpu_time(unsigned pid, unsigned *utime, unsigned *stime) { |
60 | // open stat file | 59 | // open stat file |
61 | char *file; | 60 | char *file; |
62 | if (asprintf(&file, "/proc/%u/stat", pid) == -1) { | 61 | if (asprintf(&file, "/proc/%u/stat", pid) == -1) |
63 | perror("asprintf"); | 62 | errExit("asprintf"); |
64 | exit(1); | 63 | |
65 | } | ||
66 | FILE *fp = fopen(file, "r"); | 64 | FILE *fp = fopen(file, "r"); |
67 | if (!fp) { | 65 | if (!fp) { |
68 | free(file); | 66 | free(file); |
@@ -93,10 +91,9 @@ myexit: | |||
93 | unsigned long long pid_get_start_time(unsigned pid) { | 91 | unsigned long long pid_get_start_time(unsigned pid) { |
94 | // open stat file | 92 | // open stat file |
95 | char *file; | 93 | char *file; |
96 | if (asprintf(&file, "/proc/%u/stat", pid) == -1) { | 94 | if (asprintf(&file, "/proc/%u/stat", pid) == -1) |
97 | perror("asprintf"); | 95 | errExit("asprintf"); |
98 | exit(1); | 96 | |
99 | } | ||
100 | FILE *fp = fopen(file, "r"); | 97 | FILE *fp = fopen(file, "r"); |
101 | if (!fp) { | 98 | if (!fp) { |
102 | free(file); | 99 | free(file); |
@@ -138,10 +135,8 @@ uid_t pid_get_uid(pid_t pid) { | |||
138 | 135 | ||
139 | // open status file | 136 | // open status file |
140 | char *file; | 137 | char *file; |
141 | if (asprintf(&file, "/proc/%u/status", pid) == -1) { | 138 | if (asprintf(&file, "/proc/%u/status", pid) == -1) |
142 | perror("asprintf"); | 139 | errExit("asprintf"); |
143 | exit(1); | ||
144 | } | ||
145 | 140 | ||
146 | FILE *fp = fopen(file, "r"); | 141 | FILE *fp = fopen(file, "r"); |
147 | if (!fp) { | 142 | if (!fp) { |
@@ -316,10 +311,9 @@ void pid_read(pid_t mon_pid) { | |||
316 | 311 | ||
317 | // open stat file | 312 | // open stat file |
318 | char *file; | 313 | char *file; |
319 | if (asprintf(&file, "/proc/%u/status", pid) == -1) { | 314 | if (asprintf(&file, "/proc/%u/status", pid) == -1) |
320 | perror("asprintf"); | 315 | errExit("asprintf"); |
321 | exit(1); | 316 | |
322 | } | ||
323 | FILE *fp = fopen(file, "r"); | 317 | FILE *fp = fopen(file, "r"); |
324 | if (!fp) { | 318 | if (!fp) { |
325 | free(file); | 319 | free(file); |
diff --git a/src/tools/unchroot b/src/tools/unchroot deleted file mode 100755 index d32ce2682..000000000 --- a/src/tools/unchroot +++ /dev/null | |||
Binary files differ | |||
diff --git a/src/tools/unchroot.c b/src/tools/unchroot.c deleted file mode 100644 index 21731296e..000000000 --- a/src/tools/unchroot.c +++ /dev/null | |||
@@ -1,125 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <errno.h> | ||
4 | #include <fcntl.h> | ||
5 | #include <string.h> | ||
6 | #include <unistd.h> | ||
7 | #include <sys/stat.h> | ||
8 | #include <sys/types.h> | ||
9 | |||
10 | /* | ||
11 | ** You should set NEED_FCHDIR to 1 if the chroot() on your | ||
12 | ** system changes the working directory of the calling | ||
13 | ** process to the same directory as the process was chroot()ed | ||
14 | ** to. | ||
15 | ** | ||
16 | ** It is known that you do not need to set this value if you | ||
17 | ** running on Solaris 2.7 and below. | ||
18 | ** | ||
19 | */ | ||
20 | #define NEED_FCHDIR 0 | ||
21 | |||
22 | #define TEMP_DIR "waterbuffalo" | ||
23 | |||
24 | /* Break out of a chroot() environment in C */ | ||
25 | |||
26 | int main() { | ||
27 | int x; /* Used to move up a directory tree */ | ||
28 | int done=0; /* Are we done yet ? */ | ||
29 | #ifdef NEED_FCHDIR | ||
30 | int dir_fd; /* File descriptor to directory */ | ||
31 | #endif | ||
32 | struct stat sbuf; /* The stat() buffer */ | ||
33 | |||
34 | /* | ||
35 | ** First we create the temporary directory if it doesn't exist | ||
36 | */ | ||
37 | if (stat(TEMP_DIR,&sbuf)<0) { | ||
38 | if (errno==ENOENT) { | ||
39 | if (mkdir(TEMP_DIR,0755)<0) { | ||
40 | fprintf(stderr,"Failed to create %s - %s\n", TEMP_DIR, | ||
41 | strerror(errno)); | ||
42 | exit(1); | ||
43 | } | ||
44 | } | ||
45 | else { | ||
46 | fprintf(stderr,"Failed to stat %s - %s\n", TEMP_DIR, | ||
47 | strerror(errno)); | ||
48 | exit(1); | ||
49 | } | ||
50 | } | ||
51 | else if (!S_ISDIR(sbuf.st_mode)) { | ||
52 | fprintf(stderr,"Error - %s is not a directory!\n",TEMP_DIR); | ||
53 | exit(1); | ||
54 | } | ||
55 | |||
56 | #ifdef NEED_FCHDIR | ||
57 | /* | ||
58 | ** Now we open the current working directory | ||
59 | ** | ||
60 | ** Note: Only required if chroot() changes the calling program's | ||
61 | ** working directory to the directory given to chroot(). | ||
62 | ** | ||
63 | */ | ||
64 | if ((dir_fd=open(".",O_RDONLY))<0) { | ||
65 | fprintf(stderr,"Failed to open \".\" for reading - %s\n", | ||
66 | strerror(errno)); | ||
67 | exit(1); | ||
68 | } | ||
69 | #endif | ||
70 | |||
71 | /* | ||
72 | ** Next we chroot() to the temporary directory | ||
73 | */ | ||
74 | if (chroot(TEMP_DIR)<0) { | ||
75 | fprintf(stderr,"Failed to chroot to %s - %s\n",TEMP_DIR, | ||
76 | strerror(errno)); | ||
77 | exit(1); | ||
78 | } | ||
79 | |||
80 | #ifdef NEED_FCHDIR | ||
81 | /* | ||
82 | ** Partially break out of the chroot by doing an fchdir() | ||
83 | ** | ||
84 | ** This only partially breaks out of the chroot() since whilst | ||
85 | ** our current working directory is outside of the chroot() jail, | ||
86 | ** our root directory is still within it. Thus anything which refers | ||
87 | ** to "/" will refer to files under the chroot() point. | ||
88 | ** | ||
89 | ** Note: Only required if chroot() changes the calling program's | ||
90 | ** working directory to the directory given to chroot(). | ||
91 | ** | ||
92 | */ | ||
93 | if (fchdir(dir_fd)<0) { | ||
94 | fprintf(stderr,"Failed to fchdir - %s\n", | ||
95 | strerror(errno)); | ||
96 | exit(1); | ||
97 | } | ||
98 | close(dir_fd); | ||
99 | #endif | ||
100 | |||
101 | /* | ||
102 | ** Completely break out of the chroot by recursing up the directory | ||
103 | ** tree and doing a chroot to the current working directory (which will | ||
104 | ** be the real "/" at that point). We just do a chdir("..") lots of | ||
105 | ** times (1024 times for luck :). If we hit the real root directory before | ||
106 | ** we have finished the loop below it doesn't matter as .. in the root | ||
107 | ** directory is the same as . in the root. | ||
108 | ** | ||
109 | ** We do the final break out by doing a chroot(".") which sets the root | ||
110 | ** directory to the current working directory - at this point the real | ||
111 | ** root directory. | ||
112 | */ | ||
113 | for(x=0;x<1024;x++) { | ||
114 | chdir(".."); | ||
115 | } | ||
116 | chroot("."); | ||
117 | |||
118 | /* | ||
119 | ** We're finally out - so exec a shell in interactive mode | ||
120 | */ | ||
121 | if (execl("/bin/sh","-i",NULL)<0) { | ||
122 | fprintf(stderr,"Failed to exec - %s\n",strerror(errno)); | ||
123 | exit(1); | ||
124 | } | ||
125 | } | ||
diff --git a/test/chroot/chroot-resolvconf.exp b/test/chroot/chroot-resolvconf.exp deleted file mode 100755 index 2d0da2fb0..000000000 --- a/test/chroot/chroot-resolvconf.exp +++ /dev/null | |||
@@ -1,14 +0,0 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | |||
3 | set timeout 10 | ||
4 | spawn $env(SHELL) | ||
5 | match_max 100000 | ||
6 | |||
7 | send -- "firejail --chroot=/tmp/chroot /bin/bash\r" | ||
8 | expect { | ||
9 | timeout {puts "TESTING ERROR 0\n";exit} | ||
10 | "invalid /tmp/chroot/etc/resolv.conf file" | ||
11 | } | ||
12 | |||
13 | puts "\nall done\n" | ||
14 | |||
diff --git a/test/chroot/chroot.sh b/test/chroot/chroot.sh new file mode 100755 index 000000000..34bff2a67 --- /dev/null +++ b/test/chroot/chroot.sh | |||
@@ -0,0 +1,21 @@ | |||
1 | #!/bin/bash | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2016 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | export MALLOC_CHECK_=3 | ||
7 | export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) | ||
8 | |||
9 | rm -f unchroot | ||
10 | gcc -o unchroot unchroot.c | ||
11 | sudo ./configure | ||
12 | |||
13 | echo "TESTING: chroot (test/chroot/fs_chroot.exp)" | ||
14 | ./fs_chroot.exp | ||
15 | |||
16 | echo "TESTING: unchroot as root (test/chroot/unchroot-as-root.exp)" | ||
17 | sudo ./unchroot-as-root.exp | ||
18 | |||
19 | |||
20 | |||
21 | rm -f unchroot | ||
diff --git a/test/chroot/configure b/test/chroot/configure new file mode 100755 index 000000000..ba8238803 --- /dev/null +++ b/test/chroot/configure | |||
@@ -0,0 +1,46 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # build a very small chroot | ||
4 | ROOTDIR="/tmp/chroot" # default chroot directory | ||
5 | DEFAULT_FILES="/bin/bash /bin/sh " # basic chroot files | ||
6 | DEFAULT_FILES+="/etc/passwd /etc/nsswitch.conf /etc/group " | ||
7 | DEFAULT_FILES+=`find /lib -name libnss*` # files required by glibc | ||
8 | DEFAULT_FILES+=" /bin/cp /bin/ls /bin/cat /bin/ps /bin/netstat /bin/ping /sbin/ifconfig /usr/bin/touch /bin/ip /bin/hostname /bin/grep /usr/bin/dig /usr/bin/openssl /usr/bin/id /usr/bin/getent /usr/bin/whoami /usr/bin/wc /usr/bin/wget /bin/umount" | ||
9 | |||
10 | rm -fr $ROOTDIR | ||
11 | mkdir -p $ROOTDIR/{root,bin,lib,lib64,usr,home,etc,dev/shm,tmp,var/run,var/tmp,var/lock,var/log,proc} | ||
12 | chmod 777 $ROOTDIR/tmp | ||
13 | mkdir -p $ROOTDIR/etc/firejail | ||
14 | mkdir -p $ROOTDIR/home/netblue/.config/firejail | ||
15 | chown netblue:netblue $ROOTDIR/home/netblue | ||
16 | chown netblue:netblue $ROOTDIR/home/netblue/.config | ||
17 | cp /home/netblue/.Xauthority $ROOTDIR/home/netblue/. | ||
18 | cp -a /etc/skel $ROOTDIR/etc/. | ||
19 | mkdir $ROOTDIR/home/someotheruser | ||
20 | mkdir $ROOTDIR/boot | ||
21 | mkdir $ROOTDIR/selinux | ||
22 | cp /etc/passwd $ROOTDIR/etc/. | ||
23 | cp /etc/group $ROOTDIR/etc/. | ||
24 | cp /etc/hosts $ROOTDIR/etc/. | ||
25 | cp /etc/hostname $ROOTDIR/etc/. | ||
26 | mkdir -p $ROOTDIR/usr/lib/x86_64-linux-gnu | ||
27 | cp -a /usr/lib/x86_64-linux-gnu/openssl-1.0.0 $ROOTDIR/usr/lib/x86_64-linux-gnu/. | ||
28 | cp -a /usr/lib/ssl $ROOTDIR/usr/lib/. | ||
29 | touch $ROOTDIR/var/log/syslog | ||
30 | touch $ROOTDIR/var/tmp/somefile | ||
31 | SORTED=`for FILE in $* $DEFAULT_FILES; do echo " $FILE "; ldd $FILE | grep -v dynamic | cut -d " " -f 3; done | sort -u` | ||
32 | for FILE in $SORTED | ||
33 | do | ||
34 | cp --parents $FILE $ROOTDIR | ||
35 | done | ||
36 | cp --parents /lib64/ld-linux-x86-64.so.2 $ROOTDIR | ||
37 | cp --parents /lib/ld-linux.so.2 $ROOTDIR | ||
38 | cp unchroot $ROOTDIR/. | ||
39 | touch $ROOTDIR/this-is-my-chroot | ||
40 | |||
41 | cd $ROOTDIR; find . | ||
42 | mkdir -p usr/lib/firejail/ | ||
43 | cp /usr/lib/firejail/libtrace.so usr/lib/firejail/. | ||
44 | |||
45 | |||
46 | echo "To enter the chroot directory run: firejail --chroot=$ROOTDIR" | ||
diff --git a/test/chroot/fs_chroot.exp b/test/chroot/fs_chroot.exp index aeb5669e1..295ff8ff9 100755 --- a/test/chroot/fs_chroot.exp +++ b/test/chroot/fs_chroot.exp | |||
@@ -20,19 +20,14 @@ expect { | |||
20 | sleep 1 | 20 | sleep 1 |
21 | send -- "bash\r" | 21 | send -- "bash\r" |
22 | sleep 1 | 22 | sleep 1 |
23 | send -- "ls /; pwd\r" | 23 | send -- "ls /\r" |
24 | expect { | 24 | expect { |
25 | timeout {puts "TESTING ERROR 0.2\n";exit} | 25 | timeout {puts "TESTING ERROR 0.2\n";exit} |
26 | "this-is-my-chroot" | 26 | "this-is-my-chroot" |
27 | } | 27 | } |
28 | expect { | 28 | after 100 |
29 | timeout {puts "TESTING ERROR 0.3\n";exit} | ||
30 | "home" | ||
31 | } | ||
32 | |||
33 | 29 | ||
34 | 30 | send -- "ps aux\r" | |
35 | send -- "ps aux; pwd\r" | ||
36 | expect { | 31 | expect { |
37 | timeout {puts "TESTING ERROR 1\n";exit} | 32 | timeout {puts "TESTING ERROR 1\n";exit} |
38 | "/bin/bash" | 33 | "/bin/bash" |
@@ -45,23 +40,14 @@ expect { | |||
45 | timeout {puts "TESTING ERROR 3\n";exit} | 40 | timeout {puts "TESTING ERROR 3\n";exit} |
46 | "ps aux" | 41 | "ps aux" |
47 | } | 42 | } |
48 | expect { | 43 | after 100 |
49 | timeout {puts "TESTING ERROR 4\n";exit} | ||
50 | "home" | ||
51 | } | ||
52 | sleep 1 | ||
53 | 44 | ||
54 | 45 | send -- "ps aux | wc -l; pwd\r" | |
55 | send -- "ps aux |wc -l; pwd\r" | ||
56 | expect { | 46 | expect { |
57 | timeout {puts "TESTING ERROR 5\n";exit} | 47 | timeout {puts "TESTING ERROR 5\n";exit} |
58 | "6" | 48 | "6" |
59 | } | 49 | } |
60 | expect { | 50 | after 100 |
61 | timeout {puts "TESTING ERROR 6\n";exit} | ||
62 | "home" | ||
63 | } | ||
64 | sleep 1 | ||
65 | 51 | ||
66 | 52 | ||
67 | puts "all done\n" | 53 | puts "all done\n" |
diff --git a/test/chroot/unchroot-as-root.exp b/test/chroot/unchroot-as-root.exp new file mode 100755 index 000000000..9f8a1d784 --- /dev/null +++ b/test/chroot/unchroot-as-root.exp | |||
@@ -0,0 +1,27 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | |||
3 | set timeout 10 | ||
4 | spawn $env(SHELL) | ||
5 | match_max 100000 | ||
6 | |||
7 | send -- "firejail --chroot=/tmp/chroot\r" | ||
8 | expect { | ||
9 | timeout {puts "TESTING ERROR 0\n";exit} | ||
10 | "Error: --chroot option is not available on Grsecurity systems" {puts "\nall done\n"; exit} | ||
11 | "Child process initialized" {puts "chroot available\n"}; | ||
12 | } | ||
13 | sleep 1 | ||
14 | |||
15 | send -- "cd /\r" | ||
16 | after 100 | ||
17 | |||
18 | |||
19 | send -- "./unchroot\r" | ||
20 | expect { | ||
21 | timeout {puts "TESTING ERROR 1\n";exit} | ||
22 | "Bad system call" | ||
23 | } | ||
24 | after 100 | ||
25 | |||
26 | puts "all done\n" | ||
27 | |||
diff --git a/test/chroot/unchroot.c b/test/chroot/unchroot.c new file mode 100644 index 000000000..1982e07f3 --- /dev/null +++ b/test/chroot/unchroot.c | |||
@@ -0,0 +1,40 @@ | |||
1 | // simple unchroot example from http://linux-vserver.org/Secure_chroot_Barrier | ||
2 | #include <unistd.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <stdio.h> | ||
5 | #include <sys/types.h> | ||
6 | #include <sys/stat.h> | ||
7 | |||
8 | void die(char *msg) { | ||
9 | perror(msg); | ||
10 | exit(1); | ||
11 | } | ||
12 | |||
13 | int main(int argc, char *argv[]) | ||
14 | { | ||
15 | int i; | ||
16 | |||
17 | if (chdir("/") != 0) | ||
18 | die("chdir(/)"); | ||
19 | |||
20 | if (mkdir("baz", 0777) != 0) | ||
21 | ; //die("mkdir(baz)"); | ||
22 | |||
23 | if (chroot("baz") != 0) | ||
24 | die("chroot(baz)"); | ||
25 | |||
26 | for (i=0; i<50; i++) { | ||
27 | if (chdir("..") != 0) | ||
28 | die("chdir(..)"); | ||
29 | } | ||
30 | |||
31 | if (chroot(".") != 0) | ||
32 | die("chroot(.)"); | ||
33 | |||
34 | printf("Exploit seems to work. =)\n"); | ||
35 | |||
36 | execl("/bin/bash", "bash", "-i", (char *)0); | ||
37 | die("exec bash"); | ||
38 | |||
39 | exit(0); | ||
40 | } | ||
diff --git a/test/environment/dns.exp b/test/environment/dns.exp index a6a7171eb..40403aade 100755 --- a/test/environment/dns.exp +++ b/test/environment/dns.exp | |||
@@ -4,6 +4,31 @@ set timeout 30 | |||
4 | spawn $env(SHELL) | 4 | spawn $env(SHELL) |
5 | match_max 100000 | 5 | match_max 100000 |
6 | 6 | ||
7 | send -- "firejail --dns=8.8.4.4 --dns=8.8.8.8 --dns=4.2.2.1\r" | ||
8 | expect { | ||
9 | timeout {puts "TESTING ERROR 2.1\n";exit} | ||
10 | "Child process initialized" | ||
11 | } | ||
12 | sleep 1 | ||
13 | |||
14 | send -- "cat /etc/resolv.conf\r" | ||
15 | expect { | ||
16 | timeout {puts "TESTING ERROR 2.2\n";exit} | ||
17 | "nameserver 8.8.4.4" | ||
18 | } | ||
19 | expect { | ||
20 | timeout {puts "TESTING ERROR 2.3\n";exit} | ||
21 | "nameserver 8.8.8.8" | ||
22 | } | ||
23 | expect { | ||
24 | timeout {puts "TESTING ERROR 2.4\n";exit} | ||
25 | "nameserver 4.2.2.1" | ||
26 | } | ||
27 | after 100 | ||
28 | send -- "exit\r" | ||
29 | after 100 | ||
30 | |||
31 | |||
7 | # no chroot | 32 | # no chroot |
8 | send -- "firejail --trace --dns=208.67.222.222 wget -q debian.org\r" | 33 | send -- "firejail --trace --dns=208.67.222.222 wget -q debian.org\r" |
9 | expect { | 34 | expect { |
@@ -27,28 +52,6 @@ after 100 | |||
27 | send -- "rm index.html\r" | 52 | send -- "rm index.html\r" |
28 | after 100 | 53 | after 100 |
29 | send -- "exit\r" | 54 | send -- "exit\r" |
30 | sleep 1 | ||
31 | |||
32 | send -- "firejail --dns=8.8.4.4 --dns=8.8.8.8 --dns=4.2.2.1\r" | ||
33 | expect { | ||
34 | timeout {puts "TESTING ERROR 2.1\n";exit} | ||
35 | "Child process initialized" | ||
36 | } | ||
37 | sleep 1 | ||
38 | |||
39 | send -- "cat /etc/resolv.conf\r" | ||
40 | expect { | ||
41 | timeout {puts "TESTING ERROR 2.2\n";exit} | ||
42 | "nameserver 8.8.4.4" | ||
43 | } | ||
44 | expect { | ||
45 | timeout {puts "TESTING ERROR 2.3\n";exit} | ||
46 | "nameserver 8.8.8.8" | ||
47 | } | ||
48 | expect { | ||
49 | timeout {puts "TESTING ERROR 2.4\n";exit} | ||
50 | "nameserver 4.2.2.1" | ||
51 | } | ||
52 | after 100 | 55 | after 100 |
53 | 56 | ||
54 | puts "\nall done\n" | 57 | puts "\nall done\n" |
diff --git a/test/filters/caps-print.exp b/test/filters/caps-print.exp new file mode 100755 index 000000000..d9d662239 --- /dev/null +++ b/test/filters/caps-print.exp | |||
@@ -0,0 +1,103 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2016 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | set timeout 10 | ||
7 | spawn $env(SHELL) | ||
8 | match_max 100000 | ||
9 | |||
10 | send -- "firejail --name=test --noprofile --caps --debug\r" | ||
11 | expect { | ||
12 | timeout {puts "TESTING ERROR 0\n";exit} | ||
13 | "Drop CAP_SYS_MODULE" | ||
14 | } | ||
15 | expect { | ||
16 | timeout {puts "TESTING ERROR 1\n";exit} | ||
17 | "Drop CAP_SYS_RAWIO" | ||
18 | } | ||
19 | expect { | ||
20 | timeout {puts "TESTING ERROR 2\n";exit} | ||
21 | "Drop CAP_SYS_BOOT" | ||
22 | } | ||
23 | expect { | ||
24 | timeout {puts "TESTING ERROR 3\n";exit} | ||
25 | "Drop CAP_SYS_NICE" | ||
26 | } | ||
27 | expect { | ||
28 | timeout {puts "TESTING ERROR 4\n";exit} | ||
29 | "Drop CAP_SYS_TTY_CONFIG" | ||
30 | } | ||
31 | expect { | ||
32 | timeout {puts "TESTING ERROR 5\n";exit} | ||
33 | "Drop CAP_SYSLOG" | ||
34 | } | ||
35 | expect { | ||
36 | timeout {puts "TESTING ERROR 6\n";exit} | ||
37 | "Drop CAP_MKNOD" | ||
38 | } | ||
39 | expect { | ||
40 | timeout {puts "TESTING ERROR 7\n";exit} | ||
41 | "Drop CAP_SYS_ADMIN" | ||
42 | } | ||
43 | expect { | ||
44 | timeout {puts "TESTING ERROR 8\n";exit} | ||
45 | "Child process initialized" | ||
46 | } | ||
47 | sleep 1 | ||
48 | |||
49 | spawn $env(SHELL) | ||
50 | send -- "firejail --caps.print=test\r" | ||
51 | expect { | ||
52 | timeout {puts "TESTING ERROR 9\n";exit} | ||
53 | "chown - enabled" | ||
54 | } | ||
55 | expect { | ||
56 | timeout {puts "TESTING ERROR 10\n";exit} | ||
57 | "setgid - enabled" | ||
58 | } | ||
59 | expect { | ||
60 | timeout {puts "TESTING ERROR 11\n";exit} | ||
61 | "setuid - enabled" | ||
62 | } | ||
63 | expect { | ||
64 | timeout {puts "TESTING ERROR 12\n";exit} | ||
65 | "mknod - disabled" | ||
66 | } | ||
67 | expect { | ||
68 | timeout {puts "TESTING ERROR 13\n";exit} | ||
69 | "syslog - disabled" | ||
70 | } | ||
71 | after 100 | ||
72 | |||
73 | send -- "firejail --debug-caps\r" | ||
74 | expect { | ||
75 | timeout {puts "TESTING ERROR 9\n";exit} | ||
76 | "21 - sys_admin" | ||
77 | } | ||
78 | expect { | ||
79 | timeout {puts "TESTING ERROR 9\n";exit} | ||
80 | "22 - sys_boot" | ||
81 | } | ||
82 | expect { | ||
83 | timeout {puts "TESTING ERROR 9\n";exit} | ||
84 | "23 - sys_nice" | ||
85 | } | ||
86 | expect { | ||
87 | timeout {puts "TESTING ERROR 9\n";exit} | ||
88 | "24 - sys_resource" | ||
89 | } | ||
90 | after 100 | ||
91 | |||
92 | send -- "firejail --caps.keep=\"bla bla bla\"\r" | ||
93 | expect { | ||
94 | timeout {puts "TESTING ERROR 10\n";exit} | ||
95 | "capability" | ||
96 | } | ||
97 | expect { | ||
98 | timeout {puts "TESTING ERROR 11\n";exit} | ||
99 | "not found" | ||
100 | } | ||
101 | |||
102 | after 100 | ||
103 | puts "\nall done\n" | ||
diff --git a/test/filters/caps.exp b/test/filters/caps.exp index 7f7cf7dd1..2954f2e58 100755 --- a/test/filters/caps.exp +++ b/test/filters/caps.exp | |||
@@ -12,7 +12,7 @@ expect { | |||
12 | timeout {puts "TESTING ERROR 1\n";exit} | 12 | timeout {puts "TESTING ERROR 1\n";exit} |
13 | "Child process initialized" | 13 | "Child process initialized" |
14 | } | 14 | } |
15 | sleep 2 | 15 | after 100 |
16 | 16 | ||
17 | send -- "cat /proc/self/status\r" | 17 | send -- "cat /proc/self/status\r" |
18 | expect { | 18 | expect { |
@@ -31,7 +31,7 @@ expect { | |||
31 | timeout {puts "TESTING ERROR 4\n";exit} | 31 | timeout {puts "TESTING ERROR 4\n";exit} |
32 | "Child process initialized" | 32 | "Child process initialized" |
33 | } | 33 | } |
34 | sleep 2 | 34 | after 100 |
35 | 35 | ||
36 | send -- "cat /proc/self/status\r" | 36 | send -- "cat /proc/self/status\r" |
37 | expect { | 37 | expect { |
@@ -50,7 +50,7 @@ expect { | |||
50 | timeout {puts "TESTING ERROR 7\n";exit} | 50 | timeout {puts "TESTING ERROR 7\n";exit} |
51 | "Child process initialized" | 51 | "Child process initialized" |
52 | } | 52 | } |
53 | sleep 2 | 53 | after 100 |
54 | 54 | ||
55 | send -- "cat /proc/self/status\r" | 55 | send -- "cat /proc/self/status\r" |
56 | expect { | 56 | expect { |
@@ -66,7 +66,74 @@ expect { | |||
66 | "Seccomp:" | 66 | "Seccomp:" |
67 | } | 67 | } |
68 | send -- "exit\r" | 68 | send -- "exit\r" |
69 | sleep 1 | ||
70 | |||
71 | |||
72 | send -- "firejail --profile=caps1.profile --debug\r" | ||
73 | expect { | ||
74 | timeout {puts "TESTING ERROR 11\n";exit} | ||
75 | "Drop CAP_SYS_MODULE" | ||
76 | } | ||
77 | expect { | ||
78 | timeout {puts "TESTING ERROR 12\n";exit} | ||
79 | "Drop CAP_SYS_ADMIN" | ||
80 | } | ||
81 | expect { | ||
82 | timeout {puts "TESTING ERROR 13\n";exit} | ||
83 | "Drop CAP_" {puts "TESTING ERROR 14\n";exit} | ||
84 | "Child process initialized" | ||
85 | } | ||
69 | after 100 | 86 | after 100 |
87 | send -- "exit\r" | ||
88 | sleep 1 | ||
70 | 89 | ||
71 | 90 | ||
91 | ## tofix: possible problem with caps.keep in profile files | ||
92 | ##send -- "firejail --caps.keep=chown,fowner --noprofile\r" | ||
93 | #send -- "firejail --profile=caps2.profile\r" | ||
94 | #expect { | ||
95 | # timeout {puts "TESTING ERROR 15\n";exit} | ||
96 | # "Child process initialized" | ||
97 | #} | ||
98 | #after 100 | ||
99 | # | ||
100 | #send -- "cat /proc/self/status\r" | ||
101 | #expect { | ||
102 | # timeout {puts "TESTING ERROR 16\n";exit} | ||
103 | # "CapBnd: 0000000000000009" | ||
104 | #} | ||
105 | #expect { | ||
106 | # timeout {puts "TESTING ERROR 17\n";exit} | ||
107 | # "Seccomp:" | ||
108 | #} | ||
109 | #send -- "exit\r" | ||
110 | #sleep 1 | ||
111 | |||
112 | #send -- "firejail --caps.drop=chown,dac_override,dac_read_search,fowner --noprofile\r" | ||
113 | send -- "firejail --profile=caps3.profile\r" | ||
114 | expect { | ||
115 | timeout {puts "TESTING ERROR 18\n";exit} | ||
116 | "Child process initialized" | ||
117 | } | ||
118 | after 100 | ||
119 | |||
120 | send -- "cat /proc/self/status\r" | ||
121 | expect { | ||
122 | timeout {puts "TESTING ERROR 19\n";exit} | ||
123 | "CapBnd:" | ||
124 | } | ||
125 | expect { | ||
126 | timeout {puts "TESTING ERROR 20\n";exit} | ||
127 | "fffffff0" | ||
128 | } | ||
129 | expect { | ||
130 | timeout {puts "TESTING ERROR 21\n";exit} | ||
131 | "Seccomp:" | ||
132 | } | ||
133 | send -- "exit\r" | ||
134 | sleep 1 | ||
135 | |||
136 | |||
137 | |||
138 | after 100 | ||
72 | puts "\nall done\n" | 139 | puts "\nall done\n" |
diff --git a/test/filters/caps1.profile b/test/filters/caps1.profile new file mode 100644 index 000000000..8b0c3b340 --- /dev/null +++ b/test/filters/caps1.profile | |||
@@ -0,0 +1 @@ | |||
caps | |||
diff --git a/test/filters/caps2.profile b/test/filters/caps2.profile new file mode 100644 index 000000000..4f0016fad --- /dev/null +++ b/test/filters/caps2.profile | |||
@@ -0,0 +1 @@ | |||
caps.drop chown,dac_override,dac_read_search,fowner \ No newline at end of file | |||
diff --git a/test/filters/caps3.profile b/test/filters/caps3.profile new file mode 100644 index 000000000..4f0016fad --- /dev/null +++ b/test/filters/caps3.profile | |||
@@ -0,0 +1 @@ | |||
caps.drop chown,dac_override,dac_read_search,fowner \ No newline at end of file | |||
diff --git a/test/filters/filters.sh b/test/filters/filters.sh index 5c7c98b3e..fea4a0296 100755 --- a/test/filters/filters.sh +++ b/test/filters/filters.sh | |||
@@ -12,6 +12,9 @@ echo "TESTING: noroot (test/filters/noroot.exp)" | |||
12 | echo "TESTING: capabilities (test/filters/caps.exp)" | 12 | echo "TESTING: capabilities (test/filters/caps.exp)" |
13 | ./caps.exp | 13 | ./caps.exp |
14 | 14 | ||
15 | echo "TESTING: capabilities print (test/filters/caps-print.exp)" | ||
16 | ./caps-print.exp | ||
17 | |||
15 | rm -f seccomp-test-file | 18 | rm -f seccomp-test-file |
16 | if [ "$(uname -m)" = "x86_64" ]; then | 19 | if [ "$(uname -m)" = "x86_64" ]; then |
17 | echo "TESTING: fseccomp (test/filters/fseccomp.exp)" | 20 | echo "TESTING: fseccomp (test/filters/fseccomp.exp)" |
diff --git a/test/fs/fs.sh b/test/fs/fs.sh index 1c5473f79..d9a425661 100755 --- a/test/fs/fs.sh +++ b/test/fs/fs.sh | |||
@@ -61,6 +61,9 @@ echo "TESTING: whitelist empty (test/fs/whitelist-empty.exp)" | |||
61 | echo "TESTING: private whitelist (test/fs/private-whitelist.exp)" | 61 | echo "TESTING: private whitelist (test/fs/private-whitelist.exp)" |
62 | ./private-whitelist.exp | 62 | ./private-whitelist.exp |
63 | 63 | ||
64 | echo "TESTING: whitelist ~/Downloads (test/fs/whitelist-downloads.exp)" | ||
65 | ./whitelist-downloads.exp | ||
66 | |||
64 | echo "TESTING: invalid filename (test/fs/invalid_filename.exp)" | 67 | echo "TESTING: invalid filename (test/fs/invalid_filename.exp)" |
65 | ./invalid_filename.exp | 68 | ./invalid_filename.exp |
66 | 69 | ||
diff --git a/test/fs/user-dirs.dirs b/test/fs/user-dirs.dirs new file mode 100644 index 000000000..0d19da4e4 --- /dev/null +++ b/test/fs/user-dirs.dirs | |||
@@ -0,0 +1,15 @@ | |||
1 | # This file is written by xdg-user-dirs-update | ||
2 | # If you want to change or add directories, just edit the line you're | ||
3 | # interested in. All local changes will be retained on the next run | ||
4 | # Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped | ||
5 | # homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an | ||
6 | # absolute path. No other format is supported. | ||
7 | # | ||
8 | XDG_DESKTOP_DIR="$HOME/Desktop" | ||
9 | XDG_DOWNLOAD_DIR="$HOME/Downloads" | ||
10 | XDG_TEMPLATES_DIR="$HOME/Templates" | ||
11 | XDG_PUBLICSHARE_DIR="$HOME/Public" | ||
12 | XDG_DOCUMENTS_DIR="$HOME/Documents" | ||
13 | XDG_MUSIC_DIR="$HOME/Music" | ||
14 | XDG_PICTURES_DIR="$HOME/Pictures" | ||
15 | XDG_VIDEOS_DIR="$HOME/Videos" | ||
diff --git a/test/fs/whitelist-downloads.exp b/test/fs/whitelist-downloads.exp new file mode 100755 index 000000000..6af318d2b --- /dev/null +++ b/test/fs/whitelist-downloads.exp | |||
@@ -0,0 +1,49 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2016 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | set timeout 10 | ||
7 | spawn $env(SHELL) | ||
8 | match_max 100000 | ||
9 | |||
10 | send -- "cp user-dirs.dirs /tmp/.\r" | ||
11 | after 100 | ||
12 | |||
13 | send -- "firejail --private --noprofile\r" | ||
14 | expect { | ||
15 | timeout {puts "TESTING ERROR 0\n";exit} | ||
16 | "Child process initialized" | ||
17 | } | ||
18 | after 100 | ||
19 | |||
20 | send -- "firejail --force --profile=/etc/firejail/firefox.profile\r" | ||
21 | expect { | ||
22 | timeout {puts "TESTING ERROR 1\n";exit} | ||
23 | "cannot whitelist Downloads directory" | ||
24 | } | ||
25 | expect { | ||
26 | timeout {puts "TESTING ERROR 2\n";exit} | ||
27 | "Child process initialized" | ||
28 | } | ||
29 | after 100 | ||
30 | |||
31 | send -- "exit\r" | ||
32 | after 100 | ||
33 | |||
34 | send -- "cp /tmp/user-dirs.dirs ~/.config/.\r" | ||
35 | after 100 | ||
36 | |||
37 | send -- "firejail --force --profile=/etc/firejail/firefox.profile\r" | ||
38 | expect { | ||
39 | timeout {puts "TESTING ERROR 3\n";exit} | ||
40 | "cannot whitelist Downloads directory" | ||
41 | } | ||
42 | expect { | ||
43 | timeout {puts "TESTING ERROR 4\n";exit} | ||
44 | "Child process initialized" | ||
45 | } | ||
46 | after 100 | ||
47 | |||
48 | puts "\nall done\n" | ||
49 | |||
diff --git a/test/utils/audit.exp b/test/utils/audit.exp new file mode 100755 index 000000000..931b46981 --- /dev/null +++ b/test/utils/audit.exp | |||
@@ -0,0 +1,79 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2016 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | set timeout 10 | ||
7 | spawn $env(SHELL) | ||
8 | match_max 100000 | ||
9 | |||
10 | send -- "firejail --audit\r" | ||
11 | expect { | ||
12 | timeout {puts "TESTING ERROR 0\n";exit} | ||
13 | "Firejail Audit" | ||
14 | } | ||
15 | expect { | ||
16 | timeout {puts "TESTING ERROR 1\n";exit} | ||
17 | "is running in a PID namespace" | ||
18 | } | ||
19 | expect { | ||
20 | timeout {puts "TESTING ERROR 2\n";exit} | ||
21 | "container/sandbox firejail" | ||
22 | } | ||
23 | expect { | ||
24 | timeout {puts "TESTING ERROR 3\n";exit} | ||
25 | "seccomp BPF enabled" | ||
26 | } | ||
27 | expect { | ||
28 | timeout {puts "TESTING ERROR 4\n";exit} | ||
29 | "all capabilities are disabled" | ||
30 | } | ||
31 | expect { | ||
32 | timeout {puts "TESTING ERROR 5\n";exit} | ||
33 | "dev directory seems to be fully populated" | ||
34 | } | ||
35 | after 100 | ||
36 | |||
37 | |||
38 | send -- "firejail --audit=/usr/lib/firejail/faudit\r" | ||
39 | expect { | ||
40 | timeout {puts "TESTING ERROR 6\n";exit} | ||
41 | "Firejail Audit" | ||
42 | } | ||
43 | expect { | ||
44 | timeout {puts "TESTING ERROR 7\n";exit} | ||
45 | "is running in a PID namespace" | ||
46 | } | ||
47 | expect { | ||
48 | timeout {puts "TESTING ERROR 8\n";exit} | ||
49 | "container/sandbox firejail" | ||
50 | } | ||
51 | expect { | ||
52 | timeout {puts "TESTING ERROR 9\n";exit} | ||
53 | "seccomp BPF enabled" | ||
54 | } | ||
55 | expect { | ||
56 | timeout {puts "TESTING ERROR 10\n";exit} | ||
57 | "all capabilities are disabled" | ||
58 | } | ||
59 | expect { | ||
60 | timeout {puts "TESTING ERROR 11\n";exit} | ||
61 | "dev directory seems to be fully populated" | ||
62 | } | ||
63 | after 100 | ||
64 | |||
65 | send -- "firejail --audit=blablabla\r" | ||
66 | expect { | ||
67 | timeout {puts "TESTING ERROR 12\n";exit} | ||
68 | "cannot find the audit program" | ||
69 | } | ||
70 | after 100 | ||
71 | |||
72 | send -- "firejail --audit=\r" | ||
73 | expect { | ||
74 | timeout {puts "TESTING ERROR 12\n";exit} | ||
75 | "invalid audit program" | ||
76 | } | ||
77 | after 100 | ||
78 | |||
79 | puts "\nall done\n" | ||
diff --git a/test/utils/utils.sh b/test/utils/utils.sh index 804e5ae0f..04702597f 100755 --- a/test/utils/utils.sh +++ b/test/utils/utils.sh | |||
@@ -6,6 +6,9 @@ | |||
6 | export MALLOC_CHECK_=3 | 6 | export MALLOC_CHECK_=3 |
7 | export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) | 7 | export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) |
8 | 8 | ||
9 | echo "TESTING: audit (test/utils/audit.exp)" | ||
10 | ./audit.exp | ||
11 | |||
9 | echo "TESTING: version (test/utils/version.exp)" | 12 | echo "TESTING: version (test/utils/version.exp)" |
10 | ./version.exp | 13 | ./version.exp |
11 | 14 | ||