diff options
Diffstat (limited to 'src')
38 files changed, 316 insertions, 220 deletions
diff --git a/src/fbuilder/build_fs.c b/src/fbuilder/build_fs.c index 1b8231033..0bc4a0ee2 100644 --- a/src/fbuilder/build_fs.c +++ b/src/fbuilder/build_fs.c | |||
@@ -217,6 +217,10 @@ void build_share(const char *fname, FILE *fp) { | |||
217 | //******************************************* | 217 | //******************************************* |
218 | static FileDB *tmp_out = NULL; | 218 | static FileDB *tmp_out = NULL; |
219 | static void tmp_callback(char *ptr) { | 219 | static void tmp_callback(char *ptr) { |
220 | // skip strace file | ||
221 | if (strncmp(ptr, "/tmp/firejail-strace", 20) == 0) | ||
222 | return; | ||
223 | |||
220 | tmp_out = filedb_add(tmp_out, ptr); | 224 | tmp_out = filedb_add(tmp_out, ptr); |
221 | } | 225 | } |
222 | 226 | ||
diff --git a/src/fbuilder/build_home.c b/src/fbuilder/build_home.c index fca3396c4..c0f4a3407 100644 --- a/src/fbuilder/build_home.c +++ b/src/fbuilder/build_home.c | |||
@@ -24,7 +24,7 @@ static FileDB *db_skip = NULL; | |||
24 | static FileDB *db_out = NULL; | 24 | static FileDB *db_out = NULL; |
25 | 25 | ||
26 | static void load_whitelist_common(void) { | 26 | static void load_whitelist_common(void) { |
27 | FILE *fp = fopen("/etc/firejail/whitelist-common.inc", "r"); | 27 | FILE *fp = fopen(SYSCONFDIR "/whitelist-common.inc", "r"); |
28 | if (!fp) { | 28 | if (!fp) { |
29 | fprintf(stderr, "Error: cannot open whitelist-common.inc\n"); | 29 | fprintf(stderr, "Error: cannot open whitelist-common.inc\n"); |
30 | exit(1); | 30 | exit(1); |
diff --git a/src/fbuilder/build_profile.c b/src/fbuilder/build_profile.c index adc00e67b..09f41a838 100644 --- a/src/fbuilder/build_profile.c +++ b/src/fbuilder/build_profile.c | |||
@@ -80,10 +80,19 @@ void build_profile(int argc, char **argv, int index, FILE *fp) { | |||
80 | stroutput, | 80 | stroutput, |
81 | }; | 81 | }; |
82 | 82 | ||
83 | // detect strace | 83 | // detect strace and check if Yama LSM allows us to use it |
84 | int have_strace = 0; | 84 | int have_strace = 0; |
85 | if (access("/usr/bin/strace", X_OK) == 0) | 85 | int have_yama_permission = 1; |
86 | if (access("/usr/bin/strace", X_OK) == 0) { | ||
86 | have_strace = 1; | 87 | have_strace = 1; |
88 | FILE *ps = fopen("/proc/sys/kernel/yama/ptrace_scope", "r"); | ||
89 | if (ps) { | ||
90 | unsigned val; | ||
91 | if (fscanf(ps, "%u", &val) == 1) | ||
92 | have_yama_permission = (val < 2); | ||
93 | fclose(ps); | ||
94 | } | ||
95 | } | ||
87 | 96 | ||
88 | // calculate command length | 97 | // calculate command length |
89 | unsigned len = (int) sizeof(cmdlist) / sizeof(char*) + argc - index + 1; | 98 | unsigned len = (int) sizeof(cmdlist) / sizeof(char*) + argc - index + 1; |
@@ -93,10 +102,11 @@ void build_profile(int argc, char **argv, int index, FILE *fp) { | |||
93 | cmd[0] = cmdlist[0]; // explicit assignment to clean scan-build error | 102 | cmd[0] = cmdlist[0]; // explicit assignment to clean scan-build error |
94 | 103 | ||
95 | // build command | 104 | // build command |
105 | // skip strace if not installed, or no permission to use it | ||
106 | int skip_strace = !(have_strace && have_yama_permission); | ||
96 | unsigned i = 0; | 107 | unsigned i = 0; |
97 | for (i = 0; i < (int) sizeof(cmdlist) / sizeof(char*); i++) { | 108 | for (i = 0; i < (int) sizeof(cmdlist) / sizeof(char*); i++) { |
98 | // skip strace if not installed | 109 | if (skip_strace && strcmp(cmdlist[i], "/usr/bin/strace") == 0) |
99 | if (have_strace == 0 && strcmp(cmdlist[i], "/usr/bin/strace") == 0) | ||
100 | break; | 110 | break; |
101 | cmd[i] = cmdlist[i]; | 111 | cmd[i] = cmdlist[i]; |
102 | } | 112 | } |
@@ -172,12 +182,14 @@ void build_profile(int argc, char **argv, int index, FILE *fp) { | |||
172 | fprintf(fp, "caps.drop all\n"); | 182 | fprintf(fp, "caps.drop all\n"); |
173 | fprintf(fp, "nonewprivs\n"); | 183 | fprintf(fp, "nonewprivs\n"); |
174 | fprintf(fp, "seccomp\n"); | 184 | fprintf(fp, "seccomp\n"); |
175 | if (have_strace) | 185 | if (!have_strace) { |
176 | build_seccomp(strace_output, fp); | ||
177 | else { | ||
178 | fprintf(fp, "# If you install strace on your system, Firejail will also create a\n"); | 186 | fprintf(fp, "# If you install strace on your system, Firejail will also create a\n"); |
179 | fprintf(fp, "# whitelisted seccomp filter.\n"); | 187 | fprintf(fp, "# whitelisted seccomp filter.\n"); |
180 | } | 188 | } |
189 | else if (!have_yama_permission) | ||
190 | fprintf(fp, "# Yama security module prevents creation of a whitelisted seccomp filter\n"); | ||
191 | else | ||
192 | build_seccomp(strace_output, fp); | ||
181 | fprintf(fp, "\n"); | 193 | fprintf(fp, "\n"); |
182 | 194 | ||
183 | fprintf(fp, "### network\n"); | 195 | fprintf(fp, "### network\n"); |
diff --git a/src/fcopy/Makefile.in b/src/fcopy/Makefile.in index 64e277e2d..85f84aa32 100644 --- a/src/fcopy/Makefile.in +++ b/src/fcopy/Makefile.in | |||
@@ -5,8 +5,8 @@ include ../common.mk | |||
5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h | 5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h |
6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | 6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ |
7 | 7 | ||
8 | fcopy: $(OBJS) | 8 | fcopy: $(OBJS) ../lib/common.o |
9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) | 9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS) |
10 | 10 | ||
11 | clean:; rm -fr *.o fcopy *.gcov *.gcda *.gcno *.plist | 11 | clean:; rm -fr *.o fcopy *.gcov *.gcda *.gcno *.plist |
12 | 12 | ||
diff --git a/src/fcopy/main.c b/src/fcopy/main.c index 67237b4ea..e65501d6d 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <ftw.h> | 23 | #include <ftw.h> |
24 | #include <errno.h> | 24 | #include <errno.h> |
25 | #include <pwd.h> | 25 | #include <pwd.h> |
26 | #include <sys/prctl.h> | ||
27 | 26 | ||
28 | #if HAVE_SELINUX | 27 | #if HAVE_SELINUX |
29 | #include <sys/stat.h> | 28 | #include <sys/stat.h> |
@@ -112,7 +111,7 @@ static void copy_file(const char *srcname, const char *destname, mode_t mode, ui | |||
112 | } | 111 | } |
113 | 112 | ||
114 | // open destination | 113 | // open destination |
115 | int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, 0755); | 114 | int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR); |
116 | if (dst < 0) { | 115 | if (dst < 0) { |
117 | if (!arg_quiet) | 116 | if (!arg_quiet) |
118 | fprintf(stderr, "Warning fcopy: cannot open %s, file not copied\n", destname); | 117 | fprintf(stderr, "Warning fcopy: cannot open %s, file not copied\n", destname); |
@@ -133,7 +132,8 @@ static void copy_file(const char *srcname, const char *destname, mode_t mode, ui | |||
133 | done += rv; | 132 | done += rv; |
134 | } | 133 | } |
135 | } | 134 | } |
136 | fflush(0); | 135 | if (len < 0) |
136 | goto errexit; | ||
137 | 137 | ||
138 | if (fchown(dst, uid, gid) == -1) | 138 | if (fchown(dst, uid, gid) == -1) |
139 | goto errexit; | 139 | goto errexit; |
@@ -180,7 +180,7 @@ void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, | |||
180 | 180 | ||
181 | // if the link is already there, don't create it | 181 | // if the link is already there, don't create it |
182 | struct stat s; | 182 | struct stat s; |
183 | if (stat(linkpath, &s) == 0) | 183 | if (lstat(linkpath, &s) == 0) |
184 | return; | 184 | return; |
185 | 185 | ||
186 | char *rp = realpath(target, NULL); | 186 | char *rp = realpath(target, NULL); |
@@ -412,30 +412,21 @@ int main(int argc, char **argv) { | |||
412 | exit(1); | 412 | exit(1); |
413 | } | 413 | } |
414 | 414 | ||
415 | #ifdef WARN_DUMPABLE | 415 | warn_dumpable(); |
416 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid()) | ||
417 | fprintf(stderr, "Error fcopy: I am dumpable\n"); | ||
418 | #endif | ||
419 | |||
420 | // trim trailing chars | ||
421 | if (src[strlen(src) - 1] == '/') | ||
422 | src[strlen(src) - 1] = '\0'; | ||
423 | if (dest[strlen(dest) - 1] == '/') | ||
424 | dest[strlen(dest) - 1] = '\0'; | ||
425 | 416 | ||
426 | // check the two files; remove ending / | 417 | // check the two files; remove ending / |
427 | int len = strlen(src); | 418 | size_t len = strlen(src); |
428 | if (src[len - 1] == '/') | 419 | while (len > 1 && src[len - 1] == '/') |
429 | src[len - 1] = '\0'; | 420 | src[--len] = '\0'; |
430 | if (strcspn(src, "\\*&!?\"'<>%^(){}[];,") != (size_t)len) { | 421 | if (strcspn(src, "\\*&!?\"'<>%^(){}[];,") != len) { |
431 | fprintf(stderr, "Error fcopy: invalid source file name %s\n", src); | 422 | fprintf(stderr, "Error fcopy: invalid source file name %s\n", src); |
432 | exit(1); | 423 | exit(1); |
433 | } | 424 | } |
434 | 425 | ||
435 | len = strlen(dest); | 426 | len = strlen(dest); |
436 | if (dest[len - 1] == '/') | 427 | while (len > 1 && dest[len - 1] == '/') |
437 | dest[len - 1] = '\0'; | 428 | dest[--len] = '\0'; |
438 | if (strcspn(dest, "\\*&!?\"'<>%^(){}[];,~") != (size_t)len) { | 429 | if (strcspn(dest, "\\*&!?\"'<>%^(){}[];,~") != len) { |
439 | fprintf(stderr, "Error fcopy: invalid dest file name %s\n", dest); | 430 | fprintf(stderr, "Error fcopy: invalid dest file name %s\n", dest); |
440 | exit(1); | 431 | exit(1); |
441 | } | 432 | } |
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config index 4853e099b..e924ef2ec 100644 --- a/src/firecfg/firecfg.config +++ b/src/firecfg/firecfg.config | |||
@@ -391,6 +391,7 @@ kazam | |||
391 | kcalc | 391 | kcalc |
392 | # kdeinit4 | 392 | # kdeinit4 |
393 | kdenlive | 393 | kdenlive |
394 | kdiff3 | ||
394 | keepass | 395 | keepass |
395 | keepass2 | 396 | keepass2 |
396 | keepassx | 397 | keepassx |
@@ -424,6 +425,7 @@ kwrite | |||
424 | leafpad | 425 | leafpad |
425 | # less - breaks man | 426 | # less - breaks man |
426 | libreoffice | 427 | libreoffice |
428 | librewolf | ||
427 | liferea | 429 | liferea |
428 | lightsoff | 430 | lightsoff |
429 | lincity-ng | 431 | lincity-ng |
@@ -455,6 +457,7 @@ macrofusion | |||
455 | magicor | 457 | magicor |
456 | # man | 458 | # man |
457 | manaplus | 459 | manaplus |
460 | marker | ||
458 | masterpdfeditor | 461 | masterpdfeditor |
459 | masterpdfeditor4 | 462 | masterpdfeditor4 |
460 | masterpdfeditor5 | 463 | masterpdfeditor5 |
@@ -463,6 +466,7 @@ mate-calculator | |||
463 | mate-color-select | 466 | mate-color-select |
464 | mate-dictionary | 467 | mate-dictionary |
465 | mathematica | 468 | mathematica |
469 | matrix-mirage | ||
466 | mattermost-desktop | 470 | mattermost-desktop |
467 | mcabber | 471 | mcabber |
468 | mediainfo | 472 | mediainfo |
@@ -474,6 +478,8 @@ mencoder | |||
474 | mendeleydesktop | 478 | mendeleydesktop |
475 | menulibre | 479 | menulibre |
476 | meteo-qt | 480 | meteo-qt |
481 | microsoft-edge | ||
482 | microsoft-edge-dev | ||
477 | midori | 483 | midori |
478 | min | 484 | min |
479 | mindless | 485 | mindless |
@@ -618,6 +624,7 @@ qemu-launcher | |||
618 | qgis | 624 | qgis |
619 | qlipper | 625 | qlipper |
620 | qmmp | 626 | qmmp |
627 | qnapi | ||
621 | qpdfview | 628 | qpdfview |
622 | qt-faststart | 629 | qt-faststart |
623 | qtox | 630 | qtox |
@@ -659,6 +666,7 @@ secret-tool | |||
659 | shellcheck | 666 | shellcheck |
660 | shortwave | 667 | shortwave |
661 | shotcut | 668 | shotcut |
669 | shotwell | ||
662 | signal-cli | 670 | signal-cli |
663 | signal-desktop | 671 | signal-desktop |
664 | silentarmy | 672 | silentarmy |
@@ -768,6 +776,7 @@ tremulous | |||
768 | trojita | 776 | trojita |
769 | truecraft | 777 | truecraft |
770 | tshark | 778 | tshark |
779 | tutanota-desktop | ||
771 | tuxguitar | 780 | tuxguitar |
772 | tvbrowser | 781 | tvbrowser |
773 | twitch | 782 | twitch |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 6c0ebcd43..9ea3edcd0 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -372,7 +372,7 @@ char *guess_shell(void); | |||
372 | // sandbox.c | 372 | // sandbox.c |
373 | #define SANDBOX_DONE '1' | 373 | #define SANDBOX_DONE '1' |
374 | int sandbox(void* sandbox_arg); | 374 | int sandbox(void* sandbox_arg); |
375 | void start_application(int no_sandbox, char *set_sandbox_status) __attribute__((noreturn)); | 375 | void start_application(int no_sandbox, int fd, char *set_sandbox_status) __attribute__((noreturn)); |
376 | void set_apparmor(void); | 376 | void set_apparmor(void); |
377 | 377 | ||
378 | // network_main.c | 378 | // network_main.c |
@@ -513,7 +513,6 @@ void check_private_dir(void); | |||
513 | void update_map(char *mapping, char *map_file); | 513 | void update_map(char *mapping, char *map_file); |
514 | void wait_for_other(int fd); | 514 | void wait_for_other(int fd); |
515 | void notify_other(int fd); | 515 | void notify_other(int fd); |
516 | const char *gnu_basename(const char *path); | ||
517 | uid_t pid_get_uid(pid_t pid); | 516 | uid_t pid_get_uid(pid_t pid); |
518 | uid_t get_group_id(const char *group); | 517 | uid_t get_group_id(const char *group); |
519 | int remove_overlay_directory(void); | 518 | int remove_overlay_directory(void); |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 0d4e496e8..4e6c1adc3 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -795,6 +795,8 @@ void disable_config(void) { | |||
795 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_PROFILE_DIR); | 795 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_PROFILE_DIR); |
796 | if (stat(RUN_FIREJAIL_X11_DIR, &s) == 0) | 796 | if (stat(RUN_FIREJAIL_X11_DIR, &s) == 0) |
797 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_X11_DIR); | 797 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_X11_DIR); |
798 | if (!arg_appimage && stat(RUN_FIREJAIL_APPIMAGE_DIR, &s) == 0) | ||
799 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_APPIMAGE_DIR); | ||
798 | } | 800 | } |
799 | 801 | ||
800 | 802 | ||
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c index 5cfd33b42..b8c1b21b1 100644 --- a/src/firejail/fs_lib.c +++ b/src/firejail/fs_lib.c | |||
@@ -33,6 +33,52 @@ extern void fslib_install_system(void); | |||
33 | static int lib_cnt = 0; | 33 | static int lib_cnt = 0; |
34 | static int dir_cnt = 0; | 34 | static int dir_cnt = 0; |
35 | 35 | ||
36 | char *find_in_path(const char *program) { | ||
37 | EUID_ASSERT(); | ||
38 | if (arg_debug) | ||
39 | printf("Searching $PATH for %s\n", program); | ||
40 | |||
41 | char self[MAXBUF]; | ||
42 | ssize_t len = readlink("/proc/self/exe", self, MAXBUF - 1); | ||
43 | if (len < 0) | ||
44 | errExit("readlink"); | ||
45 | self[len] = '\0'; | ||
46 | |||
47 | char *path = getenv("PATH"); | ||
48 | if (!path) | ||
49 | return NULL; | ||
50 | char *dup = strdup(path); | ||
51 | if (!dup) | ||
52 | errExit("strdup"); | ||
53 | char *tok = strtok(dup, ":"); | ||
54 | while (tok) { | ||
55 | char *fname; | ||
56 | if (asprintf(&fname, "%s/%s", tok, program) == -1) | ||
57 | errExit("asprintf"); | ||
58 | |||
59 | if (arg_debug) | ||
60 | printf("trying #%s#\n", fname); | ||
61 | struct stat s; | ||
62 | if (stat(fname, &s) == 0) { | ||
63 | // but skip links created by firecfg | ||
64 | char *rp = realpath(fname, NULL); | ||
65 | if (!rp) | ||
66 | errExit("realpath"); | ||
67 | if (strcmp(self, rp) != 0) { | ||
68 | free(rp); | ||
69 | free(dup); | ||
70 | return fname; | ||
71 | } | ||
72 | free(rp); | ||
73 | } | ||
74 | free(fname); | ||
75 | tok = strtok(NULL, ":"); | ||
76 | } | ||
77 | |||
78 | free(dup); | ||
79 | return NULL; | ||
80 | } | ||
81 | |||
36 | static void report_duplication(const char *full_path) { | 82 | static void report_duplication(const char *full_path) { |
37 | char *fname = strrchr(full_path, '/'); | 83 | char *fname = strrchr(full_path, '/'); |
38 | if (fname && *(++fname) != '\0') { | 84 | if (fname && *(++fname) != '\0') { |
@@ -165,7 +211,7 @@ void fslib_copy_dir(const char *full_path) { | |||
165 | mkdir_attr(dest, 0755, 0, 0); | 211 | mkdir_attr(dest, 0755, 0, 0); |
166 | 212 | ||
167 | if (mount(full_path, dest, NULL, MS_BIND|MS_REC, NULL) < 0 || | 213 | if (mount(full_path, dest, NULL, MS_BIND|MS_REC, NULL) < 0 || |
168 | mount(NULL, dest, NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) | 214 | mount(NULL, dest, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) |
169 | errExit("mount bind"); | 215 | errExit("mount bind"); |
170 | fs_logger2("clone", full_path); | 216 | fs_logger2("clone", full_path); |
171 | fs_logger2("mount", full_path); | 217 | fs_logger2("mount", full_path); |
@@ -336,11 +382,40 @@ void fs_private_lib(void) { | |||
336 | // start timetrace | 382 | // start timetrace |
337 | timetrace_start(); | 383 | timetrace_start(); |
338 | 384 | ||
385 | // bring in firejail executable libraries in case we are redirected here by a firejail symlink from /usr/local/bin/firejail | ||
386 | if (arg_debug || arg_debug_private_lib) | ||
387 | printf("Installing Firejail libraries\n"); | ||
388 | fslib_install_list(PATH_FIREJAIL); | ||
389 | |||
390 | // bring in firejail directory | ||
391 | fslib_install_list(LIBDIR "/firejail"); | ||
392 | |||
393 | // bring in dhclient libraries | ||
394 | if (any_dhcp()) { | ||
395 | if (arg_debug || arg_debug_private_lib) | ||
396 | printf("Installing dhclient libraries\n"); | ||
397 | fslib_install_list(RUN_MNT_DIR "/dhclient"); | ||
398 | } | ||
399 | fmessage("Firejail libraries installed in %0.2f ms\n", timetrace_end()); | ||
400 | |||
401 | timetrace_start(); | ||
402 | |||
339 | // copy the libs in the new lib directory for the main exe | 403 | // copy the libs in the new lib directory for the main exe |
340 | if (cfg.original_program_index > 0) { | 404 | if (cfg.original_program_index > 0) { |
341 | if (arg_debug || arg_debug_private_lib) | 405 | if (arg_debug || arg_debug_private_lib) |
342 | printf("Installing sandboxed program libraries\n"); | 406 | printf("Installing sandboxed program libraries\n"); |
343 | fslib_install_list(cfg.original_argv[cfg.original_program_index]); | 407 | |
408 | if (strchr(cfg.original_argv[cfg.original_program_index], '/')) | ||
409 | fslib_install_list(cfg.original_argv[cfg.original_program_index]); | ||
410 | else { // search executable in $PATH | ||
411 | EUID_USER(); | ||
412 | char *fname = find_in_path(cfg.original_argv[cfg.original_program_index]); | ||
413 | EUID_ROOT(); | ||
414 | if (fname) { | ||
415 | fslib_install_list(fname); | ||
416 | free(fname); | ||
417 | } | ||
418 | } | ||
344 | } | 419 | } |
345 | 420 | ||
346 | // for the shell | 421 | // for the shell |
@@ -369,18 +444,11 @@ void fs_private_lib(void) { | |||
369 | } | 444 | } |
370 | fmessage("Program libraries installed in %0.2f ms\n", timetrace_end()); | 445 | fmessage("Program libraries installed in %0.2f ms\n", timetrace_end()); |
371 | 446 | ||
372 | // install the reset of the system libraries | 447 | // install the rest of the system libraries |
373 | if (arg_debug || arg_debug_private_lib) | 448 | if (arg_debug || arg_debug_private_lib) |
374 | printf("Installing system libraries\n"); | 449 | printf("Installing system libraries\n"); |
375 | fslib_install_system(); | 450 | fslib_install_system(); |
376 | 451 | ||
377 | // bring in firejail directory for --trace and seccomp post exec | ||
378 | // bring in firejail executable libraries in case we are redirected here by a firejail symlink from /usr/local/bin/firejail | ||
379 | fslib_install_list("/usr/bin/firejail,firejail"); // todo: use the installed path for the executable | ||
380 | |||
381 | // install libraries needed by fcopy | ||
382 | fslib_install_list(PATH_FCOPY); | ||
383 | |||
384 | fmessage("Installed %d %s and %d %s\n", lib_cnt, (lib_cnt == 1)? "library": "libraries", | 452 | fmessage("Installed %d %s and %d %s\n", lib_cnt, (lib_cnt == 1)? "library": "libraries", |
385 | dir_cnt, (dir_cnt == 1)? "directory": "directories"); | 453 | dir_cnt, (dir_cnt == 1)? "directory": "directories"); |
386 | 454 | ||
diff --git a/src/firejail/fs_lib2.c b/src/firejail/fs_lib2.c index b2ae07f3e..95e10ee05 100644 --- a/src/firejail/fs_lib2.c +++ b/src/firejail/fs_lib2.c | |||
@@ -30,6 +30,7 @@ extern void fslib_copy_dir(const char *full_path); | |||
30 | //*************************************************************** | 30 | //*************************************************************** |
31 | // standard libc libraries based on Debian's libc6 package | 31 | // standard libc libraries based on Debian's libc6 package |
32 | // selinux seems to be linked in most command line utilities | 32 | // selinux seems to be linked in most command line utilities |
33 | // libpcre2 is a dependency of selinux | ||
33 | // locale (/usr/lib/locale) - without it, the program will default to "C" locale | 34 | // locale (/usr/lib/locale) - without it, the program will default to "C" locale |
34 | typedef struct liblist_t { | 35 | typedef struct liblist_t { |
35 | const char *name; | 36 | const char *name; |
@@ -38,6 +39,7 @@ typedef struct liblist_t { | |||
38 | 39 | ||
39 | static LibList libc_list[] = { | 40 | static LibList libc_list[] = { |
40 | { "libselinux.so.", 0 }, | 41 | { "libselinux.so.", 0 }, |
42 | { "libpcre2-8.so.", 0 }, | ||
41 | { "libapparmor.so.", 0}, | 43 | { "libapparmor.so.", 0}, |
42 | { "ld-linux-x86-64.so.", 0 }, | 44 | { "ld-linux-x86-64.so.", 0 }, |
43 | { "libanl.so.", 0 }, | 45 | { "libanl.so.", 0 }, |
@@ -104,17 +106,15 @@ static void stdc(const char *dirname) { | |||
104 | 106 | ||
105 | void fslib_install_stdc(void) { | 107 | void fslib_install_stdc(void) { |
106 | // install standard C libraries | 108 | // install standard C libraries |
109 | timetrace_start(); | ||
107 | struct stat s; | 110 | struct stat s; |
108 | char *stdclib = "/lib64"; // CentOS, Fedora, Arch | ||
109 | |||
110 | if (stat("/lib/x86_64-linux-gnu", &s) == 0) { // Debian & friends | 111 | if (stat("/lib/x86_64-linux-gnu", &s) == 0) { // Debian & friends |
111 | mkdir_attr(RUN_LIB_DIR "/x86_64-linux-gnu", 0755, 0, 0); | 112 | mkdir_attr(RUN_LIB_DIR "/x86_64-linux-gnu", 0755, 0, 0); |
112 | selinux_relabel_path(RUN_LIB_DIR "/x86_64-linux-gnu", "/lib/x86_64-linux-gnu"); | 113 | selinux_relabel_path(RUN_LIB_DIR "/x86_64-linux-gnu", "/lib/x86_64-linux-gnu"); |
113 | stdclib = "/lib/x86_64-linux-gnu"; | 114 | stdc("/lib/x86_64-linux-gnu"); |
114 | } | 115 | } |
115 | 116 | ||
116 | timetrace_start(); | 117 | stdc("/lib64"); // CentOS, Fedora, Arch, ld-linux.so in Debian & friends |
117 | stdc(stdclib); | ||
118 | 118 | ||
119 | // install locale | 119 | // install locale |
120 | if (stat("/usr/lib/locale", &s) == 0) | 120 | if (stat("/usr/lib/locale", &s) == 0) |
diff --git a/src/firejail/join.c b/src/firejail/join.c index ca8b8c4bf..4f0210f95 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c | |||
@@ -20,10 +20,14 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/stat.h> | 21 | #include <sys/stat.h> |
22 | #include <sys/wait.h> | 22 | #include <sys/wait.h> |
23 | #include <fcntl.h> | ||
24 | #include <unistd.h> | 23 | #include <unistd.h> |
25 | #include <errno.h> | 24 | #include <errno.h> |
26 | 25 | ||
26 | #include <fcntl.h> | ||
27 | #ifndef O_PATH | ||
28 | #define O_PATH 010000000 | ||
29 | #endif | ||
30 | |||
27 | #include <sys/prctl.h> | 31 | #include <sys/prctl.h> |
28 | #ifndef PR_SET_NO_NEW_PRIVS | 32 | #ifndef PR_SET_NO_NEW_PRIVS |
29 | #define PR_SET_NO_NEW_PRIVS 38 | 33 | #define PR_SET_NO_NEW_PRIVS 38 |
@@ -292,13 +296,28 @@ static void extract_umask(pid_t pid) { | |||
292 | fprintf(stderr, "Error: cannot open umask file\n"); | 296 | fprintf(stderr, "Error: cannot open umask file\n"); |
293 | exit(1); | 297 | exit(1); |
294 | } | 298 | } |
295 | if (fscanf(fp, "%o", &orig_umask) != 1) { | 299 | if (fscanf(fp, "%3o", &orig_umask) != 1) { |
296 | fprintf(stderr, "Error: cannot read umask\n"); | 300 | fprintf(stderr, "Error: cannot read umask\n"); |
297 | exit(1); | 301 | exit(1); |
298 | } | 302 | } |
299 | fclose(fp); | 303 | fclose(fp); |
300 | } | 304 | } |
301 | 305 | ||
306 | static int open_shell(void) { | ||
307 | EUID_ASSERT(); | ||
308 | assert(cfg.shell); | ||
309 | |||
310 | if (arg_debug) | ||
311 | printf("Opening shell %s\n", cfg.shell); | ||
312 | // file descriptor will leak if not opened with O_CLOEXEC !! | ||
313 | int fd = open(cfg.shell, O_PATH|O_CLOEXEC); | ||
314 | if (fd == -1) { | ||
315 | fprintf(stderr, "Error: cannot open shell %s\n", cfg.shell); | ||
316 | exit(1); | ||
317 | } | ||
318 | return fd; | ||
319 | } | ||
320 | |||
302 | // return false if the sandbox identified by pid is not fully set up yet or if | 321 | // return false if the sandbox identified by pid is not fully set up yet or if |
303 | // it is no firejail sandbox at all, return true if the sandbox is complete | 322 | // it is no firejail sandbox at all, return true if the sandbox is complete |
304 | bool is_ready_for_join(const pid_t pid) { | 323 | bool is_ready_for_join(const pid_t pid) { |
@@ -316,7 +335,7 @@ bool is_ready_for_join(const pid_t pid) { | |||
316 | struct stat s; | 335 | struct stat s; |
317 | if (fstat(fd, &s) == -1) | 336 | if (fstat(fd, &s) == -1) |
318 | errExit("fstat"); | 337 | errExit("fstat"); |
319 | if (!S_ISREG(s.st_mode) || s.st_uid != 0) { | 338 | if (!S_ISREG(s.st_mode) || s.st_uid != 0 || s.st_size != 1) { |
320 | close(fd); | 339 | close(fd); |
321 | return false; | 340 | return false; |
322 | } | 341 | } |
@@ -391,6 +410,10 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
391 | 410 | ||
392 | extract_x11_display(parent); | 411 | extract_x11_display(parent); |
393 | 412 | ||
413 | int shfd = -1; | ||
414 | if (!arg_shell_none && !arg_audit) | ||
415 | shfd = open_shell(); | ||
416 | |||
394 | EUID_ROOT(); | 417 | EUID_ROOT(); |
395 | // in user mode set caps seccomp, cpu, cgroup, etc | 418 | // in user mode set caps seccomp, cpu, cgroup, etc |
396 | if (getuid() != 0) { | 419 | if (getuid() != 0) { |
@@ -400,6 +423,7 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
400 | extract_cgroup(pid); | 423 | extract_cgroup(pid); |
401 | extract_nogroups(pid); | 424 | extract_nogroups(pid); |
402 | extract_user_namespace(pid); | 425 | extract_user_namespace(pid); |
426 | extract_umask(pid); | ||
403 | #ifdef HAVE_APPARMOR | 427 | #ifdef HAVE_APPARMOR |
404 | extract_apparmor(pid); | 428 | extract_apparmor(pid); |
405 | #endif | 429 | #endif |
@@ -409,9 +433,6 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
409 | if (cfg.cgroup) // not available for uid 0 | 433 | if (cfg.cgroup) // not available for uid 0 |
410 | set_cgroup(cfg.cgroup); | 434 | set_cgroup(cfg.cgroup); |
411 | 435 | ||
412 | // set umask, also uid 0 | ||
413 | extract_umask(pid); | ||
414 | |||
415 | // join namespaces | 436 | // join namespaces |
416 | if (arg_join_network) { | 437 | if (arg_join_network) { |
417 | if (join_namespace(pid, "net")) | 438 | if (join_namespace(pid, "net")) |
@@ -522,10 +543,9 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
522 | extract_command(argc, argv, index); | 543 | extract_command(argc, argv, index); |
523 | if (cfg.command_line == NULL) { | 544 | if (cfg.command_line == NULL) { |
524 | assert(cfg.shell); | 545 | assert(cfg.shell); |
525 | cfg.command_line = cfg.shell; | ||
526 | cfg.window_title = cfg.shell; | 546 | cfg.window_title = cfg.shell; |
527 | } | 547 | } |
528 | if (arg_debug) | 548 | else if (arg_debug) |
529 | printf("Extracted command #%s#\n", cfg.command_line); | 549 | printf("Extracted command #%s#\n", cfg.command_line); |
530 | 550 | ||
531 | // set cpu affinity | 551 | // set cpu affinity |
@@ -554,11 +574,13 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
554 | dbus_set_system_bus_env(); | 574 | dbus_set_system_bus_env(); |
555 | #endif | 575 | #endif |
556 | 576 | ||
557 | start_application(0, NULL); | 577 | start_application(0, shfd, NULL); |
558 | 578 | ||
559 | __builtin_unreachable(); | 579 | __builtin_unreachable(); |
560 | } | 580 | } |
561 | EUID_USER(); | 581 | EUID_USER(); |
582 | if (shfd != -1) | ||
583 | close(shfd); | ||
562 | 584 | ||
563 | int status = 0; | 585 | int status = 0; |
564 | //***************************** | 586 | //***************************** |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 544bfe83a..0f0086a6e 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -1231,11 +1231,6 @@ int main(int argc, char **argv, char **envp) { | |||
1231 | } | 1231 | } |
1232 | EUID_ASSERT(); | 1232 | EUID_ASSERT(); |
1233 | 1233 | ||
1234 | #ifdef WARN_DUMPABLE | ||
1235 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid()) | ||
1236 | fprintf(stderr, "Error: Firejail is dumpable\n"); | ||
1237 | #endif | ||
1238 | |||
1239 | // check for force-nonewprivs in /etc/firejail/firejail.config file | 1234 | // check for force-nonewprivs in /etc/firejail/firejail.config file |
1240 | if (checkcfg(CFG_FORCE_NONEWPRIVS)) | 1235 | if (checkcfg(CFG_FORCE_NONEWPRIVS)) |
1241 | arg_nonewprivs = 1; | 1236 | arg_nonewprivs = 1; |
@@ -2787,7 +2782,7 @@ int main(int argc, char **argv, char **envp) { | |||
2787 | 2782 | ||
2788 | // build the sandbox command | 2783 | // build the sandbox command |
2789 | if (prog_index == -1 && cfg.shell) { | 2784 | if (prog_index == -1 && cfg.shell) { |
2790 | cfg.command_line = cfg.shell; | 2785 | assert(cfg.command_line == NULL); // runs cfg.shell |
2791 | cfg.window_title = cfg.shell; | 2786 | cfg.window_title = cfg.shell; |
2792 | cfg.command_name = cfg.shell; | 2787 | cfg.command_name = cfg.shell; |
2793 | } | 2788 | } |
diff --git a/src/firejail/no_sandbox.c b/src/firejail/no_sandbox.c index 01df77ee6..6c7803602 100644 --- a/src/firejail/no_sandbox.c +++ b/src/firejail/no_sandbox.c | |||
@@ -204,14 +204,15 @@ void run_no_sandbox(int argc, char **argv) { | |||
204 | break; | 204 | break; |
205 | } | 205 | } |
206 | } | 206 | } |
207 | // if shell is /usr/bin/firejail, replace it with /bin/bash | 207 | |
208 | if (strcmp(cfg.shell, PATH_FIREJAIL) == 0) { | 208 | // if shell is /usr/bin/firejail, replace it with /bin/bash |
209 | cfg.shell = "/bin/bash"; | 209 | // if (strcmp(cfg.shell, PATH_FIREJAIL) == 0) { |
210 | prog_index = 0; | 210 | // cfg.shell = "/bin/bash"; |
211 | } | 211 | // prog_index = 0; |
212 | // } | ||
212 | 213 | ||
213 | if (prog_index == 0) { | 214 | if (prog_index == 0) { |
214 | cfg.command_line = cfg.shell; | 215 | assert(cfg.command_line == NULL); // runs cfg.shell |
215 | cfg.window_title = cfg.shell; | 216 | cfg.window_title = cfg.shell; |
216 | } else { | 217 | } else { |
217 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); | 218 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); |
@@ -230,5 +231,5 @@ void run_no_sandbox(int argc, char **argv) { | |||
230 | 231 | ||
231 | arg_quiet = 1; | 232 | arg_quiet = 1; |
232 | 233 | ||
233 | start_application(1, NULL); | 234 | start_application(1, -1, NULL); |
234 | } | 235 | } |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 4172c96f7..1ee8cdfcb 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -619,6 +619,17 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
619 | #endif | 619 | #endif |
620 | return 0; | 620 | return 0; |
621 | } | 621 | } |
622 | else if (strncmp(ptr, "netns ", 6) == 0) { | ||
623 | #ifdef HAVE_NETWORK | ||
624 | if (checkcfg(CFG_NETWORK)) { | ||
625 | arg_netns = ptr + 6; | ||
626 | check_netns(arg_netns); | ||
627 | } | ||
628 | else | ||
629 | warning_feature_disabled("networking"); | ||
630 | #endif | ||
631 | return 0; | ||
632 | } | ||
622 | else if (strcmp(ptr, "net none") == 0) { | 633 | else if (strcmp(ptr, "net none") == 0) { |
623 | arg_nonetwork = 1; | 634 | arg_nonetwork = 1; |
624 | cfg.bridge0.configured = 0; | 635 | cfg.bridge0.configured = 0; |
diff --git a/src/firejail/run_symlink.c b/src/firejail/run_symlink.c index ea3889024..b38cc0ca6 100644 --- a/src/firejail/run_symlink.c +++ b/src/firejail/run_symlink.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <unistd.h> | 23 | #include <unistd.h> |
24 | 24 | ||
25 | extern char *find_in_path(const char *program); | ||
26 | |||
25 | void run_symlink(int argc, char **argv, int run_as_is) { | 27 | void run_symlink(int argc, char **argv, int run_as_is) { |
26 | EUID_ASSERT(); | 28 | EUID_ASSERT(); |
27 | 29 | ||
@@ -40,54 +42,17 @@ void run_symlink(int argc, char **argv, int run_as_is) { | |||
40 | errExit("setresuid"); | 42 | errExit("setresuid"); |
41 | 43 | ||
42 | // find the real program by looking in PATH | 44 | // find the real program by looking in PATH |
43 | char *p = getenv("PATH"); | 45 | if (!getenv("PATH")) { |
44 | if (!p) { | ||
45 | fprintf(stderr, "Error: PATH environment variable not set\n"); | 46 | fprintf(stderr, "Error: PATH environment variable not set\n"); |
46 | exit(1); | 47 | exit(1); |
47 | } | 48 | } |
48 | 49 | ||
49 | char *path = strdup(p); | 50 | char *p = find_in_path(program); |
50 | if (!path) | 51 | if (!p) { |
51 | errExit("strdup"); | ||
52 | |||
53 | char *selfpath = realpath("/proc/self/exe", NULL); | ||
54 | if (!selfpath) | ||
55 | errExit("realpath"); | ||
56 | |||
57 | // look in path for our program | ||
58 | char *tok = strtok(path, ":"); | ||
59 | int found = 0; | ||
60 | while (tok) { | ||
61 | char *name; | ||
62 | if (asprintf(&name, "%s/%s", tok, program) == -1) | ||
63 | errExit("asprintf"); | ||
64 | |||
65 | struct stat s; | ||
66 | if (stat(name, &s) == 0) { | ||
67 | /* coverity[toctou] */ | ||
68 | char* rp = realpath(name, NULL); | ||
69 | if (!rp) | ||
70 | errExit("realpath"); | ||
71 | |||
72 | if (strcmp(selfpath, rp) != 0) { | ||
73 | program = strdup(name); | ||
74 | found = 1; | ||
75 | free(rp); | ||
76 | break; | ||
77 | } | ||
78 | |||
79 | free(rp); | ||
80 | } | ||
81 | |||
82 | free(name); | ||
83 | tok = strtok(NULL, ":"); | ||
84 | } | ||
85 | if (!found) { | ||
86 | fprintf(stderr, "Error: cannot find the program in the path\n"); | 52 | fprintf(stderr, "Error: cannot find the program in the path\n"); |
87 | exit(1); | 53 | exit(1); |
88 | } | 54 | } |
89 | 55 | program = p; | |
90 | free(selfpath); | ||
91 | 56 | ||
92 | // restore original umask | 57 | // restore original umask |
93 | umask(orig_umask); | 58 | umask(orig_umask); |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 5115191ea..d811fe45a 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -461,7 +461,7 @@ static int ok_to_run(const char *program) { | |||
461 | return 0; | 461 | return 0; |
462 | } | 462 | } |
463 | 463 | ||
464 | void start_application(int no_sandbox, char *set_sandbox_status) { | 464 | void start_application(int no_sandbox, int fd, char *set_sandbox_status) { |
465 | // set environment | 465 | // set environment |
466 | if (no_sandbox == 0) { | 466 | if (no_sandbox == 0) { |
467 | env_defaults(); | 467 | env_defaults(); |
@@ -471,7 +471,7 @@ void start_application(int no_sandbox, char *set_sandbox_status) { | |||
471 | umask(orig_umask); | 471 | umask(orig_umask); |
472 | 472 | ||
473 | if (arg_debug) { | 473 | if (arg_debug) { |
474 | printf("starting application\n"); | 474 | printf("Starting application\n"); |
475 | printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD")); | 475 | printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD")); |
476 | } | 476 | } |
477 | 477 | ||
@@ -488,9 +488,6 @@ void start_application(int no_sandbox, char *set_sandbox_status) { | |||
488 | if (set_sandbox_status) | 488 | if (set_sandbox_status) |
489 | *set_sandbox_status = SANDBOX_DONE; | 489 | *set_sandbox_status = SANDBOX_DONE; |
490 | execl(arg_audit_prog, arg_audit_prog, NULL); | 490 | execl(arg_audit_prog, arg_audit_prog, NULL); |
491 | |||
492 | perror("execl"); | ||
493 | exit(1); | ||
494 | } | 491 | } |
495 | //**************************************** | 492 | //**************************************** |
496 | // start the program without using a shell | 493 | // start the program without using a shell |
@@ -532,35 +529,37 @@ void start_application(int no_sandbox, char *set_sandbox_status) { | |||
532 | //**************************************** | 529 | //**************************************** |
533 | else { | 530 | else { |
534 | assert(cfg.shell); | 531 | assert(cfg.shell); |
535 | assert(cfg.command_line); | ||
536 | 532 | ||
537 | char *arg[5]; | 533 | char *arg[5]; |
538 | int index = 0; | 534 | int index = 0; |
539 | arg[index++] = cfg.shell; | 535 | arg[index++] = cfg.shell; |
540 | if (login_shell) { | 536 | if (cfg.command_line) { |
541 | arg[index++] = "-l"; | ||
542 | if (arg_debug) | ||
543 | printf("Starting %s login shell\n", cfg.shell); | ||
544 | } else { | ||
545 | arg[index++] = "-c"; | ||
546 | if (arg_debug) | 537 | if (arg_debug) |
547 | printf("Running %s command through %s\n", cfg.command_line, cfg.shell); | 538 | printf("Running %s command through %s\n", cfg.command_line, cfg.shell); |
539 | arg[index++] = "-c"; | ||
548 | if (arg_doubledash) | 540 | if (arg_doubledash) |
549 | arg[index++] = "--"; | 541 | arg[index++] = "--"; |
550 | arg[index++] = cfg.command_line; | 542 | arg[index++] = cfg.command_line; |
551 | } | 543 | } |
552 | arg[index] = NULL; | 544 | else if (login_shell) { |
545 | if (arg_debug) | ||
546 | printf("Starting %s login shell\n", cfg.shell); | ||
547 | arg[index++] = "-l"; | ||
548 | } | ||
549 | else if (arg_debug) | ||
550 | printf("Starting %s shell\n", cfg.shell); | ||
551 | |||
553 | assert(index < 5); | 552 | assert(index < 5); |
553 | arg[index] = NULL; | ||
554 | 554 | ||
555 | if (arg_debug) { | 555 | if (arg_debug) { |
556 | char *msg; | 556 | char *msg; |
557 | if (asprintf(&msg, "sandbox %d, execvp into %s", sandbox_pid, cfg.command_line) == -1) | 557 | if (asprintf(&msg, "sandbox %d, execvp into %s", |
558 | sandbox_pid, cfg.command_line ? cfg.command_line : cfg.shell) == -1) | ||
558 | errExit("asprintf"); | 559 | errExit("asprintf"); |
559 | logmsg(msg); | 560 | logmsg(msg); |
560 | free(msg); | 561 | free(msg); |
561 | } | ||
562 | 562 | ||
563 | if (arg_debug) { | ||
564 | int i; | 563 | int i; |
565 | for (i = 0; i < 5; i++) { | 564 | for (i = 0; i < 5; i++) { |
566 | if (arg[i] == NULL) | 565 | if (arg[i] == NULL) |
@@ -580,10 +579,14 @@ void start_application(int no_sandbox, char *set_sandbox_status) { | |||
580 | if (set_sandbox_status) | 579 | if (set_sandbox_status) |
581 | *set_sandbox_status = SANDBOX_DONE; | 580 | *set_sandbox_status = SANDBOX_DONE; |
582 | execvp(arg[0], arg); | 581 | execvp(arg[0], arg); |
582 | |||
583 | // join sandbox without shell in the mount namespace | ||
584 | if (fd > -1) | ||
585 | fexecve(fd, arg, environ); | ||
583 | } | 586 | } |
584 | 587 | ||
585 | perror("execvp"); | 588 | perror("Cannot start application"); |
586 | exit(1); // it should never get here!!! | 589 | exit(1); |
587 | } | 590 | } |
588 | 591 | ||
589 | static void enforce_filters(void) { | 592 | static void enforce_filters(void) { |
@@ -1223,7 +1226,7 @@ int sandbox(void* sandbox_arg) { | |||
1223 | set_nice(cfg.nice); | 1226 | set_nice(cfg.nice); |
1224 | set_rlimits(); | 1227 | set_rlimits(); |
1225 | 1228 | ||
1226 | start_application(0, set_sandbox_status); | 1229 | start_application(0, -1, set_sandbox_status); |
1227 | } | 1230 | } |
1228 | 1231 | ||
1229 | munmap(set_sandbox_status, 1); | 1232 | munmap(set_sandbox_status, 1); |
diff --git a/src/firejail/util.c b/src/firejail/util.c index a3927cc88..911c8bd94 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -565,27 +565,18 @@ char *clean_pathname(const char *path) { | |||
565 | if (!rv) | 565 | if (!rv) |
566 | errExit("malloc"); | 566 | errExit("malloc"); |
567 | 567 | ||
568 | if (len > 0) { | 568 | size_t i = 0; |
569 | size_t i = 0, j = 0, cnt = 0; | 569 | size_t j = 0; |
570 | for (; i < len; i++) { | 570 | while (path[i]) { |
571 | if (path[i] == '/') | 571 | while (path[i] == '/' && path[i+1] == '/') |
572 | cnt++; | 572 | i++; |
573 | else | 573 | rv[j++] = path[i++]; |
574 | cnt = 0; | ||
575 | |||
576 | if (cnt < 2) { | ||
577 | rv[j] = path[i]; | ||
578 | j++; | ||
579 | } | ||
580 | } | ||
581 | rv[j] = '\0'; | ||
582 | |||
583 | // remove a trailing slash | ||
584 | if (j > 1 && rv[j - 1] == '/') | ||
585 | rv[j - 1] = '\0'; | ||
586 | } | 574 | } |
587 | else | 575 | rv[j] = '\0'; |
588 | *rv = '\0'; | 576 | |
577 | // remove a trailing slash | ||
578 | if (j > 1 && rv[j - 1] == '/') | ||
579 | rv[j - 1] = '\0'; | ||
589 | 580 | ||
590 | return rv; | 581 | return rv; |
591 | } | 582 | } |
@@ -820,20 +811,6 @@ void notify_other(int fd) { | |||
820 | fclose(stream); | 811 | fclose(stream); |
821 | } | 812 | } |
822 | 813 | ||
823 | |||
824 | |||
825 | |||
826 | // Equivalent to the GNU version of basename, which is incompatible with | ||
827 | // the POSIX basename. A few lines of code saves any portability pain. | ||
828 | // https://www.gnu.org/software/libc/manual/html_node/Finding-Tokens-in-a-String.html#index-basename | ||
829 | const char *gnu_basename(const char *path) { | ||
830 | const char *last_slash = strrchr(path, '/'); | ||
831 | if (!last_slash) | ||
832 | return path; | ||
833 | return last_slash+1; | ||
834 | } | ||
835 | |||
836 | |||
837 | uid_t pid_get_uid(pid_t pid) { | 814 | uid_t pid_get_uid(pid_t pid) { |
838 | EUID_ASSERT(); | 815 | EUID_ASSERT(); |
839 | uid_t rv = 0; | 816 | uid_t rv = 0; |
diff --git a/src/fldd/Makefile.in b/src/fldd/Makefile.in index 53382c2df..37b139d38 100644 --- a/src/fldd/Makefile.in +++ b/src/fldd/Makefile.in | |||
@@ -5,8 +5,8 @@ include ../common.mk | |||
5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h ../include/ldd_utils.h | 5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h ../include/ldd_utils.h |
6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | 6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ |
7 | 7 | ||
8 | fldd: $(OBJS) ../lib/ldd_utils.o | 8 | fldd: $(OBJS) ../lib/common.o ../lib/ldd_utils.o |
9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/ldd_utils.o $(LIBS) $(EXTRA_LDFLAGS) | 9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o ../lib/ldd_utils.o $(LIBS) $(EXTRA_LDFLAGS) |
10 | 10 | ||
11 | clean:; rm -fr *.o fldd *.gcov *.gcda *.gcno *.plist | 11 | clean:; rm -fr *.o fldd *.gcov *.gcda *.gcno *.plist |
12 | 12 | ||
diff --git a/src/fldd/main.c b/src/fldd/main.c index d68504f6b..55a0dfcce 100644 --- a/src/fldd/main.c +++ b/src/fldd/main.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <fcntl.h> | 24 | #include <fcntl.h> |
25 | #include <sys/mman.h> | 25 | #include <sys/mman.h> |
26 | #include <sys/mount.h> | 26 | #include <sys/mount.h> |
27 | #include <sys/prctl.h> | ||
28 | #include <sys/stat.h> | 27 | #include <sys/stat.h> |
29 | #include <sys/types.h> | 28 | #include <sys/types.h> |
30 | #include <unistd.h> | 29 | #include <unistd.h> |
@@ -303,10 +302,7 @@ printf("\n"); | |||
303 | return 0; | 302 | return 0; |
304 | } | 303 | } |
305 | 304 | ||
306 | #ifdef WARN_DUMPABLE | 305 | warn_dumpable(); |
307 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid()) | ||
308 | fprintf(stderr, "Error fldd: I am dumpable\n"); | ||
309 | #endif | ||
310 | 306 | ||
311 | // check program access | 307 | // check program access |
312 | if (access(argv[1], R_OK)) { | 308 | if (access(argv[1], R_OK)) { |
diff --git a/src/fnet/Makefile.in b/src/fnet/Makefile.in index 37566db72..bd5fe9e7a 100644 --- a/src/fnet/Makefile.in +++ b/src/fnet/Makefile.in | |||
@@ -5,8 +5,8 @@ include ../common.mk | |||
5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/libnetlink.h | 5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/libnetlink.h |
6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | 6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ |
7 | 7 | ||
8 | fnet: $(OBJS) ../lib/libnetlink.o | 8 | fnet: $(OBJS) ../lib/common.o ../lib/libnetlink.o |
9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o $(LIBS) $(EXTRA_LDFLAGS) | 9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o ../lib/libnetlink.o $(LIBS) $(EXTRA_LDFLAGS) |
10 | 10 | ||
11 | clean:; rm -fr *.o fnet *.gcov *.gcda *.gcno *.plist | 11 | clean:; rm -fr *.o fnet *.gcov *.gcda *.gcno *.plist |
12 | 12 | ||
diff --git a/src/fnet/main.c b/src/fnet/main.c index f6316a7fe..db090fb95 100644 --- a/src/fnet/main.c +++ b/src/fnet/main.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <sys/types.h> | 21 | #include <sys/types.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <sys/utsname.h> | 23 | #include <sys/utsname.h> |
24 | #include <sys/prctl.h> | ||
25 | 24 | ||
26 | int arg_quiet = 0; | 25 | int arg_quiet = 0; |
27 | 26 | ||
@@ -69,10 +68,9 @@ printf("\n"); | |||
69 | usage(); | 68 | usage(); |
70 | return 0; | 69 | return 0; |
71 | } | 70 | } |
72 | #ifdef WARN_DUMPABLE | 71 | |
73 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid()) | 72 | warn_dumpable(); |
74 | fprintf(stderr, "Error fnet: I am dumpable\n"); | 73 | |
75 | #endif | ||
76 | char *quiet = getenv("FIREJAIL_QUIET"); | 74 | char *quiet = getenv("FIREJAIL_QUIET"); |
77 | if (quiet && strcmp(quiet, "yes") == 0) | 75 | if (quiet && strcmp(quiet, "yes") == 0) |
78 | arg_quiet = 1; | 76 | arg_quiet = 1; |
diff --git a/src/fnetfilter/Makefile.in b/src/fnetfilter/Makefile.in index 055167192..6fe650a17 100644 --- a/src/fnetfilter/Makefile.in +++ b/src/fnetfilter/Makefile.in | |||
@@ -5,8 +5,8 @@ include ../common.mk | |||
5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h | 5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h |
6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | 6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ |
7 | 7 | ||
8 | fnetfilter: $(OBJS) | 8 | fnetfilter: $(OBJS) ../lib/common.o |
9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) | 9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS) |
10 | 10 | ||
11 | clean:; rm -fr *.o fnetfilter *.gcov *.gcda *.gcno *.plist | 11 | clean:; rm -fr *.o fnetfilter *.gcov *.gcda *.gcno *.plist |
12 | 12 | ||
diff --git a/src/fnetfilter/main.c b/src/fnetfilter/main.c index 1ca35ab56..381d0d36e 100644 --- a/src/fnetfilter/main.c +++ b/src/fnetfilter/main.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "../include/common.h" | 20 | #include "../include/common.h" |
21 | #include <sys/prctl.h> | ||
22 | 21 | ||
23 | #define MAXBUF 4098 | 22 | #define MAXBUF 4098 |
24 | #define MAXARGS 16 | 23 | #define MAXARGS 16 |
@@ -181,10 +180,9 @@ printf("\n"); | |||
181 | usage(); | 180 | usage(); |
182 | return 1; | 181 | return 1; |
183 | } | 182 | } |
184 | #ifdef WARN_DUMPABLE | 183 | |
185 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid()) | 184 | warn_dumpable(); |
186 | fprintf(stderr, "Error fnetfilter: I am dumpable\n"); | 185 | |
187 | #endif | ||
188 | char *destfile = (argc == 3)? argv[2]: argv[1]; | 186 | char *destfile = (argc == 3)? argv[2]: argv[1]; |
189 | char *command = (argc == 3)? argv[1]: NULL; | 187 | char *command = (argc == 3)? argv[1]: NULL; |
190 | //printf("command %s\n", command); | 188 | //printf("command %s\n", command); |
diff --git a/src/fsec-optimize/Makefile.in b/src/fsec-optimize/Makefile.in index 0387f7ec7..b6a28fdd8 100644 --- a/src/fsec-optimize/Makefile.in +++ b/src/fsec-optimize/Makefile.in | |||
@@ -5,8 +5,8 @@ include ../common.mk | |||
5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/seccomp.h ../include/syscall.h | 5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/seccomp.h ../include/syscall.h |
6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | 6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ |
7 | 7 | ||
8 | fsec-optimize: $(OBJS) ../lib/libnetlink.o | 8 | fsec-optimize: $(OBJS) ../lib/common.o ../lib/libnetlink.o |
9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) | 9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS) |
10 | 10 | ||
11 | clean:; rm -fr *.o fsec-optimize *.gcov *.gcda *.gcno *.plist | 11 | clean:; rm -fr *.o fsec-optimize *.gcov *.gcda *.gcno *.plist |
12 | 12 | ||
diff --git a/src/fsec-optimize/fsec_optimize.h b/src/fsec-optimize/fsec_optimize.h index 034fde2ac..211111641 100644 --- a/src/fsec-optimize/fsec_optimize.h +++ b/src/fsec-optimize/fsec_optimize.h | |||
@@ -22,7 +22,6 @@ | |||
22 | #include "../include/common.h" | 22 | #include "../include/common.h" |
23 | #include "../include/seccomp.h" | 23 | #include "../include/seccomp.h" |
24 | #include <sys/mman.h> | 24 | #include <sys/mman.h> |
25 | #include <sys/prctl.h> | ||
26 | 25 | ||
27 | // optimize.c | 26 | // optimize.c |
28 | struct sock_filter *duplicate(struct sock_filter *filter, int entries); | 27 | struct sock_filter *duplicate(struct sock_filter *filter, int entries); |
diff --git a/src/fsec-optimize/main.c b/src/fsec-optimize/main.c index fb13eeca8..74aebc9e0 100644 --- a/src/fsec-optimize/main.c +++ b/src/fsec-optimize/main.c | |||
@@ -44,11 +44,7 @@ printf("\n"); | |||
44 | return 0; | 44 | return 0; |
45 | } | 45 | } |
46 | 46 | ||
47 | #ifdef WARN_DUMPABLE | 47 | warn_dumpable(); |
48 | // check FIREJAIL_PLUGIN in order to not print a warning during make | ||
49 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid() && getenv("FIREJAIL_PLUGIN")) | ||
50 | fprintf(stderr, "Error fsec-optimize: I am dumpable\n"); | ||
51 | #endif | ||
52 | 48 | ||
53 | char *fname = argv[1]; | 49 | char *fname = argv[1]; |
54 | 50 | ||
diff --git a/src/fsec-print/Makefile.in b/src/fsec-print/Makefile.in index a30ff4ba3..bf39a8c77 100644 --- a/src/fsec-print/Makefile.in +++ b/src/fsec-print/Makefile.in | |||
@@ -5,8 +5,8 @@ include ../common.mk | |||
5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/seccomp.h ../include/syscall.h | 5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/seccomp.h ../include/syscall.h |
6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | 6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ |
7 | 7 | ||
8 | fsec-print: $(OBJS) ../lib/libnetlink.o ../lib/errno.o ../lib/syscall.o | 8 | fsec-print: $(OBJS) ../lib/common.o ../lib/libnetlink.o ../lib/errno.o ../lib/syscall.o |
9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/errno.o ../lib/syscall.o $(LIBS) $(EXTRA_LDFLAGS) | 9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o ../lib/errno.o ../lib/syscall.o $(LIBS) $(EXTRA_LDFLAGS) |
10 | 10 | ||
11 | clean:; rm -fr *.o fsec-print *.gcov *.gcda *.gcno *.plist | 11 | clean:; rm -fr *.o fsec-print *.gcov *.gcda *.gcno *.plist |
12 | 12 | ||
diff --git a/src/fsec-print/fsec_print.h b/src/fsec-print/fsec_print.h index 9d17e3f18..337199288 100644 --- a/src/fsec-print/fsec_print.h +++ b/src/fsec-print/fsec_print.h | |||
@@ -23,7 +23,6 @@ | |||
23 | #include "../include/seccomp.h" | 23 | #include "../include/seccomp.h" |
24 | #include "../include/syscall.h" | 24 | #include "../include/syscall.h" |
25 | #include <sys/mman.h> | 25 | #include <sys/mman.h> |
26 | #include <sys/prctl.h> | ||
27 | 26 | ||
28 | // print.c | 27 | // print.c |
29 | void print(struct sock_filter *filter, int entries); | 28 | void print(struct sock_filter *filter, int entries); |
diff --git a/src/fsec-print/main.c b/src/fsec-print/main.c index d1f056e47..ed030db21 100644 --- a/src/fsec-print/main.c +++ b/src/fsec-print/main.c | |||
@@ -61,10 +61,7 @@ printf("\n"); | |||
61 | return 0; | 61 | return 0; |
62 | } | 62 | } |
63 | 63 | ||
64 | #ifdef WARN_DUMPABLE | 64 | warn_dumpable(); |
65 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid()) | ||
66 | fprintf(stderr, "Error fsec-print: I am dumpable\n"); | ||
67 | #endif | ||
68 | 65 | ||
69 | char *fname = argv[1]; | 66 | char *fname = argv[1]; |
70 | 67 | ||
diff --git a/src/fseccomp/Makefile.in b/src/fseccomp/Makefile.in index 8623db6f8..b776a73ce 100644 --- a/src/fseccomp/Makefile.in +++ b/src/fseccomp/Makefile.in | |||
@@ -5,8 +5,8 @@ include ../common.mk | |||
5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h | 5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h |
6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | 6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ |
7 | 7 | ||
8 | fseccomp: $(OBJS) ../lib/errno.o ../lib/syscall.o | 8 | fseccomp: $(OBJS) ../lib/common.o ../lib/errno.o ../lib/syscall.o |
9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/errno.o ../lib/syscall.o $(LIBS) $(EXTRA_LDFLAGS) | 9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o ../lib/errno.o ../lib/syscall.o $(LIBS) $(EXTRA_LDFLAGS) |
10 | 10 | ||
11 | clean:; rm -fr *.o fseccomp *.gcov *.gcda *.gcno *.plist | 11 | clean:; rm -fr *.o fseccomp *.gcov *.gcda *.gcno *.plist |
12 | 12 | ||
diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h index e40999938..e8dd083b6 100644 --- a/src/fseccomp/fseccomp.h +++ b/src/fseccomp/fseccomp.h | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <stdlib.h> | 23 | #include <stdlib.h> |
24 | #include <string.h> | 24 | #include <string.h> |
25 | #include <assert.h> | 25 | #include <assert.h> |
26 | #include <sys/prctl.h> | ||
27 | #include "../include/common.h" | 26 | #include "../include/common.h" |
28 | #include "../include/syscall.h" | 27 | #include "../include/syscall.h" |
29 | 28 | ||
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index f505ca0f3..c8259b079 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c | |||
@@ -69,11 +69,7 @@ printf("\n"); | |||
69 | return 0; | 69 | return 0; |
70 | } | 70 | } |
71 | 71 | ||
72 | #ifdef WARN_DUMPABLE | 72 | warn_dumpable(); |
73 | // check FIREJAIL_PLUGIN in order to not print a warning during make | ||
74 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid() && getenv("FIREJAIL_PLUGIN")) | ||
75 | fprintf(stderr, "Error fseccomp: I am dumpable\n"); | ||
76 | #endif | ||
77 | 73 | ||
78 | char *quiet = getenv("FIREJAIL_QUIET"); | 74 | char *quiet = getenv("FIREJAIL_QUIET"); |
79 | if (quiet && strcmp(quiet, "yes") == 0) | 75 | if (quiet && strcmp(quiet, "yes") == 0) |
diff --git a/src/include/common.h b/src/include/common.h index 5df51c5a9..5497929c7 100644 --- a/src/include/common.h +++ b/src/include/common.h | |||
@@ -38,11 +38,6 @@ | |||
38 | 38 | ||
39 | #define errExit(msg) do { char msgout[500]; snprintf(msgout, 500, "Error %s: %s:%d %s", msg, __FILE__, __LINE__, __FUNCTION__); perror(msgout); exit(1);} while (0) | 39 | #define errExit(msg) do { char msgout[500]; snprintf(msgout, 500, "Error %s: %s:%d %s", msg, __FILE__, __LINE__, __FUNCTION__); perror(msgout); exit(1);} while (0) |
40 | 40 | ||
41 | // check if processes run with dumpable flag set | ||
42 | // currently we get "Error fseccomp: I am dumpable" every time we run a firejail build on Debian 8, | ||
43 | // regardless what Debian version we run the build on | ||
44 | //#define WARN_DUMPABLE | ||
45 | |||
46 | // macro to print ip addresses in a printf statement | 41 | // macro to print ip addresses in a printf statement |
47 | #define PRINT_IP(A) \ | 42 | #define PRINT_IP(A) \ |
48 | ((int) (((A) >> 24) & 0xFF)), ((int) (((A) >> 16) & 0xFF)), ((int) (((A) >> 8) & 0xFF)), ((int) ( (A) & 0xFF)) | 43 | ((int) (((A) >> 24) & 0xFF)), ((int) (((A) >> 16) & 0xFF)), ((int) (((A) >> 8) & 0xFF)), ((int) ( (A) & 0xFF)) |
@@ -126,4 +121,6 @@ char *pid_proc_comm(const pid_t pid); | |||
126 | char *pid_proc_cmdline(const pid_t pid); | 121 | char *pid_proc_cmdline(const pid_t pid); |
127 | int pid_proc_cmdline_x11_xpra_xephyr(const pid_t pid); | 122 | int pid_proc_cmdline_x11_xpra_xephyr(const pid_t pid); |
128 | int pid_hidepid(void); | 123 | int pid_hidepid(void); |
124 | void warn_dumpable(void); | ||
125 | const char *gnu_basename(const char *path); | ||
129 | #endif | 126 | #endif |
diff --git a/src/lib/common.c b/src/lib/common.c index 823442835..ace5cb87e 100644 --- a/src/lib/common.c +++ b/src/lib/common.c | |||
@@ -267,7 +267,6 @@ int pid_proc_cmdline_x11_xpra_xephyr(const pid_t pid) { | |||
267 | } | 267 | } |
268 | 268 | ||
269 | // return 1 if /proc is mounted hidepid, or if /proc/mouns access is denied | 269 | // return 1 if /proc is mounted hidepid, or if /proc/mouns access is denied |
270 | #define BUFLEN 4096 | ||
271 | int pid_hidepid(void) { | 270 | int pid_hidepid(void) { |
272 | FILE *fp = fopen("/proc/mounts", "r"); | 271 | FILE *fp = fopen("/proc/mounts", "r"); |
273 | if (!fp) | 272 | if (!fp) |
@@ -288,6 +287,39 @@ int pid_hidepid(void) { | |||
288 | return 0; | 287 | return 0; |
289 | } | 288 | } |
290 | 289 | ||
290 | // print error if unprivileged users can trace the process | ||
291 | void warn_dumpable(void) { | ||
292 | if (getuid() != 0 && prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getenv("FIREJAIL_PLUGIN")) { | ||
293 | fprintf(stderr, "Error: dumpable process\n"); | ||
294 | |||
295 | // best effort to provide detailed debug information | ||
296 | // cannot use process name, it is just a file descriptor number | ||
297 | char path[BUFLEN]; | ||
298 | ssize_t len = readlink("/proc/self/exe", path, BUFLEN - 1); | ||
299 | if (len < 0) | ||
300 | return; | ||
301 | path[len] = '\0'; | ||
302 | // path can refer to a sandbox mount namespace, use basename only | ||
303 | const char *base = gnu_basename(path); | ||
304 | |||
305 | struct stat s; | ||
306 | if (stat("/proc/self/exe", &s) == 0 && s.st_uid != 0) | ||
307 | fprintf(stderr, "Change owner of %s executable to root\n", base); | ||
308 | else if (access("/proc/self/exe", R_OK) == 0) | ||
309 | fprintf(stderr, "Remove read permission on %s executable\n", base); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | // Equivalent to the GNU version of basename, which is incompatible with | ||
314 | // the POSIX basename. A few lines of code saves any portability pain. | ||
315 | // https://www.gnu.org/software/libc/manual/html_node/Finding-Tokens-in-a-String.html#index-basename | ||
316 | const char *gnu_basename(const char *path) { | ||
317 | const char *last_slash = strrchr(path, '/'); | ||
318 | if (!last_slash) | ||
319 | return path; | ||
320 | return last_slash+1; | ||
321 | } | ||
322 | |||
291 | //************************** | 323 | //************************** |
292 | // time trace based on getticks function | 324 | // time trace based on getticks function |
293 | //************************** | 325 | //************************** |
diff --git a/src/lib/syscall.c b/src/lib/syscall.c index 4903971ad..6823d0ae6 100644 --- a/src/lib/syscall.c +++ b/src/lib/syscall.c | |||
@@ -336,6 +336,7 @@ static const SyscallGroupList sysgroups[] = { | |||
336 | #endif | 336 | #endif |
337 | }, | 337 | }, |
338 | { .name = "@default-keep", .list = | 338 | { .name = "@default-keep", .list = |
339 | "execveat," // commonly used by fexecve | ||
339 | "execve," | 340 | "execve," |
340 | "prctl" | 341 | "prctl" |
341 | }, | 342 | }, |
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 9524254c1..030a3c95c 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt | |||
@@ -862,6 +862,11 @@ the parent interface specified by --net is not configured. An IP address and | |||
862 | a default gateway address also have to be added. | 862 | a default gateway address also have to be added. |
863 | 863 | ||
864 | .TP | 864 | .TP |
865 | \fBnetns namespace | ||
866 | Run the program in a named, persistent network namespace. These can | ||
867 | be created and configured using "ip netns". | ||
868 | |||
869 | .TP | ||
865 | \fBveth-name name | 870 | \fBveth-name name |
866 | Use this name for the interface connected to the bridge for --net=bridge_interface commands, | 871 | Use this name for the interface connected to the bridge for --net=bridge_interface commands, |
867 | instead of the default one. | 872 | instead of the default one. |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 562b3eda3..e72ef48c2 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -76,10 +76,10 @@ If an appropriate profile is not found, Firejail will use a default profile. | |||
76 | The default profile is quite restrictive. In case the application doesn't work, use --noprofile option | 76 | The default profile is quite restrictive. In case the application doesn't work, use --noprofile option |
77 | to disable it. For more information, please see \fBSECURITY PROFILES\fR section below. | 77 | to disable it. For more information, please see \fBSECURITY PROFILES\fR section below. |
78 | .PP | 78 | .PP |
79 | If a program argument is not specified, Firejail starts /bin/bash shell. | 79 | If a program argument is not specified, Firejail starts the user's preferred shell. |
80 | Examples: | 80 | Examples: |
81 | .PP | 81 | .PP |
82 | $ firejail [OPTIONS] # starting a /bin/bash shell | 82 | $ firejail [OPTIONS] # starting the program specified in $SHELL, usually /bin/bash |
83 | .PP | 83 | .PP |
84 | $ firejail [OPTIONS] firefox # starting Mozilla Firefox | 84 | $ firejail [OPTIONS] firefox # starting Mozilla Firefox |
85 | .PP | 85 | .PP |
@@ -2273,7 +2273,7 @@ rm: cannot remove `testfile': Operation not permitted | |||
2273 | .TP | 2273 | .TP |
2274 | \fB\-\-seccomp.keep=syscall,@group,!syscall2 | 2274 | \fB\-\-seccomp.keep=syscall,@group,!syscall2 |
2275 | Enable seccomp filter, blacklist all syscall not listed and "syscall2". | 2275 | Enable seccomp filter, blacklist all syscall not listed and "syscall2". |
2276 | The system calls needed by Firejail (group @default-keep: prctl, execve) | 2276 | The system calls needed by Firejail (group @default-keep: prctl, execve, execveat) |
2277 | are handled with the preload library. On a 64 bit architecture, an | 2277 | are handled with the preload library. On a 64 bit architecture, an |
2278 | additional filter for 32 bit system calls can be installed with | 2278 | additional filter for 32 bit system calls can be installed with |
2279 | \-\-seccomp.32.keep. | 2279 | \-\-seccomp.32.keep. |
@@ -2476,7 +2476,7 @@ $ firejail \-\-shell=none script.sh | |||
2476 | \fB\-\-shell=program | 2476 | \fB\-\-shell=program |
2477 | Set default user shell. Use this shell to run the application using \-c shell option. | 2477 | Set default user shell. Use this shell to run the application using \-c shell option. |
2478 | For example "firejail \-\-shell=/bin/dash firefox" will start Mozilla Firefox as "/bin/dash \-c firefox". | 2478 | For example "firejail \-\-shell=/bin/dash firefox" will start Mozilla Firefox as "/bin/dash \-c firefox". |
2479 | By default Bash shell (/bin/bash) is used. | 2479 | By default the user's preferred shell is used. |
2480 | .br | 2480 | .br |
2481 | 2481 | ||
2482 | .br | 2482 | .br |
@@ -3023,7 +3023,7 @@ We provide a tool that automates all this integration, please see \&\flfirecfg\f | |||
3023 | .SH EXAMPLES | 3023 | .SH EXAMPLES |
3024 | .TP | 3024 | .TP |
3025 | \f\firejail | 3025 | \f\firejail |
3026 | Sandbox a regular /bin/bash session. | 3026 | Sandbox a regular shell session. |
3027 | .TP | 3027 | .TP |
3028 | \f\firejail firefox | 3028 | \f\firejail firefox |
3029 | Start Mozilla Firefox. | 3029 | Start Mozilla Firefox. |
@@ -3043,7 +3043,7 @@ Start Firefox in a new network namespace. An IP address is | |||
3043 | assigned automatically. | 3043 | assigned automatically. |
3044 | .TP | 3044 | .TP |
3045 | \f\firejail \-\-net=br0 \-\-ip=10.10.20.5 \-\-net=br1 \-\-net=br2 | 3045 | \f\firejail \-\-net=br0 \-\-ip=10.10.20.5 \-\-net=br1 \-\-net=br2 |
3046 | Start a /bin/bash session in a new network namespace and connect it | 3046 | Start a shell session in a new network namespace and connect it |
3047 | to br0, br1, and br2 host bridge devices. IP addresses are assigned | 3047 | to br0, br1, and br2 host bridge devices. IP addresses are assigned |
3048 | automatically for the interfaces connected to br1 and b2 | 3048 | automatically for the interfaces connected to br1 and b2 |
3049 | #endif | 3049 | #endif |
diff --git a/src/profstats/main.c b/src/profstats/main.c index 4c1221464..68f62831b 100644 --- a/src/profstats/main.c +++ b/src/profstats/main.c | |||
@@ -30,6 +30,8 @@ static int cnt_seccomp = 0; | |||
30 | static int cnt_caps = 0; | 30 | static int cnt_caps = 0; |
31 | static int cnt_dbus_system_none = 0; | 31 | static int cnt_dbus_system_none = 0; |
32 | static int cnt_dbus_user_none = 0; | 32 | static int cnt_dbus_user_none = 0; |
33 | static int cnt_dbus_system_filter = 0; | ||
34 | static int cnt_dbus_user_filter = 0; | ||
33 | static int cnt_dotlocal = 0; | 35 | static int cnt_dotlocal = 0; |
34 | static int cnt_globalsdotlocal = 0; | 36 | static int cnt_globalsdotlocal = 0; |
35 | static int cnt_netnone = 0; | 37 | static int cnt_netnone = 0; |
@@ -107,6 +109,7 @@ void process_file(const char *fname) { | |||
107 | return; | 109 | return; |
108 | } | 110 | } |
109 | 111 | ||
112 | int have_include_local = 0; | ||
110 | char buf[MAXBUF]; | 113 | char buf[MAXBUF]; |
111 | while (fgets(buf, MAXBUF, fp)) { | 114 | while (fgets(buf, MAXBUF, fp)) { |
112 | char *ptr = strchr(buf, '\n'); | 115 | char *ptr = strchr(buf, '\n'); |
@@ -152,11 +155,16 @@ void process_file(const char *fname) { | |||
152 | cnt_privateetc++; | 155 | cnt_privateetc++; |
153 | else if (strncmp(ptr, "dbus-system none", 16) == 0) | 156 | else if (strncmp(ptr, "dbus-system none", 16) == 0) |
154 | cnt_dbus_system_none++; | 157 | cnt_dbus_system_none++; |
158 | else if (strncmp(ptr, "dbus-system", 11) == 0) | ||
159 | cnt_dbus_system_filter++; | ||
155 | else if (strncmp(ptr, "dbus-user none", 14) == 0) | 160 | else if (strncmp(ptr, "dbus-user none", 14) == 0) |
156 | cnt_dbus_user_none++; | 161 | cnt_dbus_user_none++; |
162 | else if (strncmp(ptr, "dbus-user", 9) == 0) | ||
163 | cnt_dbus_user_filter++; | ||
157 | else if (strncmp(ptr, "include ", 8) == 0) { | 164 | else if (strncmp(ptr, "include ", 8) == 0) { |
158 | // not processing .local files | 165 | // not processing .local files |
159 | if (strstr(ptr, ".local")) { | 166 | if (strstr(ptr, ".local")) { |
167 | have_include_local = 1; | ||
160 | //printf("dotlocal %d, level %d - #%s#, redirect #%s#\n", cnt_dotlocal, level, fname, buf + 8); | 168 | //printf("dotlocal %d, level %d - #%s#, redirect #%s#\n", cnt_dotlocal, level, fname, buf + 8); |
161 | if (strstr(ptr, "globals.local")) | 169 | if (strstr(ptr, "globals.local")) |
162 | cnt_globalsdotlocal++; | 170 | cnt_globalsdotlocal++; |
@@ -174,6 +182,8 @@ void process_file(const char *fname) { | |||
174 | } | 182 | } |
175 | 183 | ||
176 | fclose(fp); | 184 | fclose(fp); |
185 | if (!have_include_local) | ||
186 | printf("No include .local found in %s\n", fname); | ||
177 | level--; | 187 | level--; |
178 | } | 188 | } |
179 | 189 | ||
@@ -257,7 +267,9 @@ int main(int argc, char **argv) { | |||
257 | int whitelistrunuser = cnt_whitelistrunuser; | 267 | int whitelistrunuser = cnt_whitelistrunuser; |
258 | int whitelistusrshare = cnt_whitelistusrshare; | 268 | int whitelistusrshare = cnt_whitelistusrshare; |
259 | int dbussystemnone = cnt_dbus_system_none; | 269 | int dbussystemnone = cnt_dbus_system_none; |
270 | int dbussystemfilter = cnt_dbus_system_filter; | ||
260 | int dbususernone = cnt_dbus_user_none; | 271 | int dbususernone = cnt_dbus_user_none; |
272 | int dbususerfilter = cnt_dbus_user_filter; | ||
261 | int ssh = cnt_ssh; | 273 | int ssh = cnt_ssh; |
262 | int mdwx = cnt_mdwx; | 274 | int mdwx = cnt_mdwx; |
263 | 275 | ||
@@ -278,6 +290,16 @@ int main(int argc, char **argv) { | |||
278 | cnt_globalsdotlocal = globalsdotlocal + 1; | 290 | cnt_globalsdotlocal = globalsdotlocal + 1; |
279 | if (cnt_whitelistrunuser > (whitelistrunuser + 1)) | 291 | if (cnt_whitelistrunuser > (whitelistrunuser + 1)) |
280 | cnt_whitelistrunuser = whitelistrunuser + 1; | 292 | cnt_whitelistrunuser = whitelistrunuser + 1; |
293 | if (cnt_seccomp > (seccomp + 1)) | ||
294 | cnt_seccomp = seccomp + 1; | ||
295 | if (cnt_dbus_user_none > (dbususernone + 1)) | ||
296 | cnt_dbus_user_none = dbususernone + 1; | ||
297 | if (cnt_dbus_user_filter > (dbususerfilter + 1)) | ||
298 | cnt_dbus_user_filter = dbususerfilter + 1; | ||
299 | if (cnt_dbus_system_none > (dbussystemnone + 1)) | ||
300 | cnt_dbus_system_none = dbussystemnone + 1; | ||
301 | if (cnt_dbus_system_filter > (dbussystemfilter + 1)) | ||
302 | cnt_dbus_system_filter = dbussystemfilter + 1; | ||
281 | 303 | ||
282 | if (arg_dbus_system_none && dbussystemnone == cnt_dbus_system_none) | 304 | if (arg_dbus_system_none && dbussystemnone == cnt_dbus_system_none) |
283 | printf("No dbus-system none found in %s\n", argv[i]); | 305 | printf("No dbus-system none found in %s\n", argv[i]); |
@@ -337,7 +359,9 @@ int main(int argc, char **argv) { | |||
337 | printf(" whitelist usr/share\t\t%d (include whitelist-usr-share-common.inc\n", cnt_whitelistusrshare); | 359 | printf(" whitelist usr/share\t\t%d (include whitelist-usr-share-common.inc\n", cnt_whitelistusrshare); |
338 | printf(" net none\t\t\t%d\n", cnt_netnone); | 360 | printf(" net none\t\t\t%d\n", cnt_netnone); |
339 | printf(" dbus-user none \t\t%d\n", cnt_dbus_user_none); | 361 | printf(" dbus-user none \t\t%d\n", cnt_dbus_user_none); |
362 | printf(" dbus-user filter \t\t%d\n", cnt_dbus_user_filter); | ||
340 | printf(" dbus-system none \t\t%d\n", cnt_dbus_system_none); | 363 | printf(" dbus-system none \t\t%d\n", cnt_dbus_system_none); |
364 | printf(" dbus-system filter \t\t%d\n", cnt_dbus_system_filter); | ||
341 | printf("\n"); | 365 | printf("\n"); |
342 | return 0; | 366 | return 0; |
343 | } | 367 | } |