diff options
Diffstat (limited to 'src')
58 files changed, 633 insertions, 355 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 23b1e364a..d056d0654 100644 --- a/src/firecfg/firecfg.config +++ b/src/firecfg/firecfg.config | |||
@@ -69,6 +69,7 @@ autokey-gtk | |||
69 | autokey-qt | 69 | autokey-qt |
70 | autokey-run | 70 | autokey-run |
71 | autokey-shell | 71 | autokey-shell |
72 | avidemux3_qt5 | ||
72 | aweather | 73 | aweather |
73 | baloo_file | 74 | baloo_file |
74 | baloo_filemetadata_temp_extractor | 75 | baloo_filemetadata_temp_extractor |
@@ -106,6 +107,7 @@ calligra | |||
106 | calligraauthor | 107 | calligraauthor |
107 | calligraconverter | 108 | calligraconverter |
108 | calligraflow | 109 | calligraflow |
110 | calligragemini | ||
109 | calligraplan | 111 | calligraplan |
110 | calligraplanwork | 112 | calligraplanwork |
111 | calligrasheets | 113 | calligrasheets |
@@ -149,6 +151,7 @@ conkeror | |||
149 | conky | 151 | conky |
150 | conplay | 152 | conplay |
151 | corebird | 153 | corebird |
154 | coyim | ||
152 | crawl | 155 | crawl |
153 | crawl-tiles | 156 | crawl-tiles |
154 | crow | 157 | crow |
@@ -172,6 +175,7 @@ dino-im | |||
172 | discord | 175 | discord |
173 | discord-canary | 176 | discord-canary |
174 | display | 177 | display |
178 | display-im6.q16 | ||
175 | dnox | 179 | dnox |
176 | dnscrypt-proxy | 180 | dnscrypt-proxy |
177 | dnsmasq | 181 | dnsmasq |
@@ -390,6 +394,7 @@ kazam | |||
390 | kcalc | 394 | kcalc |
391 | # kdeinit4 | 395 | # kdeinit4 |
392 | kdenlive | 396 | kdenlive |
397 | kdiff3 | ||
393 | keepass | 398 | keepass |
394 | keepass2 | 399 | keepass2 |
395 | keepassx | 400 | keepassx |
@@ -455,6 +460,7 @@ macrofusion | |||
455 | magicor | 460 | magicor |
456 | # man | 461 | # man |
457 | manaplus | 462 | manaplus |
463 | marker | ||
458 | masterpdfeditor | 464 | masterpdfeditor |
459 | masterpdfeditor4 | 465 | masterpdfeditor4 |
460 | masterpdfeditor5 | 466 | masterpdfeditor5 |
@@ -532,6 +538,7 @@ mypaint | |||
532 | mypaint-ora-thumbnailer | 538 | mypaint-ora-thumbnailer |
533 | natron | 539 | natron |
534 | ncdu | 540 | ncdu |
541 | neomutt | ||
535 | netactview | 542 | netactview |
536 | nethack | 543 | nethack |
537 | netsurf | 544 | netsurf |
@@ -621,6 +628,7 @@ qemu-launcher | |||
621 | qgis | 628 | qgis |
622 | qlipper | 629 | qlipper |
623 | qmmp | 630 | qmmp |
631 | qnapi | ||
624 | qpdfview | 632 | qpdfview |
625 | qt-faststart | 633 | qt-faststart |
626 | qtox | 634 | qtox |
@@ -662,6 +670,7 @@ secret-tool | |||
662 | shellcheck | 670 | shellcheck |
663 | shortwave | 671 | shortwave |
664 | shotcut | 672 | shotcut |
673 | shotwell | ||
665 | signal-cli | 674 | signal-cli |
666 | signal-desktop | 675 | signal-desktop |
667 | silentarmy | 676 | silentarmy |
@@ -771,6 +780,7 @@ tremulous | |||
771 | trojita | 780 | trojita |
772 | truecraft | 781 | truecraft |
773 | tshark | 782 | tshark |
783 | tutanota-desktop | ||
774 | tuxguitar | 784 | tuxguitar |
775 | tvbrowser | 785 | tvbrowser |
776 | twitch | 786 | twitch |
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c index 6190b6f01..dd94b9921 100644 --- a/src/firejail/appimage.c +++ b/src/firejail/appimage.c | |||
@@ -131,14 +131,16 @@ void appimage_set(const char *appimage) { | |||
131 | errExit("Failed to obtain absolute path"); | 131 | errExit("Failed to obtain absolute path"); |
132 | 132 | ||
133 | // set environment | 133 | // set environment |
134 | if (setenv("APPIMAGE", abspath, 1) < 0) | 134 | env_store_name_val("APPIMAGE", abspath, SETENV); |
135 | errExit("setenv"); | 135 | |
136 | if (mntdir && setenv("APPDIR", mntdir, 1) < 0) | 136 | if (mntdir) |
137 | errExit("setenv"); | 137 | env_store_name_val("APPDIR", mntdir, SETENV); |
138 | if (size != 0 && setenv("ARGV0", appimage, 1) < 0) | 138 | |
139 | errExit("setenv"); | 139 | if (size != 0) |
140 | if (cfg.cwd && setenv("OWD", cfg.cwd, 1) < 0) | 140 | env_store_name_val("ARGV0", appimage, SETENV); |
141 | errExit("setenv"); | 141 | |
142 | if (cfg.cwd) | ||
143 | env_store_name_val("OWD", cfg.cwd, SETENV); | ||
142 | 144 | ||
143 | // build new command line | 145 | // build new command line |
144 | if (asprintf(&cfg.command_line, "%s/AppRun", mntdir) == -1) | 146 | if (asprintf(&cfg.command_line, "%s/AppRun", mntdir) == -1) |
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index 085221464..fb2171a55 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c | |||
@@ -215,10 +215,8 @@ int checkcfg(int val) { | |||
215 | } | 215 | } |
216 | 216 | ||
217 | // file copy limit | 217 | // file copy limit |
218 | else if (strncmp(ptr, "file-copy-limit ", 16) == 0) { | 218 | else if (strncmp(ptr, "file-copy-limit ", 16) == 0) |
219 | if (setenv("FIREJAIL_FILE_COPY_LIMIT", ptr + 16, 1) == -1) | 219 | env_store_name_val("FIREJAIL_FILE_COPY_LIMIT", ptr + 16, SETENV); |
220 | errExit("setenv"); | ||
221 | } | ||
222 | 220 | ||
223 | // timeout for join option | 221 | // timeout for join option |
224 | else if (strncmp(ptr, "join-timeout ", 13) == 0) | 222 | else if (strncmp(ptr, "join-timeout ", 13) == 0) |
diff --git a/src/firejail/chroot.c b/src/firejail/chroot.c index cfa32d1d3..9253490ca 100644 --- a/src/firejail/chroot.c +++ b/src/firejail/chroot.c | |||
@@ -173,9 +173,21 @@ void fs_chroot(const char *rootdir) { | |||
173 | 173 | ||
174 | // x11 | 174 | // x11 |
175 | // if users want this mount, they should set FIREJAIL_CHROOT_X11 | 175 | // if users want this mount, they should set FIREJAIL_CHROOT_X11 |
176 | if (getenv("FIREJAIL_X11") || getenv("FIREJAIL_CHROOT_X11")) { | 176 | if (env_get("FIREJAIL_X11") || env_get("FIREJAIL_CHROOT_X11")) { |
177 | if (arg_debug) | 177 | if (arg_debug) |
178 | printf("Mounting /tmp/.X11-unix on chroot /tmp/.X11-unix\n"); | 178 | printf("Mounting /tmp/.X11-unix on chroot /tmp/.X11-unix\n"); |
179 | struct stat s1, s2; | ||
180 | if (stat("/tmp", &s1) || lstat("/tmp/.X11-unix", &s2)) | ||
181 | errExit("mounting /tmp/.X11-unix"); | ||
182 | if ((s1.st_mode & S_ISVTX) != S_ISVTX) { | ||
183 | fprintf(stderr, "Error: sticky bit not set on /tmp directory\n"); | ||
184 | exit(1); | ||
185 | } | ||
186 | if (s2.st_uid != 0) { | ||
187 | fprintf(stderr, "Error: /tmp/.X11-unix not owned by root user\n"); | ||
188 | exit(1); | ||
189 | } | ||
190 | |||
179 | check_subdir(parentfd, "tmp/.X11-unix", 0); | 191 | check_subdir(parentfd, "tmp/.X11-unix", 0); |
180 | fd = openat(parentfd, "tmp/.X11-unix", O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 192 | fd = openat(parentfd, "tmp/.X11-unix", O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
181 | if (fd == -1) | 193 | if (fd == -1) |
@@ -194,7 +206,7 @@ void fs_chroot(const char *rootdir) { | |||
194 | check_subdir(parentfd, "run", 1); | 206 | check_subdir(parentfd, "run", 1); |
195 | 207 | ||
196 | // pulseaudio; only support for default directory /run/user/$UID/pulse | 208 | // pulseaudio; only support for default directory /run/user/$UID/pulse |
197 | if (getenv("FIREJAIL_CHROOT_PULSE")) { | 209 | if (env_get("FIREJAIL_CHROOT_PULSE")) { |
198 | char *pulse; | 210 | char *pulse; |
199 | if (asprintf(&pulse, "%s/run/user/%d/pulse", cfg.chrootdir, getuid()) == -1) | 211 | if (asprintf(&pulse, "%s/run/user/%d/pulse", cfg.chrootdir, getuid()) == -1) |
200 | errExit("asprintf"); | 212 | errExit("asprintf"); |
diff --git a/src/firejail/dbus.c b/src/firejail/dbus.c index 3cf75ed84..1d0f07089 100644 --- a/src/firejail/dbus.c +++ b/src/firejail/dbus.c | |||
@@ -329,7 +329,7 @@ void dbus_proxy_start(void) { | |||
329 | errExit("close"); | 329 | errExit("close"); |
330 | 330 | ||
331 | if (arg_dbus_user == DBUS_POLICY_FILTER) { | 331 | if (arg_dbus_user == DBUS_POLICY_FILTER) { |
332 | char *user_env = getenv(DBUS_SESSION_BUS_ADDRESS_ENV); | 332 | const char *user_env = env_get(DBUS_SESSION_BUS_ADDRESS_ENV); |
333 | if (user_env == NULL) { | 333 | if (user_env == NULL) { |
334 | char *dbus_user_socket = find_user_socket(); | 334 | char *dbus_user_socket = find_user_socket(); |
335 | write_arg(args_pipe[1], DBUS_SOCKET_PATH_PREFIX "%s", | 335 | write_arg(args_pipe[1], DBUS_SOCKET_PATH_PREFIX "%s", |
@@ -350,7 +350,7 @@ void dbus_proxy_start(void) { | |||
350 | } | 350 | } |
351 | 351 | ||
352 | if (arg_dbus_system == DBUS_POLICY_FILTER) { | 352 | if (arg_dbus_system == DBUS_POLICY_FILTER) { |
353 | char *system_env = getenv(DBUS_SYSTEM_BUS_ADDRESS_ENV); | 353 | const char *system_env = env_get(DBUS_SYSTEM_BUS_ADDRESS_ENV); |
354 | if (system_env == NULL) { | 354 | if (system_env == NULL) { |
355 | write_arg(args_pipe[1], | 355 | write_arg(args_pipe[1], |
356 | DBUS_SOCKET_PATH_PREFIX DBUS_SYSTEM_SOCKET); | 356 | DBUS_SOCKET_PATH_PREFIX DBUS_SYSTEM_SOCKET); |
@@ -435,8 +435,8 @@ static void socket_overlay(char *socket_path, char *proxy_path) { | |||
435 | close(fd); | 435 | close(fd); |
436 | } | 436 | } |
437 | 437 | ||
438 | static char *get_socket_env(const char *name) { | 438 | static const char *get_socket_env(const char *name) { |
439 | char *value = getenv(name); | 439 | const char *value = env_get(name); |
440 | if (value == NULL) | 440 | if (value == NULL) |
441 | return NULL; | 441 | return NULL; |
442 | if (strncmp(value, DBUS_SOCKET_PATH_PREFIX, | 442 | if (strncmp(value, DBUS_SOCKET_PATH_PREFIX, |
@@ -446,21 +446,13 @@ static char *get_socket_env(const char *name) { | |||
446 | } | 446 | } |
447 | 447 | ||
448 | void dbus_set_session_bus_env(void) { | 448 | void dbus_set_session_bus_env(void) { |
449 | if (setenv(DBUS_SESSION_BUS_ADDRESS_ENV, | 449 | env_store_name_val(DBUS_SESSION_BUS_ADDRESS_ENV, |
450 | DBUS_SOCKET_PATH_PREFIX RUN_DBUS_USER_SOCKET, 1) == -1) { | 450 | DBUS_SOCKET_PATH_PREFIX RUN_DBUS_USER_SOCKET, SETENV); |
451 | fprintf(stderr, "Error: cannot modify " DBUS_SESSION_BUS_ADDRESS_ENV | ||
452 | " required by --dbus-user\n"); | ||
453 | exit(1); | ||
454 | } | ||
455 | } | 451 | } |
456 | 452 | ||
457 | void dbus_set_system_bus_env(void) { | 453 | void dbus_set_system_bus_env(void) { |
458 | if (setenv(DBUS_SYSTEM_BUS_ADDRESS_ENV, | 454 | env_store_name_val(DBUS_SYSTEM_BUS_ADDRESS_ENV, |
459 | DBUS_SOCKET_PATH_PREFIX RUN_DBUS_SYSTEM_SOCKET, 1) == -1) { | 455 | DBUS_SOCKET_PATH_PREFIX RUN_DBUS_SYSTEM_SOCKET, SETENV); |
460 | fprintf(stderr, "Error: cannot modify " DBUS_SYSTEM_BUS_ADDRESS_ENV | ||
461 | " required by --dbus-system\n"); | ||
462 | exit(1); | ||
463 | } | ||
464 | } | 456 | } |
465 | 457 | ||
466 | static void disable_socket_dir(void) { | 458 | static void disable_socket_dir(void) { |
@@ -506,7 +498,7 @@ void dbus_apply_policy(void) { | |||
506 | errExit("asprintf"); | 498 | errExit("asprintf"); |
507 | disable_file_or_dir(dbus_user_socket2); | 499 | disable_file_or_dir(dbus_user_socket2); |
508 | 500 | ||
509 | char *user_env = get_socket_env(DBUS_SESSION_BUS_ADDRESS_ENV); | 501 | const char *user_env = get_socket_env(DBUS_SESSION_BUS_ADDRESS_ENV); |
510 | if (user_env != NULL && strcmp(user_env, dbus_user_socket) != 0 && | 502 | if (user_env != NULL && strcmp(user_env, dbus_user_socket) != 0 && |
511 | strcmp(user_env, dbus_user_socket2) != 0) | 503 | strcmp(user_env, dbus_user_socket2) != 0) |
512 | disable_file_or_dir(user_env); | 504 | disable_file_or_dir(user_env); |
@@ -535,7 +527,7 @@ void dbus_apply_policy(void) { | |||
535 | 527 | ||
536 | disable_file_or_dir(DBUS_SYSTEM_SOCKET); | 528 | disable_file_or_dir(DBUS_SYSTEM_SOCKET); |
537 | 529 | ||
538 | char *system_env = get_socket_env(DBUS_SYSTEM_BUS_ADDRESS_ENV); | 530 | const char *system_env = get_socket_env(DBUS_SYSTEM_BUS_ADDRESS_ENV); |
539 | if (system_env != NULL && strcmp(system_env, DBUS_SYSTEM_SOCKET) != 0) | 531 | if (system_env != NULL && strcmp(system_env, DBUS_SYSTEM_SOCKET) != 0) |
540 | disable_file_or_dir(system_env); | 532 | disable_file_or_dir(system_env); |
541 | 533 | ||
@@ -561,4 +553,4 @@ void dbus_apply_policy(void) { | |||
561 | 553 | ||
562 | fwarning("An abstract unix socket for session D-BUS might still be available. Use --net or remove unix from --protocol set.\n"); | 554 | fwarning("An abstract unix socket for session D-BUS might still be available. Use --net or remove unix from --protocol set.\n"); |
563 | } | 555 | } |
564 | #endif // HAVE_DBUSPROXY \ No newline at end of file | 556 | #endif // HAVE_DBUSPROXY |
diff --git a/src/firejail/env.c b/src/firejail/env.c index d74cebb39..9ee6c6bfb 100644 --- a/src/firejail/env.c +++ b/src/firejail/env.c | |||
@@ -25,8 +25,8 @@ | |||
25 | 25 | ||
26 | typedef struct env_t { | 26 | typedef struct env_t { |
27 | struct env_t *next; | 27 | struct env_t *next; |
28 | char *name; | 28 | const char *name; |
29 | char *value; | 29 | const char *value; |
30 | ENV_OP op; | 30 | ENV_OP op; |
31 | } Env; | 31 | } Env; |
32 | static Env *envlist = NULL; | 32 | static Env *envlist = NULL; |
@@ -117,45 +117,35 @@ void env_ibus_load(void) { | |||
117 | // default sandbox env variables | 117 | // default sandbox env variables |
118 | void env_defaults(void) { | 118 | void env_defaults(void) { |
119 | // Qt fixes | 119 | // Qt fixes |
120 | if (setenv("QT_X11_NO_MITSHM", "1", 1) < 0) | 120 | env_store_name_val("QT_X11_NO_MITSHM", "1", SETENV); |
121 | errExit("setenv"); | 121 | env_store_name_val("QML_DISABLE_DISK_CACHE", "1", SETENV); |
122 | if (setenv("QML_DISABLE_DISK_CACHE", "1", 1) < 0) | 122 | // env_store_name_val("QTWEBENGINE_DISABLE_SANDBOX", "1", SETENV); |
123 | errExit("setenv"); | 123 | // env_store_name_val("MOZ_NO_REMOTE, "1", SETENV); |
124 | // if (setenv("QTWEBENGINE_DISABLE_SANDBOX", "1", 1) < 0) | 124 | env_store_name_val("container", "firejail", SETENV); // LXC sets container=lxc, |
125 | // errExit("setenv"); | ||
126 | // if (setenv("MOZ_NO_REMOTE, "1", 1) < 0) | ||
127 | // errExit("setenv"); | ||
128 | if (setenv("container", "firejail", 1) < 0) // LXC sets container=lxc, | ||
129 | errExit("setenv"); | ||
130 | if (!cfg.shell) | 125 | if (!cfg.shell) |
131 | cfg.shell = guess_shell(); | 126 | cfg.shell = guess_shell(); |
132 | if (cfg.shell && setenv("SHELL", cfg.shell, 1) < 0) | 127 | if (cfg.shell) |
133 | errExit("setenv"); | 128 | env_store_name_val("SHELL", cfg.shell, SETENV); |
134 | 129 | ||
135 | // spawn KIO slaves inside the sandbox | 130 | // spawn KIO slaves inside the sandbox |
136 | if (setenv("KDE_FORK_SLAVES", "1", 1) < 0) | 131 | env_store_name_val("KDE_FORK_SLAVES", "1", SETENV); |
137 | errExit("setenv"); | ||
138 | 132 | ||
139 | // set prompt color to green | 133 | // set prompt color to green |
140 | int set_prompt = 0; | 134 | int set_prompt = 0; |
141 | if (checkcfg(CFG_FIREJAIL_PROMPT)) | 135 | if (checkcfg(CFG_FIREJAIL_PROMPT)) |
142 | set_prompt = 1; | 136 | set_prompt = 1; |
143 | else { // check FIREJAIL_PROMPT="yes" environment variable | 137 | else { // check FIREJAIL_PROMPT="yes" environment variable |
144 | char *prompt = getenv("FIREJAIL_PROMPT"); | 138 | const char *prompt = env_get("FIREJAIL_PROMPT"); |
145 | if (prompt && strcmp(prompt, "yes") == 0) | 139 | if (prompt && strcmp(prompt, "yes") == 0) |
146 | set_prompt = 1; | 140 | set_prompt = 1; |
147 | } | 141 | } |
148 | 142 | ||
149 | if (set_prompt) { | 143 | if (set_prompt) |
150 | //export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' | 144 | //export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' |
151 | if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0) | 145 | env_store_name_val("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", SETENV); |
152 | errExit("setenv"); | 146 | else |
153 | } | ||
154 | else { | ||
155 | // remove PROMPT_COMMAND | 147 | // remove PROMPT_COMMAND |
156 | if (setenv("PROMPT_COMMAND", ":", 1) < 0) // unsetenv() will not work here, bash still picks it up from somewhere | 148 | env_store_name_val("PROMPT_COMMAND", ":", SETENV); // unsetenv() will not work here, bash still picks it up from somewhere |
157 | errExit("setenv"); | ||
158 | } | ||
159 | 149 | ||
160 | // set the window title | 150 | // set the window title |
161 | if (!arg_quiet && isatty(STDOUT_FILENO)) | 151 | if (!arg_quiet && isatty(STDOUT_FILENO)) |
@@ -163,14 +153,13 @@ void env_defaults(void) { | |||
163 | 153 | ||
164 | // pass --quiet as an environment variable, in case the command calls further firejailed commands | 154 | // pass --quiet as an environment variable, in case the command calls further firejailed commands |
165 | if (arg_quiet) | 155 | if (arg_quiet) |
166 | setenv("FIREJAIL_QUIET", "yes", 1); | 156 | env_store_name_val("FIREJAIL_QUIET", "yes", SETENV); |
167 | 157 | ||
168 | fflush(0); | 158 | fflush(0); |
169 | } | 159 | } |
170 | 160 | ||
171 | // parse and store the environment setting | 161 | // parse and store the environment setting |
172 | void env_store(const char *str, ENV_OP op) { | 162 | void env_store(const char *str, ENV_OP op) { |
173 | EUID_ASSERT(); | ||
174 | assert(str); | 163 | assert(str); |
175 | 164 | ||
176 | // some basic checking | 165 | // some basic checking |
@@ -181,8 +170,7 @@ void env_store(const char *str, ENV_OP op) { | |||
181 | if (!ptr) | 170 | if (!ptr) |
182 | goto errexit; | 171 | goto errexit; |
183 | ptr++; | 172 | ptr++; |
184 | if (*ptr == '\0') | 173 | op = SETENV; |
185 | goto errexit; | ||
186 | } | 174 | } |
187 | 175 | ||
188 | // build list entry | 176 | // build list entry |
@@ -210,8 +198,40 @@ errexit: | |||
210 | exit(1); | 198 | exit(1); |
211 | } | 199 | } |
212 | 200 | ||
201 | void env_store_name_val(const char *name, const char *val, ENV_OP op) { | ||
202 | assert(name); | ||
203 | |||
204 | // some basic checking | ||
205 | if (*name == '\0') | ||
206 | goto errexit; | ||
207 | |||
208 | // build list entry | ||
209 | Env *env = calloc(1, sizeof(Env)); | ||
210 | if (!env) | ||
211 | errExit("calloc"); | ||
212 | |||
213 | env->name = strdup(name); | ||
214 | if (env->name == NULL) | ||
215 | errExit("strdup"); | ||
216 | |||
217 | if (op == SETENV) { | ||
218 | env->value = strdup(val); | ||
219 | if (env->value == NULL) | ||
220 | errExit("strdup"); | ||
221 | } | ||
222 | env->op = op; | ||
223 | |||
224 | // add entry to the list | ||
225 | env_add(env); | ||
226 | return; | ||
227 | |||
228 | errexit: | ||
229 | fprintf(stderr, "Error: invalid --env setting\n"); | ||
230 | exit(1); | ||
231 | } | ||
232 | |||
213 | // set env variables in the new sandbox process | 233 | // set env variables in the new sandbox process |
214 | void env_apply(void) { | 234 | void env_apply_all(void) { |
215 | Env *env = envlist; | 235 | Env *env = envlist; |
216 | 236 | ||
217 | while (env) { | 237 | while (env) { |
@@ -225,3 +245,81 @@ void env_apply(void) { | |||
225 | env = env->next; | 245 | env = env->next; |
226 | } | 246 | } |
227 | } | 247 | } |
248 | |||
249 | // get env variable | ||
250 | const char *env_get(const char *name) { | ||
251 | Env *env = envlist; | ||
252 | const char *r = NULL; | ||
253 | |||
254 | while (env) { | ||
255 | if (strcmp(env->name, name) == 0) { | ||
256 | if (env->op == SETENV) | ||
257 | r = env->value; | ||
258 | else if (env->op == RMENV) | ||
259 | r = NULL; | ||
260 | } | ||
261 | env = env->next; | ||
262 | } | ||
263 | return r; | ||
264 | } | ||
265 | |||
266 | static const char * const env_whitelist[] = { | ||
267 | "LANG", | ||
268 | "LANGUAGE", | ||
269 | "LC_MESSAGES", | ||
270 | "PATH", | ||
271 | "DISPLAY" // required by X11 | ||
272 | }; | ||
273 | |||
274 | static const char * const env_whitelist_sbox[] = { | ||
275 | "FIREJAIL_DEBUG", | ||
276 | "FIREJAIL_FILE_COPY_LIMIT", | ||
277 | "FIREJAIL_PLUGIN", | ||
278 | "FIREJAIL_QUIET", | ||
279 | "FIREJAIL_SECCOMP_ERROR_ACTION", | ||
280 | "FIREJAIL_TEST_ARGUMENTS", | ||
281 | "FIREJAIL_TRACEFILE" | ||
282 | }; | ||
283 | |||
284 | static void env_apply_list(const char * const *list, unsigned int num_items) { | ||
285 | Env *env = envlist; | ||
286 | |||
287 | while (env) { | ||
288 | if (env->op == SETENV) { | ||
289 | for (unsigned int i = 0; i < num_items; i++) | ||
290 | if (strcmp(env->name, list[i]) == 0) { | ||
291 | // sanity check for whitelisted environment variables | ||
292 | if (strlen(env->name) + strlen(env->value) >= MAX_ENV_LEN) { | ||
293 | fprintf(stderr, "Error: too long environment variable %s, please use --rmenv\n", env->name); | ||
294 | exit(1); | ||
295 | } | ||
296 | |||
297 | //fprintf(stderr, "whitelisted env var %s=%s\n", env->name, env->value); | ||
298 | if (setenv(env->name, env->value, 1) < 0) | ||
299 | errExit("setenv"); | ||
300 | break; | ||
301 | } | ||
302 | } else if (env->op == RMENV) | ||
303 | unsetenv(env->name); | ||
304 | |||
305 | env = env->next; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | // Filter env variables in main firejail process. All variables will | ||
310 | // be reapplied for the sandboxed app by env_apply_all(). | ||
311 | void env_apply_whitelist(void) { | ||
312 | int r; | ||
313 | |||
314 | r = clearenv(); | ||
315 | if (r != 0) | ||
316 | errExit("clearenv"); | ||
317 | |||
318 | env_apply_list(env_whitelist, ARRAY_SIZE(env_whitelist)); | ||
319 | } | ||
320 | |||
321 | // Filter env variables for a sbox app | ||
322 | void env_apply_whitelist_sbox(void) { | ||
323 | env_apply_whitelist(); | ||
324 | env_apply_list(env_whitelist_sbox, ARRAY_SIZE(env_whitelist_sbox)); | ||
325 | } | ||
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 80987e494..e352dadc4 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -81,6 +81,8 @@ | |||
81 | (void) rv;\ | 81 | (void) rv;\ |
82 | } while (0) | 82 | } while (0) |
83 | 83 | ||
84 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
85 | |||
84 | // main.c | 86 | // main.c |
85 | typedef struct bridge_t { | 87 | typedef struct bridge_t { |
86 | // on the host | 88 | // on the host |
@@ -513,7 +515,6 @@ void check_private_dir(void); | |||
513 | void update_map(char *mapping, char *map_file); | 515 | void update_map(char *mapping, char *map_file); |
514 | void wait_for_other(int fd); | 516 | void wait_for_other(int fd); |
515 | void notify_other(int fd); | 517 | void notify_other(int fd); |
516 | const char *gnu_basename(const char *path); | ||
517 | uid_t pid_get_uid(pid_t pid); | 518 | uid_t pid_get_uid(pid_t pid); |
518 | uid_t get_group_id(const char *group); | 519 | uid_t get_group_id(const char *group); |
519 | int remove_overlay_directory(void); | 520 | int remove_overlay_directory(void); |
@@ -656,7 +657,7 @@ int check_kernel_procs(void); | |||
656 | void run_no_sandbox(int argc, char **argv) __attribute__((noreturn)); | 657 | void run_no_sandbox(int argc, char **argv) __attribute__((noreturn)); |
657 | 658 | ||
658 | #define MAX_ENVS 256 // some sane maximum number of environment variables | 659 | #define MAX_ENVS 256 // some sane maximum number of environment variables |
659 | #define MAX_ENV_LEN (PATH_MAX + 32) // FOOBAR=SOME_PATH | 660 | #define MAX_ENV_LEN (PATH_MAX + 32) // FOOBAR=SOME_PATH, only applied to Firejail's own sandboxed apps |
660 | // env.c | 661 | // env.c |
661 | typedef enum { | 662 | typedef enum { |
662 | SETENV = 0, | 663 | SETENV = 0, |
@@ -664,8 +665,12 @@ typedef enum { | |||
664 | } ENV_OP; | 665 | } ENV_OP; |
665 | 666 | ||
666 | void env_store(const char *str, ENV_OP op); | 667 | void env_store(const char *str, ENV_OP op); |
667 | void env_apply(void); | 668 | void env_store_name_val(const char *name, const char *val, ENV_OP op); |
669 | void env_apply_all(void); | ||
670 | void env_apply_whitelist(void); | ||
671 | void env_apply_whitelist_sbox(void); | ||
668 | void env_defaults(void); | 672 | void env_defaults(void); |
673 | const char *env_get(const char *name); | ||
669 | void env_ibus_load(void); | 674 | void env_ibus_load(void); |
670 | 675 | ||
671 | // fs_whitelist.c | 676 | // fs_whitelist.c |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 0d4e496e8..ef1f87f0c 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -487,27 +487,26 @@ void fs_tmpfs(const char *dir, unsigned check_owner) { | |||
487 | close(fd); | 487 | close(fd); |
488 | } | 488 | } |
489 | 489 | ||
490 | // remount path, but preserve existing mount flags; requires a resolved path | 490 | // remount path, preserving other mount flags; requires a resolved path |
491 | static void fs_remount_simple(const char *path, OPERATION op) { | 491 | static void fs_remount_simple(const char *path, OPERATION op) { |
492 | assert(path); | 492 | assert(path); |
493 | 493 | ||
494 | // open path without following symbolic links | 494 | // open path without following symbolic links |
495 | int fd = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC); | 495 | int fd1 = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC); |
496 | if (fd == -1) | 496 | if (fd1 == -1) |
497 | goto out; | 497 | goto out; |
498 | // identify file owner | 498 | struct stat s1; |
499 | struct stat s; | 499 | if (fstat(fd1, &s1) == -1) { |
500 | if (fstat(fd, &s) == -1) { | ||
501 | // fstat can fail with EACCES if path is a FUSE mount, | 500 | // fstat can fail with EACCES if path is a FUSE mount, |
502 | // mounted without 'allow_root' or 'allow_other' | 501 | // mounted without 'allow_root' or 'allow_other' |
503 | if (errno != EACCES) | 502 | if (errno != EACCES) |
504 | errExit("fstat"); | 503 | errExit("fstat"); |
505 | close(fd); | 504 | close(fd1); |
506 | goto out; | 505 | goto out; |
507 | } | 506 | } |
508 | // get mount flags | 507 | // get mount flags |
509 | struct statvfs buf; | 508 | struct statvfs buf; |
510 | if (fstatvfs(fd, &buf) == -1) | 509 | if (fstatvfs(fd1, &buf) == -1) |
511 | errExit("fstatvfs"); | 510 | errExit("fstatvfs"); |
512 | unsigned long flags = buf.f_flag; | 511 | unsigned long flags = buf.f_flag; |
513 | 512 | ||
@@ -515,13 +514,13 @@ static void fs_remount_simple(const char *path, OPERATION op) { | |||
515 | if (op == MOUNT_RDWR || op == MOUNT_RDWR_NOCHECK) { | 514 | if (op == MOUNT_RDWR || op == MOUNT_RDWR_NOCHECK) { |
516 | // nothing to do if there is no read-only flag | 515 | // nothing to do if there is no read-only flag |
517 | if ((flags & MS_RDONLY) == 0) { | 516 | if ((flags & MS_RDONLY) == 0) { |
518 | close(fd); | 517 | close(fd1); |
519 | return; | 518 | return; |
520 | } | 519 | } |
521 | // allow only user owned directories, except the user is root | 520 | // allow only user owned directories, except the user is root |
522 | if (op == MOUNT_RDWR && getuid() != 0 && s.st_uid != getuid()) { | 521 | if (op != MOUNT_RDWR_NOCHECK && getuid() != 0 && s1.st_uid != getuid()) { |
523 | fwarning("you are not allowed to change %s to read-write\n", path); | 522 | fwarning("you are not allowed to change %s to read-write\n", path); |
524 | close(fd); | 523 | close(fd1); |
525 | return; | 524 | return; |
526 | } | 525 | } |
527 | flags &= ~MS_RDONLY; | 526 | flags &= ~MS_RDONLY; |
@@ -530,7 +529,7 @@ static void fs_remount_simple(const char *path, OPERATION op) { | |||
530 | else if (op == MOUNT_NOEXEC) { | 529 | else if (op == MOUNT_NOEXEC) { |
531 | // nothing to do if path is mounted noexec already | 530 | // nothing to do if path is mounted noexec already |
532 | if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID)) { | 531 | if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID)) { |
533 | close(fd); | 532 | close(fd1); |
534 | return; | 533 | return; |
535 | } | 534 | } |
536 | flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID; | 535 | flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID; |
@@ -539,7 +538,7 @@ static void fs_remount_simple(const char *path, OPERATION op) { | |||
539 | else if (op == MOUNT_READONLY) { | 538 | else if (op == MOUNT_READONLY) { |
540 | // nothing to do if path is mounted read-only already | 539 | // nothing to do if path is mounted read-only already |
541 | if ((flags & MS_RDONLY) == MS_RDONLY) { | 540 | if ((flags & MS_RDONLY) == MS_RDONLY) { |
542 | close(fd); | 541 | close(fd1); |
543 | return; | 542 | return; |
544 | } | 543 | } |
545 | flags |= MS_RDONLY; | 544 | flags |= MS_RDONLY; |
@@ -549,21 +548,26 @@ static void fs_remount_simple(const char *path, OPERATION op) { | |||
549 | 548 | ||
550 | if (arg_debug) | 549 | if (arg_debug) |
551 | printf("Mounting %s %s\n", opstr[op], path); | 550 | printf("Mounting %s %s\n", opstr[op], path); |
552 | // mount --bind /bin /bin | 551 | // mount --bind path path |
553 | char *proc; | 552 | char *proc; |
554 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | 553 | if (asprintf(&proc, "/proc/self/fd/%d", fd1) == -1) |
555 | errExit("asprintf"); | 554 | errExit("asprintf"); |
556 | if (mount(proc, proc, NULL, MS_BIND|MS_REC, NULL) < 0) | 555 | if (mount(proc, proc, NULL, MS_BIND|MS_REC, NULL) < 0) |
557 | errExit("mount"); | 556 | errExit("mount"); |
558 | free(proc); | 557 | free(proc); |
559 | close(fd); | ||
560 | 558 | ||
561 | // mount --bind -o remount,ro /bin | 559 | // mount --bind -o remount,ro path |
562 | // we need to open path again | 560 | // need to open path again without following symbolic links |
563 | fd = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC); | 561 | int fd2 = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC); |
564 | if (fd == -1) | 562 | if (fd2 == -1) |
565 | errExit("open"); | 563 | errExit("open"); |
566 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | 564 | struct stat s2; |
565 | if (fstat(fd2, &s2) == -1) | ||
566 | errExit("fstat"); | ||
567 | // device and inode number should be the same | ||
568 | if (s1.st_dev != s2.st_dev || s1.st_ino != s2.st_ino) | ||
569 | errLogExit("invalid %s mount", opstr[op]); | ||
570 | if (asprintf(&proc, "/proc/self/fd/%d", fd2) == -1) | ||
567 | errExit("asprintf"); | 571 | errExit("asprintf"); |
568 | if (mount(NULL, proc, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0) | 572 | if (mount(NULL, proc, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0) |
569 | errExit("mount"); | 573 | errExit("mount"); |
@@ -579,7 +583,8 @@ static void fs_remount_simple(const char *path, OPERATION op) { | |||
579 | errLogExit("invalid %s mount", opstr[op]); | 583 | errLogExit("invalid %s mount", opstr[op]); |
580 | fs_logger2(opstr[op], path); | 584 | fs_logger2(opstr[op], path); |
581 | free(proc); | 585 | free(proc); |
582 | close(fd); | 586 | close(fd1); |
587 | close(fd2); | ||
583 | return; | 588 | return; |
584 | 589 | ||
585 | out: | 590 | out: |
@@ -795,6 +800,8 @@ void disable_config(void) { | |||
795 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_PROFILE_DIR); | 800 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_PROFILE_DIR); |
796 | if (stat(RUN_FIREJAIL_X11_DIR, &s) == 0) | 801 | if (stat(RUN_FIREJAIL_X11_DIR, &s) == 0) |
797 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_X11_DIR); | 802 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_X11_DIR); |
803 | if (!arg_appimage && stat(RUN_FIREJAIL_APPIMAGE_DIR, &s) == 0) | ||
804 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_APPIMAGE_DIR); | ||
798 | } | 805 | } |
799 | 806 | ||
800 | 807 | ||
@@ -1219,7 +1226,7 @@ void fs_private_tmp(void) { | |||
1219 | printf("Generate private-tmp whitelist commands\n"); | 1226 | printf("Generate private-tmp whitelist commands\n"); |
1220 | 1227 | ||
1221 | // check XAUTHORITY file, KDE keeps it under /tmp | 1228 | // check XAUTHORITY file, KDE keeps it under /tmp |
1222 | char *xauth = getenv("XAUTHORITY"); | 1229 | const char *xauth = env_get("XAUTHORITY"); |
1223 | if (xauth) { | 1230 | if (xauth) { |
1224 | char *rp = realpath(xauth, NULL); | 1231 | char *rp = realpath(xauth, NULL); |
1225 | if (rp && strncmp(rp, "/tmp/", 5) == 0) { | 1232 | if (rp && strncmp(rp, "/tmp/", 5) == 0) { |
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/fs_whitelist.c b/src/firejail/fs_whitelist.c index 1d7552339..d60c57fec 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c | |||
@@ -778,7 +778,7 @@ void fs_whitelist(void) { | |||
778 | fs_logger("tmpfs /tmp"); | 778 | fs_logger("tmpfs /tmp"); |
779 | 779 | ||
780 | // pam-tmpdir - issue #2685 | 780 | // pam-tmpdir - issue #2685 |
781 | char *env = getenv("TMP"); | 781 | const char *env = env_get("TMP"); |
782 | if (env) { | 782 | if (env) { |
783 | char *pamtmpdir; | 783 | char *pamtmpdir; |
784 | if (asprintf(&pamtmpdir, "/tmp/user/%u", getuid()) == -1) | 784 | if (asprintf(&pamtmpdir, "/tmp/user/%u", getuid()) == -1) |
diff --git a/src/firejail/join.c b/src/firejail/join.c index d2f802add..bdd0f286c 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c | |||
@@ -296,7 +296,7 @@ static void extract_umask(pid_t pid) { | |||
296 | fprintf(stderr, "Error: cannot open umask file\n"); | 296 | fprintf(stderr, "Error: cannot open umask file\n"); |
297 | exit(1); | 297 | exit(1); |
298 | } | 298 | } |
299 | if (fscanf(fp, "%o", &orig_umask) != 1) { | 299 | if (fscanf(fp, "%3o", &orig_umask) != 1) { |
300 | fprintf(stderr, "Error: cannot read umask\n"); | 300 | fprintf(stderr, "Error: cannot read umask\n"); |
301 | exit(1); | 301 | exit(1); |
302 | } | 302 | } |
@@ -335,7 +335,7 @@ bool is_ready_for_join(const pid_t pid) { | |||
335 | struct stat s; | 335 | struct stat s; |
336 | if (fstat(fd, &s) == -1) | 336 | if (fstat(fd, &s) == -1) |
337 | errExit("fstat"); | 337 | errExit("fstat"); |
338 | 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) { |
339 | close(fd); | 339 | close(fd); |
340 | return false; | 340 | return false; |
341 | } | 341 | } |
@@ -411,7 +411,7 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
411 | extract_x11_display(parent); | 411 | extract_x11_display(parent); |
412 | 412 | ||
413 | int shfd = -1; | 413 | int shfd = -1; |
414 | if (!arg_shell_none) | 414 | if (!arg_shell_none && !arg_audit) |
415 | shfd = open_shell(); | 415 | shfd = open_shell(); |
416 | 416 | ||
417 | EUID_ROOT(); | 417 | EUID_ROOT(); |
@@ -423,6 +423,7 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
423 | extract_cgroup(pid); | 423 | extract_cgroup(pid); |
424 | extract_nogroups(pid); | 424 | extract_nogroups(pid); |
425 | extract_user_namespace(pid); | 425 | extract_user_namespace(pid); |
426 | extract_umask(pid); | ||
426 | #ifdef HAVE_APPARMOR | 427 | #ifdef HAVE_APPARMOR |
427 | extract_apparmor(pid); | 428 | extract_apparmor(pid); |
428 | #endif | 429 | #endif |
@@ -432,9 +433,6 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
432 | if (cfg.cgroup) // not available for uid 0 | 433 | if (cfg.cgroup) // not available for uid 0 |
433 | set_cgroup(cfg.cgroup); | 434 | set_cgroup(cfg.cgroup); |
434 | 435 | ||
435 | // set umask, also uid 0 | ||
436 | extract_umask(pid); | ||
437 | |||
438 | // join namespaces | 436 | // join namespaces |
439 | if (arg_join_network) { | 437 | if (arg_join_network) { |
440 | if (join_namespace(pid, "net")) | 438 | if (join_namespace(pid, "net")) |
@@ -563,7 +561,7 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
563 | char *display_str; | 561 | char *display_str; |
564 | if (asprintf(&display_str, ":%d", display) == -1) | 562 | if (asprintf(&display_str, ":%d", display) == -1) |
565 | errExit("asprintf"); | 563 | errExit("asprintf"); |
566 | setenv("DISPLAY", display_str, 1); | 564 | env_store_name_val("DISPLAY", display_str, SETENV); |
567 | free(display_str); | 565 | free(display_str); |
568 | } | 566 | } |
569 | 567 | ||
diff --git a/src/firejail/main.c b/src/firejail/main.c index e5d8a4720..982a4c7a6 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -861,19 +861,20 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
861 | } | 861 | } |
862 | 862 | ||
863 | char *guess_shell(void) { | 863 | char *guess_shell(void) { |
864 | char *shell = NULL; | 864 | const char *shell; |
865 | char *retval; | ||
865 | struct stat s; | 866 | struct stat s; |
866 | 867 | ||
867 | shell = getenv("SHELL"); | 868 | shell = env_get("SHELL"); |
868 | if (shell) { | 869 | if (shell) { |
869 | invalid_filename(shell, 0); // no globbing | 870 | invalid_filename(shell, 0); // no globbing |
870 | if (!is_dir(shell) && strstr(shell, "..") == NULL && stat(shell, &s) == 0 && access(shell, X_OK) == 0 && | 871 | if (!is_dir(shell) && strstr(shell, "..") == NULL && stat(shell, &s) == 0 && access(shell, X_OK) == 0 && |
871 | strcmp(shell, PATH_FIREJAIL) != 0) | 872 | strcmp(shell, PATH_FIREJAIL) != 0) |
872 | return shell; | 873 | goto found; |
873 | } | 874 | } |
874 | 875 | ||
875 | // shells in order of preference | 876 | // shells in order of preference |
876 | char *shells[] = {"/bin/bash", "/bin/csh", "/usr/bin/zsh", "/bin/sh", "/bin/ash", NULL }; | 877 | static const char * const shells[] = {"/bin/bash", "/bin/csh", "/usr/bin/zsh", "/bin/sh", "/bin/ash", NULL }; |
877 | 878 | ||
878 | int i = 0; | 879 | int i = 0; |
879 | while (shells[i] != NULL) { | 880 | while (shells[i] != NULL) { |
@@ -884,8 +885,11 @@ char *guess_shell(void) { | |||
884 | } | 885 | } |
885 | i++; | 886 | i++; |
886 | } | 887 | } |
887 | 888 | found: | |
888 | return shell; | 889 | retval = strdup(shell); |
890 | if (!retval) | ||
891 | errExit("strdup"); | ||
892 | return retval; | ||
889 | } | 893 | } |
890 | 894 | ||
891 | // return argument index | 895 | // return argument index |
@@ -926,9 +930,13 @@ static void run_builder(int argc, char **argv) { | |||
926 | if (setresuid(-1, getuid(), getuid()) != 0) | 930 | if (setresuid(-1, getuid(), getuid()) != 0) |
927 | errExit("setresuid"); | 931 | errExit("setresuid"); |
928 | 932 | ||
933 | assert(env_get("LD_PRELOAD") == NULL); | ||
929 | assert(getenv("LD_PRELOAD") == NULL); | 934 | assert(getenv("LD_PRELOAD") == NULL); |
930 | umask(orig_umask); | 935 | umask(orig_umask); |
931 | 936 | ||
937 | // restore some environment variables | ||
938 | env_apply_whitelist_sbox(); | ||
939 | |||
932 | argv[0] = LIBDIR "/firejail/fbuilder"; | 940 | argv[0] = LIBDIR "/firejail/fbuilder"; |
933 | execvp(argv[0], argv); | 941 | execvp(argv[0], argv); |
934 | 942 | ||
@@ -994,6 +1002,16 @@ int main(int argc, char **argv, char **envp) { | |||
994 | exit(1); | 1002 | exit(1); |
995 | } | 1003 | } |
996 | 1004 | ||
1005 | // Stash environment variables | ||
1006 | for (i = 0, ptr = envp; ptr && *ptr && i < MAX_ENVS; i++, ptr++) | ||
1007 | env_store(*ptr, SETENV); | ||
1008 | |||
1009 | // sanity check for environment variables | ||
1010 | if (i >= MAX_ENVS) { | ||
1011 | fprintf(stderr, "Error: too many environment variables, please use --rmenv\n"); | ||
1012 | exit(1); | ||
1013 | } | ||
1014 | |||
997 | // sanity check for arguments | 1015 | // sanity check for arguments |
998 | for (i = 0; i < argc; i++) { | 1016 | for (i = 0; i < argc; i++) { |
999 | if (*argv[i] == 0) { | 1017 | if (*argv[i] == 0) { |
@@ -1005,29 +1023,19 @@ int main(int argc, char **argv, char **envp) { | |||
1005 | exit(1); | 1023 | exit(1); |
1006 | } | 1024 | } |
1007 | // Also remove requested environment variables | 1025 | // Also remove requested environment variables |
1008 | // entirely to avoid tripping the length check below | ||
1009 | if (strncmp(argv[i], "--rmenv=", 8) == 0) | 1026 | if (strncmp(argv[i], "--rmenv=", 8) == 0) |
1010 | unsetenv(argv[i] + 8); | 1027 | env_store(argv[i] + 8, RMENV); |
1011 | } | 1028 | } |
1012 | 1029 | ||
1013 | // sanity check for environment variables | 1030 | // Reapply a minimal set of environment variables |
1014 | for (i = 0, ptr = envp; ptr && *ptr && i < MAX_ENVS; i++, ptr++) { | 1031 | env_apply_whitelist(); |
1015 | if (strlen(*ptr) >= MAX_ENV_LEN) { | ||
1016 | fprintf(stderr, "Error: too long environment variables, please use --rmenv\n"); | ||
1017 | exit(1); | ||
1018 | } | ||
1019 | } | ||
1020 | if (i >= MAX_ENVS) { | ||
1021 | fprintf(stderr, "Error: too many environment variables, please use --rmenv\n"); | ||
1022 | exit(1); | ||
1023 | } | ||
1024 | 1032 | ||
1025 | // check if the user is allowed to use firejail | 1033 | // check if the user is allowed to use firejail |
1026 | init_cfg(argc, argv); | 1034 | init_cfg(argc, argv); |
1027 | 1035 | ||
1028 | // get starting timestamp, process --quiet | 1036 | // get starting timestamp, process --quiet |
1029 | timetrace_start(); | 1037 | timetrace_start(); |
1030 | char *env_quiet = getenv("FIREJAIL_QUIET"); | 1038 | const char *env_quiet = env_get("FIREJAIL_QUIET"); |
1031 | if (check_arg(argc, argv, "--quiet", 1) || (env_quiet && strcmp(env_quiet, "yes") == 0)) | 1039 | if (check_arg(argc, argv, "--quiet", 1) || (env_quiet && strcmp(env_quiet, "yes") == 0)) |
1032 | arg_quiet = 1; | 1040 | arg_quiet = 1; |
1033 | 1041 | ||
@@ -1037,7 +1045,7 @@ int main(int argc, char **argv, char **envp) { | |||
1037 | 1045 | ||
1038 | // build /run/firejail directory structure | 1046 | // build /run/firejail directory structure |
1039 | preproc_build_firejail_dir(); | 1047 | preproc_build_firejail_dir(); |
1040 | char *container_name = getenv("container"); | 1048 | const char *container_name = env_get("container"); |
1041 | if (!container_name || strcmp(container_name, "firejail")) { | 1049 | if (!container_name || strcmp(container_name, "firejail")) { |
1042 | lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); | 1050 | lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); |
1043 | if (lockfd_directory != -1) { | 1051 | if (lockfd_directory != -1) { |
@@ -1170,6 +1178,9 @@ int main(int argc, char **argv, char **envp) { | |||
1170 | 1178 | ||
1171 | drop_privs(1); | 1179 | drop_privs(1); |
1172 | umask(orig_umask); | 1180 | umask(orig_umask); |
1181 | |||
1182 | // restore original environment variables | ||
1183 | env_apply_all(); | ||
1173 | int rv = system(argv[2]); | 1184 | int rv = system(argv[2]); |
1174 | exit(rv); | 1185 | exit(rv); |
1175 | } | 1186 | } |
@@ -1231,11 +1242,6 @@ int main(int argc, char **argv, char **envp) { | |||
1231 | } | 1242 | } |
1232 | EUID_ASSERT(); | 1243 | EUID_ASSERT(); |
1233 | 1244 | ||
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 | 1245 | // check for force-nonewprivs in /etc/firejail/firejail.config file |
1240 | if (checkcfg(CFG_FORCE_NONEWPRIVS)) | 1246 | if (checkcfg(CFG_FORCE_NONEWPRIVS)) |
1241 | arg_nonewprivs = 1; | 1247 | arg_nonewprivs = 1; |
diff --git a/src/firejail/no_sandbox.c b/src/firejail/no_sandbox.c index 6c7803602..111d94333 100644 --- a/src/firejail/no_sandbox.c +++ b/src/firejail/no_sandbox.c | |||
@@ -41,7 +41,7 @@ int check_namespace_virt(void) { | |||
41 | EUID_ASSERT(); | 41 | EUID_ASSERT(); |
42 | 42 | ||
43 | // check container environment variable | 43 | // check container environment variable |
44 | char *str = getenv("container"); | 44 | const char *str = env_get("container"); |
45 | if (str && is_container(str)) | 45 | if (str && is_container(str)) |
46 | return 1; | 46 | return 1; |
47 | 47 | ||
diff --git a/src/firejail/output.c b/src/firejail/output.c index 36cb905cb..1682ee025 100644 --- a/src/firejail/output.c +++ b/src/firejail/output.c | |||
@@ -95,6 +95,9 @@ void check_output(int argc, char **argv) { | |||
95 | close(pipefd[0]); | 95 | close(pipefd[0]); |
96 | } | 96 | } |
97 | 97 | ||
98 | // restore some environment variables | ||
99 | env_apply_whitelist_sbox(); | ||
100 | |||
98 | char *args[3]; | 101 | char *args[3]; |
99 | args[0] = LIBDIR "/firejail/ftee"; | 102 | args[0] = LIBDIR "/firejail/ftee"; |
100 | args[1] = outfile; | 103 | args[1] = outfile; |
@@ -137,6 +140,10 @@ void check_output(int argc, char **argv) { | |||
137 | } | 140 | } |
138 | args[j++] = argv[i]; | 141 | args[j++] = argv[i]; |
139 | } | 142 | } |
143 | |||
144 | // restore original environment variables | ||
145 | env_apply_all(); | ||
146 | |||
140 | execvp(args[0], args); | 147 | execvp(args[0], args); |
141 | 148 | ||
142 | perror("execvp"); | 149 | perror("execvp"); |
diff --git a/src/firejail/paths.c b/src/firejail/paths.c index 5de704bef..981a6bc71 100644 --- a/src/firejail/paths.c +++ b/src/firejail/paths.c | |||
@@ -26,13 +26,13 @@ static unsigned int longest_path_elt = 0; | |||
26 | 26 | ||
27 | static char *elt = NULL; // moved from inside init_paths in order to get rid of scan-build warning | 27 | static char *elt = NULL; // moved from inside init_paths in order to get rid of scan-build warning |
28 | static void init_paths(void) { | 28 | static void init_paths(void) { |
29 | char *path = getenv("PATH"); | 29 | const char *env_path = env_get("PATH"); |
30 | char *p; | 30 | char *p; |
31 | if (!path) { | 31 | if (!env_path) { |
32 | path = "/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"; | 32 | env_path = "/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"; |
33 | setenv("PATH", path, 1); | 33 | env_store_name_val("PATH", env_path, SETENV); |
34 | } | 34 | } |
35 | path = strdup(path); | 35 | char *path = strdup(env_path); |
36 | if (!path) | 36 | if (!path) |
37 | errExit("strdup"); | 37 | errExit("strdup"); |
38 | 38 | ||
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 1ee8cdfcb..3766ba8f0 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -158,7 +158,7 @@ static int check_nosound(void) { | |||
158 | } | 158 | } |
159 | 159 | ||
160 | static int check_x11(void) { | 160 | static int check_x11(void) { |
161 | return (arg_x11_block || arg_x11_xorg || getenv("FIREJAIL_X11")); | 161 | return (arg_x11_block || arg_x11_xorg || env_get("FIREJAIL_X11")); |
162 | } | 162 | } |
163 | 163 | ||
164 | static int check_disable_u2f(void) { | 164 | static int check_disable_u2f(void) { |
@@ -1181,7 +1181,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1181 | if (strcmp(ptr, "x11 xephyr") == 0) { | 1181 | if (strcmp(ptr, "x11 xephyr") == 0) { |
1182 | #ifdef HAVE_X11 | 1182 | #ifdef HAVE_X11 |
1183 | if (checkcfg(CFG_X11)) { | 1183 | if (checkcfg(CFG_X11)) { |
1184 | char *x11env = getenv("FIREJAIL_X11"); | 1184 | const char *x11env = env_get("FIREJAIL_X11"); |
1185 | if (x11env && strcmp(x11env, "yes") == 0) { | 1185 | if (x11env && strcmp(x11env, "yes") == 0) { |
1186 | return 0; | 1186 | return 0; |
1187 | } | 1187 | } |
@@ -1210,7 +1210,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1210 | if (strcmp(ptr, "x11 xpra") == 0) { | 1210 | if (strcmp(ptr, "x11 xpra") == 0) { |
1211 | #ifdef HAVE_X11 | 1211 | #ifdef HAVE_X11 |
1212 | if (checkcfg(CFG_X11)) { | 1212 | if (checkcfg(CFG_X11)) { |
1213 | char *x11env = getenv("FIREJAIL_X11"); | 1213 | const char *x11env = env_get("FIREJAIL_X11"); |
1214 | if (x11env && strcmp(x11env, "yes") == 0) { | 1214 | if (x11env && strcmp(x11env, "yes") == 0) { |
1215 | return 0; | 1215 | return 0; |
1216 | } | 1216 | } |
@@ -1229,7 +1229,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1229 | if (strcmp(ptr, "x11 xvfb") == 0) { | 1229 | if (strcmp(ptr, "x11 xvfb") == 0) { |
1230 | #ifdef HAVE_X11 | 1230 | #ifdef HAVE_X11 |
1231 | if (checkcfg(CFG_X11)) { | 1231 | if (checkcfg(CFG_X11)) { |
1232 | char *x11env = getenv("FIREJAIL_X11"); | 1232 | const char *x11env = env_get("FIREJAIL_X11"); |
1233 | if (x11env && strcmp(x11env, "yes") == 0) { | 1233 | if (x11env && strcmp(x11env, "yes") == 0) { |
1234 | return 0; | 1234 | return 0; |
1235 | } | 1235 | } |
@@ -1248,7 +1248,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1248 | if (strcmp(ptr, "x11") == 0) { | 1248 | if (strcmp(ptr, "x11") == 0) { |
1249 | #ifdef HAVE_X11 | 1249 | #ifdef HAVE_X11 |
1250 | if (checkcfg(CFG_X11)) { | 1250 | if (checkcfg(CFG_X11)) { |
1251 | char *x11env = getenv("FIREJAIL_X11"); | 1251 | const char *x11env = env_get("FIREJAIL_X11"); |
1252 | if (x11env && strcmp(x11env, "yes") == 0) { | 1252 | if (x11env && strcmp(x11env, "yes") == 0) { |
1253 | return 0; | 1253 | return 0; |
1254 | } | 1254 | } |
diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c index a5c924a70..5df3d9cd3 100644 --- a/src/firejail/pulseaudio.c +++ b/src/firejail/pulseaudio.c | |||
@@ -42,7 +42,7 @@ void pulseaudio_disable(void) { | |||
42 | 42 | ||
43 | 43 | ||
44 | // blacklist pulseaudio socket in XDG_RUNTIME_DIR | 44 | // blacklist pulseaudio socket in XDG_RUNTIME_DIR |
45 | char *name = getenv("XDG_RUNTIME_DIR"); | 45 | const char *name = env_get("XDG_RUNTIME_DIR"); |
46 | if (name) | 46 | if (name) |
47 | disable_file_path(name, "pulse/native"); | 47 | disable_file_path(name, "pulse/native"); |
48 | 48 | ||
@@ -76,7 +76,10 @@ void pulseaudio_disable(void) { | |||
76 | } | 76 | } |
77 | 77 | ||
78 | static void pulseaudio_fallback(const char *path) { | 78 | static void pulseaudio_fallback(const char *path) { |
79 | assert(path); | ||
80 | |||
79 | fmessage("Cannot mount tmpfs on %s/.config/pulse\n", cfg.homedir); | 81 | fmessage("Cannot mount tmpfs on %s/.config/pulse\n", cfg.homedir); |
82 | env_store_name_val("PULSE_CLIENTCONFIG", path, SETENV); | ||
80 | if (setenv("PULSE_CLIENTCONFIG", path, 1) < 0) | 83 | if (setenv("PULSE_CLIENTCONFIG", path, 1) < 0) |
81 | errExit("setenv"); | 84 | errExit("setenv"); |
82 | } | 85 | } |
diff --git a/src/firejail/run_symlink.c b/src/firejail/run_symlink.c index ea3889024..5bf27fc6d 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,58 +42,25 @@ 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 | const char *path = env_get("PATH"); |
44 | if (!p) { | 46 | if (!path) { |
45 | fprintf(stderr, "Error: PATH environment variable not set\n"); | 47 | fprintf(stderr, "Error: PATH environment variable not set\n"); |
46 | exit(1); | 48 | exit(1); |
47 | } | 49 | } |
48 | 50 | ||
49 | char *path = strdup(p); | 51 | char *p = find_in_path(program); |
50 | if (!path) | 52 | 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"); | 53 | fprintf(stderr, "Error: cannot find the program in the path\n"); |
87 | exit(1); | 54 | exit(1); |
88 | } | 55 | } |
89 | 56 | program = p; | |
90 | free(selfpath); | ||
91 | 57 | ||
92 | // restore original umask | 58 | // restore original umask |
93 | umask(orig_umask); | 59 | umask(orig_umask); |
94 | 60 | ||
61 | // restore original environment variables | ||
62 | env_apply_all(); | ||
63 | |||
95 | // desktop integration is not supported for root user; instead, the original program is started | 64 | // desktop integration is not supported for root user; instead, the original program is started |
96 | if (getuid() == 0 || run_as_is) { | 65 | if (getuid() == 0 || run_as_is) { |
97 | argv[0] = program; | 66 | argv[0] = program; |
@@ -108,6 +77,7 @@ void run_symlink(int argc, char **argv, int run_as_is) { | |||
108 | a[i + 2] = argv[i + 1]; | 77 | a[i + 2] = argv[i + 1]; |
109 | } | 78 | } |
110 | a[i + 2] = NULL; | 79 | a[i + 2] = NULL; |
80 | assert(env_get("LD_PRELOAD") == NULL); | ||
111 | assert(getenv("LD_PRELOAD") == NULL); | 81 | assert(getenv("LD_PRELOAD") == NULL); |
112 | execvp(a[0], a); | 82 | execvp(a[0], a); |
113 | 83 | ||
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index d811fe45a..1f94d86cd 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -268,8 +268,7 @@ static void sandbox_if_up(Bridge *br) { | |||
268 | 268 | ||
269 | static void chk_chroot(void) { | 269 | static void chk_chroot(void) { |
270 | // if we are starting firejail inside some other container technology, we don't care about this | 270 | // if we are starting firejail inside some other container technology, we don't care about this |
271 | char *mycont = getenv("container"); | 271 | if (env_get("container")) |
272 | if (mycont) | ||
273 | return; | 272 | return; |
274 | 273 | ||
275 | // check if this is a regular chroot | 274 | // check if this is a regular chroot |
@@ -419,7 +418,7 @@ static int ok_to_run(const char *program) { | |||
419 | return 1; | 418 | return 1; |
420 | } | 419 | } |
421 | else { // search $PATH | 420 | else { // search $PATH |
422 | char *path1 = getenv("PATH"); | 421 | const char *path1 = env_get("PATH"); |
423 | if (path1) { | 422 | if (path1) { |
424 | if (arg_debug) | 423 | if (arg_debug) |
425 | printf("Searching $PATH for %s\n", program); | 424 | printf("Searching $PATH for %s\n", program); |
@@ -465,7 +464,7 @@ void start_application(int no_sandbox, int fd, char *set_sandbox_status) { | |||
465 | // set environment | 464 | // set environment |
466 | if (no_sandbox == 0) { | 465 | if (no_sandbox == 0) { |
467 | env_defaults(); | 466 | env_defaults(); |
468 | env_apply(); | 467 | env_apply_all(); |
469 | } | 468 | } |
470 | // restore original umask | 469 | // restore original umask |
471 | umask(orig_umask); | 470 | umask(orig_umask); |
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c index a2aaa86eb..baf99c5b9 100644 --- a/src/firejail/sbox.c +++ b/src/firejail/sbox.c | |||
@@ -36,7 +36,7 @@ static int __attribute__((noreturn)) sbox_do_exec_v(unsigned filtermask, char * | |||
36 | int env_index = 0; | 36 | int env_index = 0; |
37 | char *new_environment[256] = { NULL }; | 37 | char *new_environment[256] = { NULL }; |
38 | // preserve firejail-specific env vars | 38 | // preserve firejail-specific env vars |
39 | char *cl = getenv("FIREJAIL_FILE_COPY_LIMIT"); | 39 | const char *cl = env_get("FIREJAIL_FILE_COPY_LIMIT"); |
40 | if (cl) { | 40 | if (cl) { |
41 | if (asprintf(&new_environment[env_index++], "FIREJAIL_FILE_COPY_LIMIT=%s", cl) == -1) | 41 | if (asprintf(&new_environment[env_index++], "FIREJAIL_FILE_COPY_LIMIT=%s", cl) == -1) |
42 | errExit("asprintf"); | 42 | errExit("asprintf"); |
@@ -120,7 +120,7 @@ static int __attribute__((noreturn)) sbox_do_exec_v(unsigned filtermask, char * | |||
120 | // handle X32 ABI | 120 | // handle X32 ABI |
121 | BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, X32_SYSCALL_BIT, 1, 0), | 121 | BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, X32_SYSCALL_BIT, 1, 0), |
122 | BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, 0, 1, 0), | 122 | BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, 0, 1, 0), |
123 | RETURN_ERRNO(EPERM), | 123 | KILL_OR_RETURN_ERRNO, |
124 | #endif | 124 | #endif |
125 | 125 | ||
126 | // syscall list | 126 | // syscall list |
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index e47e6c910..808dd4c37 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c | |||
@@ -208,7 +208,7 @@ int seccomp_filter_drop(bool native) { | |||
208 | // - seccomp | 208 | // - seccomp |
209 | if (cfg.seccomp_list_drop == NULL) { | 209 | if (cfg.seccomp_list_drop == NULL) { |
210 | // default seccomp if error action is not changed | 210 | // default seccomp if error action is not changed |
211 | if (cfg.seccomp_list == NULL && cfg.seccomp_error_action) { | 211 | if (cfg.seccomp_list == NULL && arg_seccomp_error_action == DEFAULT_SECCOMP_ERROR_ACTION) { |
212 | if (arg_seccomp_block_secondary) | 212 | if (arg_seccomp_block_secondary) |
213 | seccomp_filter_block_secondary(); | 213 | seccomp_filter_block_secondary(); |
214 | else { | 214 | else { |
@@ -221,11 +221,29 @@ int seccomp_filter_drop(bool native) { | |||
221 | } | 221 | } |
222 | // default seccomp filter with additional drop list | 222 | // default seccomp filter with additional drop list |
223 | else { // cfg.seccomp_list != NULL | 223 | else { // cfg.seccomp_list != NULL |
224 | if (arg_seccomp_block_secondary) | 224 | int rv; |
225 | |||
226 | if (arg_seccomp_block_secondary) { | ||
227 | if (arg_seccomp_error_action != DEFAULT_SECCOMP_ERROR_ACTION) { | ||
228 | if (arg_debug) | ||
229 | printf("Rebuild secondary block seccomp filter\n"); | ||
230 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, | ||
231 | PATH_FSECCOMP, "secondary", "block", RUN_SECCOMP_BLOCK_SECONDARY); | ||
232 | if (rv) | ||
233 | exit(rv); | ||
234 | } | ||
225 | seccomp_filter_block_secondary(); | 235 | seccomp_filter_block_secondary(); |
226 | else { | 236 | } else { |
227 | #if defined(__x86_64__) | 237 | #if defined(__x86_64__) |
228 | #if defined(__LP64__) | 238 | #if defined(__LP64__) |
239 | if (arg_seccomp_error_action != DEFAULT_SECCOMP_ERROR_ACTION) { | ||
240 | if (arg_debug) | ||
241 | printf("Rebuild 32 bit seccomp filter\n"); | ||
242 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, | ||
243 | PATH_FSECCOMP, "secondary", "32", RUN_SECCOMP_32); | ||
244 | if (rv) | ||
245 | exit(rv); | ||
246 | } | ||
229 | seccomp_filter_32(); | 247 | seccomp_filter_32(); |
230 | #endif | 248 | #endif |
231 | #endif | 249 | #endif |
@@ -242,16 +260,22 @@ int seccomp_filter_drop(bool native) { | |||
242 | list = cfg.seccomp_list32; | 260 | list = cfg.seccomp_list32; |
243 | } | 261 | } |
244 | 262 | ||
245 | if (list == NULL) | ||
246 | list = ""; | ||
247 | // build the seccomp filter as a regular user | 263 | // build the seccomp filter as a regular user |
248 | int rv; | 264 | if (list) |
249 | if (arg_allow_debuggers) | 265 | if (arg_allow_debuggers) |
250 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, | 266 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, |
251 | PATH_FSECCOMP, command, "drop", filter, postexec_filter, list, "allow-debuggers"); | 267 | PATH_FSECCOMP, command, "drop", filter, postexec_filter, list, "allow-debuggers"); |
268 | else | ||
269 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 6, | ||
270 | PATH_FSECCOMP, command, "drop", filter, postexec_filter, list); | ||
252 | else | 271 | else |
253 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 6, | 272 | if (arg_allow_debuggers) |
254 | PATH_FSECCOMP, command, "drop", filter, postexec_filter, list); | 273 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, |
274 | PATH_FSECCOMP, command, filter, "allow-debuggers"); | ||
275 | else | ||
276 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, | ||
277 | PATH_FSECCOMP, command, filter); | ||
278 | |||
255 | if (rv) | 279 | if (rv) |
256 | exit(rv); | 280 | exit(rv); |
257 | 281 | ||
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/firejail/x11.c b/src/firejail/x11.c index 4872a5207..1121ec84e 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -41,7 +41,7 @@ | |||
41 | // Parse the DISPLAY environment variable and return a display number. | 41 | // Parse the DISPLAY environment variable and return a display number. |
42 | // Returns -1 if DISPLAY is not set, or is set to anything other than :ddd. | 42 | // Returns -1 if DISPLAY is not set, or is set to anything other than :ddd. |
43 | int x11_display(void) { | 43 | int x11_display(void) { |
44 | const char *display_str = getenv("DISPLAY"); | 44 | const char *display_str = env_get("DISPLAY"); |
45 | char *endp; | 45 | char *endp; |
46 | unsigned long display; | 46 | unsigned long display; |
47 | 47 | ||
@@ -208,7 +208,7 @@ void x11_start_xvfb(int argc, char **argv) { | |||
208 | pid_t jail = 0; | 208 | pid_t jail = 0; |
209 | pid_t server = 0; | 209 | pid_t server = 0; |
210 | 210 | ||
211 | setenv("FIREJAIL_X11", "yes", 1); | 211 | env_store_name_val("FIREJAIL_X11", "yes", SETENV); |
212 | 212 | ||
213 | // never try to run X servers as root!!! | 213 | // never try to run X servers as root!!! |
214 | if (getuid() == 0) { | 214 | if (getuid() == 0) { |
@@ -326,7 +326,11 @@ void x11_start_xvfb(int argc, char **argv) { | |||
326 | if (arg_debug) | 326 | if (arg_debug) |
327 | printf("Starting xvfb...\n"); | 327 | printf("Starting xvfb...\n"); |
328 | 328 | ||
329 | // restore original environment variables | ||
330 | env_apply_all(); | ||
331 | |||
329 | // running without privileges - see drop_privs call above | 332 | // running without privileges - see drop_privs call above |
333 | assert(env_get("LD_PRELOAD") == NULL); | ||
330 | assert(getenv("LD_PRELOAD") == NULL); | 334 | assert(getenv("LD_PRELOAD") == NULL); |
331 | execvp(server_argv[0], server_argv); | 335 | execvp(server_argv[0], server_argv); |
332 | perror("execvp"); | 336 | perror("execvp"); |
@@ -355,7 +359,7 @@ void x11_start_xvfb(int argc, char **argv) { | |||
355 | free(fname); | 359 | free(fname); |
356 | 360 | ||
357 | assert(display_str); | 361 | assert(display_str); |
358 | setenv("DISPLAY", display_str, 1); | 362 | env_store_name_val("DISPLAY", display_str, SETENV); |
359 | // run attach command | 363 | // run attach command |
360 | jail = fork(); | 364 | jail = fork(); |
361 | if (jail < 0) | 365 | if (jail < 0) |
@@ -363,7 +367,11 @@ void x11_start_xvfb(int argc, char **argv) { | |||
363 | if (jail == 0) { | 367 | if (jail == 0) { |
364 | fmessage("\n*** Attaching to Xvfb display %d ***\n\n", display); | 368 | fmessage("\n*** Attaching to Xvfb display %d ***\n\n", display); |
365 | 369 | ||
370 | // restore original environment variables | ||
371 | env_apply_all(); | ||
372 | |||
366 | // running without privileges - see drop_privs call above | 373 | // running without privileges - see drop_privs call above |
374 | assert(env_get("LD_PRELOAD") == NULL); | ||
367 | assert(getenv("LD_PRELOAD") == NULL); | 375 | assert(getenv("LD_PRELOAD") == NULL); |
368 | execvp(jail_argv[0], jail_argv); | 376 | execvp(jail_argv[0], jail_argv); |
369 | perror("execvp"); | 377 | perror("execvp"); |
@@ -428,7 +436,7 @@ void x11_start_xephyr(int argc, char **argv) { | |||
428 | if (newscreen) | 436 | if (newscreen) |
429 | xephyr_screen = newscreen; | 437 | xephyr_screen = newscreen; |
430 | 438 | ||
431 | setenv("FIREJAIL_X11", "yes", 1); | 439 | env_store_name_val("FIREJAIL_X11", "yes", SETENV); |
432 | 440 | ||
433 | // unfortunately, xephyr does a number of weird things when started by root user!!! | 441 | // unfortunately, xephyr does a number of weird things when started by root user!!! |
434 | if (getuid() == 0) { | 442 | if (getuid() == 0) { |
@@ -556,7 +564,11 @@ void x11_start_xephyr(int argc, char **argv) { | |||
556 | if (arg_debug) | 564 | if (arg_debug) |
557 | printf("Starting xephyr...\n"); | 565 | printf("Starting xephyr...\n"); |
558 | 566 | ||
567 | // restore original environment variables | ||
568 | env_apply_all(); | ||
569 | |||
559 | // running without privileges - see drop_privs call above | 570 | // running without privileges - see drop_privs call above |
571 | assert(env_get("LD_PRELOAD") == NULL); | ||
560 | assert(getenv("LD_PRELOAD") == NULL); | 572 | assert(getenv("LD_PRELOAD") == NULL); |
561 | execvp(server_argv[0], server_argv); | 573 | execvp(server_argv[0], server_argv); |
562 | perror("execvp"); | 574 | perror("execvp"); |
@@ -585,7 +597,7 @@ void x11_start_xephyr(int argc, char **argv) { | |||
585 | free(fname); | 597 | free(fname); |
586 | 598 | ||
587 | assert(display_str); | 599 | assert(display_str); |
588 | setenv("DISPLAY", display_str, 1); | 600 | env_store_name_val("DISPLAY", display_str, SETENV); |
589 | // run attach command | 601 | // run attach command |
590 | jail = fork(); | 602 | jail = fork(); |
591 | if (jail < 0) | 603 | if (jail < 0) |
@@ -594,8 +606,12 @@ void x11_start_xephyr(int argc, char **argv) { | |||
594 | if (!arg_quiet) | 606 | if (!arg_quiet) |
595 | printf("\n*** Attaching to Xephyr display %d ***\n\n", display); | 607 | printf("\n*** Attaching to Xephyr display %d ***\n\n", display); |
596 | 608 | ||
609 | // restore original environment variables | ||
610 | env_apply_all(); | ||
611 | |||
597 | // running without privileges - see drop_privs call above | 612 | // running without privileges - see drop_privs call above |
598 | assert(getenv("LD_PRELOAD") == NULL); | 613 | assert(getenv("LD_PRELOAD") == NULL); |
614 | assert(env_get("LD_PRELOAD") == NULL); | ||
599 | execvp(jail_argv[0], jail_argv); | 615 | execvp(jail_argv[0], jail_argv); |
600 | perror("execvp"); | 616 | perror("execvp"); |
601 | _exit(1); | 617 | _exit(1); |
@@ -780,8 +796,12 @@ static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, | |||
780 | dup2(fd_null,2); | 796 | dup2(fd_null,2); |
781 | } | 797 | } |
782 | 798 | ||
799 | // restore original environment variables | ||
800 | env_apply_all(); | ||
801 | |||
783 | // running without privileges - see drop_privs call above | 802 | // running without privileges - see drop_privs call above |
784 | assert(getenv("LD_PRELOAD") == NULL); | 803 | assert(getenv("LD_PRELOAD") == NULL); |
804 | assert(env_get("LD_PRELOAD") == NULL); | ||
785 | execvp(server_argv[0], server_argv); | 805 | execvp(server_argv[0], server_argv); |
786 | perror("execvp"); | 806 | perror("execvp"); |
787 | _exit(1); | 807 | _exit(1); |
@@ -827,7 +847,11 @@ static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, | |||
827 | 847 | ||
828 | fmessage("\n*** Attaching to xpra display %d ***\n\n", display); | 848 | fmessage("\n*** Attaching to xpra display %d ***\n\n", display); |
829 | 849 | ||
850 | // restore original environment variables | ||
851 | env_apply_all(); | ||
852 | |||
830 | // running without privileges - see drop_privs call above | 853 | // running without privileges - see drop_privs call above |
854 | assert(env_get("LD_PRELOAD") == NULL); | ||
831 | assert(getenv("LD_PRELOAD") == NULL); | 855 | assert(getenv("LD_PRELOAD") == NULL); |
832 | execvp(attach_argv[0], attach_argv); | 856 | execvp(attach_argv[0], attach_argv); |
833 | perror("execvp"); | 857 | perror("execvp"); |
@@ -835,7 +859,7 @@ static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, | |||
835 | } | 859 | } |
836 | 860 | ||
837 | assert(display_str); | 861 | assert(display_str); |
838 | setenv("DISPLAY", display_str, 1); | 862 | env_store_name_val("DISPLAY", display_str, SETENV); |
839 | 863 | ||
840 | // build jail command | 864 | // build jail command |
841 | char *firejail_argv[argc+2]; | 865 | char *firejail_argv[argc+2]; |
@@ -857,7 +881,12 @@ static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, | |||
857 | errExit("fork"); | 881 | errExit("fork"); |
858 | if (jail == 0) { | 882 | if (jail == 0) { |
859 | // running without privileges - see drop_privs call above | 883 | // running without privileges - see drop_privs call above |
884 | assert(env_get("LD_PRELOAD") == NULL); | ||
860 | assert(getenv("LD_PRELOAD") == NULL); | 885 | assert(getenv("LD_PRELOAD") == NULL); |
886 | |||
887 | // restore original environment variables | ||
888 | env_apply_all(); | ||
889 | |||
861 | if (firejail_argv[0]) // shut up llvm scan-build | 890 | if (firejail_argv[0]) // shut up llvm scan-build |
862 | execvp(firejail_argv[0], firejail_argv); | 891 | execvp(firejail_argv[0], firejail_argv); |
863 | perror("execvp"); | 892 | perror("execvp"); |
@@ -883,7 +912,12 @@ static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, | |||
883 | dup2(fd_null,1); | 912 | dup2(fd_null,1); |
884 | dup2(fd_null,2); | 913 | dup2(fd_null,2); |
885 | } | 914 | } |
915 | |||
916 | // restore original environment variables | ||
917 | env_apply_all(); | ||
918 | |||
886 | // running without privileges - see drop_privs call above | 919 | // running without privileges - see drop_privs call above |
920 | assert(env_get("LD_PRELOAD") == NULL); | ||
887 | assert(getenv("LD_PRELOAD") == NULL); | 921 | assert(getenv("LD_PRELOAD") == NULL); |
888 | execvp(stop_argv[0], stop_argv); | 922 | execvp(stop_argv[0], stop_argv); |
889 | perror("execvp"); | 923 | perror("execvp"); |
@@ -1051,7 +1085,11 @@ static void __attribute__((noreturn)) x11_start_xpra_new(int argc, char **argv, | |||
1051 | dup2(fd_null,2); | 1085 | dup2(fd_null,2); |
1052 | } | 1086 | } |
1053 | 1087 | ||
1088 | // restore original environment variables | ||
1089 | env_apply_all(); | ||
1090 | |||
1054 | // running without privileges - see drop_privs call above | 1091 | // running without privileges - see drop_privs call above |
1092 | assert(env_get("LD_PRELOAD") == NULL); | ||
1055 | assert(getenv("LD_PRELOAD") == NULL); | 1093 | assert(getenv("LD_PRELOAD") == NULL); |
1056 | execvp(server_argv[0], server_argv); | 1094 | execvp(server_argv[0], server_argv); |
1057 | perror("execvp"); | 1095 | perror("execvp"); |
@@ -1072,7 +1110,7 @@ static void __attribute__((noreturn)) x11_start_xpra_new(int argc, char **argv, | |||
1072 | void x11_start_xpra(int argc, char **argv) { | 1110 | void x11_start_xpra(int argc, char **argv) { |
1073 | EUID_ASSERT(); | 1111 | EUID_ASSERT(); |
1074 | 1112 | ||
1075 | setenv("FIREJAIL_X11", "yes", 1); | 1113 | env_store_name_val("FIREJAIL_X11", "yes", SETENV); |
1076 | 1114 | ||
1077 | // unfortunately, xpra does a number of weird things when started by root user!!! | 1115 | // unfortunately, xpra does a number of weird things when started by root user!!! |
1078 | if (getuid() == 0) { | 1116 | if (getuid() == 0) { |
@@ -1134,7 +1172,7 @@ void x11_xorg(void) { | |||
1134 | #ifdef HAVE_X11 | 1172 | #ifdef HAVE_X11 |
1135 | 1173 | ||
1136 | // get DISPLAY env | 1174 | // get DISPLAY env |
1137 | char *display = getenv("DISPLAY"); | 1175 | const char *display = env_get("DISPLAY"); |
1138 | if (!display) { | 1176 | if (!display) { |
1139 | fputs("Error: --x11=xorg requires an 'outer' X11 server to use.\n", stderr); | 1177 | fputs("Error: --x11=xorg requires an 'outer' X11 server to use.\n", stderr); |
1140 | exit(1); | 1178 | exit(1); |
@@ -1259,7 +1297,7 @@ void x11_xorg(void) { | |||
1259 | ASSERT_PERMS(dest, getuid(), getgid(), 0600); | 1297 | ASSERT_PERMS(dest, getuid(), getgid(), 0600); |
1260 | 1298 | ||
1261 | // blacklist user .Xauthority file if it is not masked already | 1299 | // blacklist user .Xauthority file if it is not masked already |
1262 | char *envar = getenv("XAUTHORITY"); | 1300 | const char *envar = env_get("XAUTHORITY"); |
1263 | if (envar) { | 1301 | if (envar) { |
1264 | char *rp = realpath(envar, NULL); | 1302 | char *rp = realpath(envar, NULL); |
1265 | if (rp) { | 1303 | if (rp) { |
@@ -1269,8 +1307,7 @@ void x11_xorg(void) { | |||
1269 | } | 1307 | } |
1270 | } | 1308 | } |
1271 | // set environment variable | 1309 | // set environment variable |
1272 | if (setenv("XAUTHORITY", dest, 1) < 0) | 1310 | env_store_name_val("XAUTHORITY", dest, SETENV); |
1273 | errExit("setenv"); | ||
1274 | free(dest); | 1311 | free(dest); |
1275 | 1312 | ||
1276 | // mask RUN_XAUTHORITY_SEC_DIR | 1313 | // mask RUN_XAUTHORITY_SEC_DIR |
@@ -1391,7 +1428,7 @@ void x11_block(void) { | |||
1391 | errExit("strdup"); | 1428 | errExit("strdup"); |
1392 | profile_check_line(cmd, 0, NULL); | 1429 | profile_check_line(cmd, 0, NULL); |
1393 | profile_add(cmd); | 1430 | profile_add(cmd); |
1394 | char *xauthority = getenv("XAUTHORITY"); | 1431 | const char *xauthority = env_get("XAUTHORITY"); |
1395 | if (xauthority) { | 1432 | if (xauthority) { |
1396 | char *line; | 1433 | char *line; |
1397 | if (asprintf(&line, "blacklist %s", xauthority) == -1) | 1434 | if (asprintf(&line, "blacklist %s", xauthority) == -1) |
diff --git a/src/firemon/Makefile.in b/src/firemon/Makefile.in index f2513213c..9ee798fe9 100644 --- a/src/firemon/Makefile.in +++ b/src/firemon/Makefile.in | |||
@@ -2,7 +2,7 @@ all: firemon | |||
2 | 2 | ||
3 | include ../common.mk | 3 | include ../common.mk |
4 | 4 | ||
5 | %.o : %.c $(H_FILE_LIST) | 5 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/pid.h |
6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | 6 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ |
7 | 7 | ||
8 | firemon: $(OBJS) ../lib/common.o ../lib/pid.o | 8 | firemon: $(OBJS) ../lib/common.o ../lib/pid.o |
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..cc5ac7e35 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 ../lib/errno.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..c64587068 100644 --- a/src/fsec-optimize/main.c +++ b/src/fsec-optimize/main.c | |||
@@ -18,6 +18,9 @@ | |||
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 "fsec_optimize.h" | 20 | #include "fsec_optimize.h" |
21 | #include "../include/syscall.h" | ||
22 | |||
23 | int arg_seccomp_error_action = SECCOMP_RET_ERRNO | EPERM; // error action: errno, log or kill | ||
21 | 24 | ||
22 | static void usage(void) { | 25 | static void usage(void) { |
23 | printf("Usage:\n"); | 26 | printf("Usage:\n"); |
@@ -44,11 +47,21 @@ printf("\n"); | |||
44 | return 0; | 47 | return 0; |
45 | } | 48 | } |
46 | 49 | ||
47 | #ifdef WARN_DUMPABLE | 50 | warn_dumpable(); |
48 | // check FIREJAIL_PLUGIN in order to not print a warning during make | 51 | |
49 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid() && getenv("FIREJAIL_PLUGIN")) | 52 | char *error_action = getenv("FIREJAIL_SECCOMP_ERROR_ACTION"); |
50 | fprintf(stderr, "Error fsec-optimize: I am dumpable\n"); | 53 | if (error_action) { |
51 | #endif | 54 | if (strcmp(error_action, "kill") == 0) |
55 | arg_seccomp_error_action = SECCOMP_RET_KILL; | ||
56 | else if (strcmp(error_action, "log") == 0) | ||
57 | arg_seccomp_error_action = SECCOMP_RET_LOG; | ||
58 | else { | ||
59 | arg_seccomp_error_action = errno_find_name(error_action); | ||
60 | if (arg_seccomp_error_action == -1) | ||
61 | errExit("seccomp-error-action: unknown errno"); | ||
62 | arg_seccomp_error_action |= SECCOMP_RET_ERRNO; | ||
63 | } | ||
64 | } | ||
52 | 65 | ||
53 | char *fname = argv[1]; | 66 | char *fname = argv[1]; |
54 | 67 | ||
diff --git a/src/fsec-optimize/optimizer.c b/src/fsec-optimize/optimizer.c index 776beaa75..eb777f13b 100644 --- a/src/fsec-optimize/optimizer.c +++ b/src/fsec-optimize/optimizer.c | |||
@@ -33,7 +33,7 @@ | |||
33 | static inline int is_blacklist(struct sock_filter *bpf) { | 33 | static inline int is_blacklist(struct sock_filter *bpf) { |
34 | if (bpf->code == BPF_JMP + BPF_JEQ + BPF_K && | 34 | if (bpf->code == BPF_JMP + BPF_JEQ + BPF_K && |
35 | (bpf + 1)->code == BPF_RET + BPF_K && | 35 | (bpf + 1)->code == BPF_RET + BPF_K && |
36 | (bpf + 1)->k == SECCOMP_RET_KILL ) | 36 | (bpf + 1)->k == (__u32)arg_seccomp_error_action) |
37 | return 1; | 37 | return 1; |
38 | return 0; | 38 | return 0; |
39 | } | 39 | } |
@@ -89,9 +89,9 @@ static int optimize_blacklists(struct sock_filter *filter, int entries) { | |||
89 | } | 89 | } |
90 | } | 90 | } |
91 | 91 | ||
92 | // step 3: add the new ret KILL, and recalculate entries | 92 | // step 3: add the new ret KILL/LOG/ERRNO, and recalculate entries |
93 | filter_step2[j].code = BPF_RET + BPF_K; | 93 | filter_step2[j].code = BPF_RET + BPF_K; |
94 | filter_step2[j].k = SECCOMP_RET_KILL; | 94 | filter_step2[j].k = arg_seccomp_error_action; |
95 | entries = j + 1; | 95 | entries = j + 1; |
96 | 96 | ||
97 | // step 4: recalculate jumps | 97 | // step 4: recalculate jumps |
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..f47efb5e8 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include "fseccomp.h" | 20 | #include "fseccomp.h" |
21 | #include "../include/seccomp.h" | 21 | #include "../include/seccomp.h" |
22 | int arg_quiet = 0; | 22 | int arg_quiet = 0; |
23 | int arg_seccomp_error_action = EPERM; // error action: errno, log or kill | 23 | int arg_seccomp_error_action = SECCOMP_RET_ERRNO | EPERM; // error action: errno, log or kill |
24 | 24 | ||
25 | static void usage(void) { | 25 | static void usage(void) { |
26 | printf("Usage:\n"); | 26 | printf("Usage:\n"); |
@@ -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/fseccomp/seccomp_secondary.c b/src/fseccomp/seccomp_secondary.c index f024859d3..b8e8d0a89 100644 --- a/src/fseccomp/seccomp_secondary.c +++ b/src/fseccomp/seccomp_secondary.c | |||
@@ -126,7 +126,7 @@ void seccomp_secondary_block(const char *fname) { | |||
126 | EXAMINE_SYSCALL, | 126 | EXAMINE_SYSCALL, |
127 | #if defined(__x86_64__) | 127 | #if defined(__x86_64__) |
128 | // block x32 | 128 | // block x32 |
129 | HANDLE_X32_KILL, | 129 | HANDLE_X32, |
130 | #endif | 130 | #endif |
131 | // block personality(2) where domain != PER_LINUX or 0xffffffff (query current personality) | 131 | // block personality(2) where domain != PER_LINUX or 0xffffffff (query current personality) |
132 | // 0: if personality(2), continue to 1, else goto 7 (allow) | 132 | // 0: if personality(2), continue to 1, else goto 7 (allow) |
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/include/seccomp.h b/src/include/seccomp.h index 90db16d39..b3b75c2d1 100644 --- a/src/include/seccomp.h +++ b/src/include/seccomp.h | |||
@@ -201,7 +201,7 @@ | |||
201 | #define VALIDATE_ARCHITECTURE_KILL \ | 201 | #define VALIDATE_ARCHITECTURE_KILL \ |
202 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \ | 202 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \ |
203 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ | 203 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ |
204 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) | 204 | KILL_OR_RETURN_ERRNO |
205 | 205 | ||
206 | #define VALIDATE_ARCHITECTURE_64 \ | 206 | #define VALIDATE_ARCHITECTURE_64 \ |
207 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \ | 207 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \ |
@@ -222,11 +222,7 @@ | |||
222 | #define HANDLE_X32 \ | 222 | #define HANDLE_X32 \ |
223 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), \ | 223 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), \ |
224 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), \ | 224 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), \ |
225 | RETURN_ERRNO(EPERM) | 225 | KILL_OR_RETURN_ERRNO |
226 | #define HANDLE_X32_KILL \ | ||
227 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), \ | ||
228 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), \ | ||
229 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) | ||
230 | #endif | 226 | #endif |
231 | 227 | ||
232 | #define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ | 228 | #define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ |
@@ -258,6 +254,8 @@ | |||
258 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO | nr) | 254 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO | nr) |
259 | 255 | ||
260 | extern int arg_seccomp_error_action; // error action: errno, log or kill | 256 | extern int arg_seccomp_error_action; // error action: errno, log or kill |
257 | #define DEFAULT_SECCOMP_ERROR_ACTION EPERM | ||
258 | |||
261 | #define KILL_OR_RETURN_ERRNO \ | 259 | #define KILL_OR_RETURN_ERRNO \ |
262 | BPF_STMT(BPF_RET+BPF_K, arg_seccomp_error_action) | 260 | BPF_STMT(BPF_RET+BPF_K, arg_seccomp_error_action) |
263 | 261 | ||
diff --git a/src/include/syscall_armeabi.h b/src/include/syscall_armeabi.h index cbdc67f37..3b574f875 100644 --- a/src/include/syscall_armeabi.h +++ b/src/include/syscall_armeabi.h | |||
@@ -42,6 +42,7 @@ | |||
42 | { "exit", 1 }, | 42 | { "exit", 1 }, |
43 | { "exit_group", 248 }, | 43 | { "exit_group", 248 }, |
44 | { "faccessat", 334 }, | 44 | { "faccessat", 334 }, |
45 | { "faccessat2", 439 }, | ||
45 | { "fallocate", 352 }, | 46 | { "fallocate", 352 }, |
46 | { "fanotify_init", 367 }, | 47 | { "fanotify_init", 367 }, |
47 | { "fanotify_mark", 368 }, | 48 | { "fanotify_mark", 368 }, |
diff --git a/src/include/syscall_i386.h b/src/include/syscall_i386.h index 4795e5b2a..752e11f24 100644 --- a/src/include/syscall_i386.h +++ b/src/include/syscall_i386.h | |||
@@ -54,6 +54,7 @@ | |||
54 | { "exit", 1 }, | 54 | { "exit", 1 }, |
55 | { "exit_group", 252 }, | 55 | { "exit_group", 252 }, |
56 | { "faccessat", 307 }, | 56 | { "faccessat", 307 }, |
57 | { "faccessat2", 439 }, | ||
57 | { "fadvise64", 250 }, | 58 | { "fadvise64", 250 }, |
58 | { "fadvise64_64", 272 }, | 59 | { "fadvise64_64", 272 }, |
59 | { "fallocate", 324 }, | 60 | { "fallocate", 324 }, |
diff --git a/src/include/syscall_x86_64.h b/src/include/syscall_x86_64.h index 539e874be..97f2762b1 100644 --- a/src/include/syscall_x86_64.h +++ b/src/include/syscall_x86_64.h | |||
@@ -47,6 +47,7 @@ | |||
47 | { "exit", 60 }, | 47 | { "exit", 60 }, |
48 | { "exit_group", 231 }, | 48 | { "exit_group", 231 }, |
49 | { "faccessat", 269 }, | 49 | { "faccessat", 269 }, |
50 | { "faccessat2", 439 }, | ||
50 | { "fadvise64", 221 }, | 51 | { "fadvise64", 221 }, |
51 | { "fallocate", 285 }, | 52 | { "fallocate", 285 }, |
52 | { "fanotify_init", 300 }, | 53 | { "fanotify_init", 300 }, |
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..758f1ce0b 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 | }, |
@@ -358,6 +359,9 @@ static const SyscallGroupList sysgroups[] = { | |||
358 | #ifdef SYS_faccessat | 359 | #ifdef SYS_faccessat |
359 | "faccessat," | 360 | "faccessat," |
360 | #endif | 361 | #endif |
362 | #ifdef SYS_faccessat2 | ||
363 | "faccessat2," | ||
364 | #endif | ||
361 | #ifdef SYS_fallocate | 365 | #ifdef SYS_fallocate |
362 | "fallocate," | 366 | "fallocate," |
363 | #endif | 367 | #endif |
diff --git a/src/man/firecfg.txt b/src/man/firecfg.txt index f3123356a..2c02aee47 100644 --- a/src/man/firecfg.txt +++ b/src/man/firecfg.txt | |||
@@ -61,7 +61,7 @@ $ sudo firecfg --add-users dustin lucas mike eleven | |||
61 | 61 | ||
62 | .TP | 62 | .TP |
63 | \fB\-\-bindir=directory | 63 | \fB\-\-bindir=directory |
64 | Create and search symbolic links in directory instead of the default location /user/local/bin. | 64 | Create and search symbolic links in directory instead of the default location /usr/local/bin. |
65 | Directory should precede /usr/bin and /bin in the PATH environment variable. | 65 | Directory should precede /usr/bin and /bin in the PATH environment variable. |
66 | 66 | ||
67 | .TP | 67 | .TP |
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 9524254c1..5e77b5f70 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt | |||
@@ -266,7 +266,7 @@ Mount new /root and /home/user directories in temporary | |||
266 | filesystems. All modifications are discarded when the sandbox is | 266 | filesystems. All modifications are discarded when the sandbox is |
267 | closed. | 267 | closed. |
268 | .TP | 268 | .TP |
269 | \fBprivate directory | 269 | \fBprivate=directory |
270 | Use directory as user home. | 270 | Use directory as user home. |
271 | .TP | 271 | .TP |
272 | \fBprivate-bin file,file | 272 | \fBprivate-bin file,file |
@@ -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 347e2b31b..e85a02ee8 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -693,6 +693,10 @@ Example: | |||
693 | $ firejail \-\-net=eth0 \-\-defaultgw=10.10.20.1 firefox | 693 | $ firejail \-\-net=eth0 \-\-defaultgw=10.10.20.1 firefox |
694 | #endif | 694 | #endif |
695 | .TP | 695 | .TP |
696 | \fB\-\-deterministic-exit-code | ||
697 | Always exit firejail with the first child's exit status. The default behavior is to use the exit status of the final child to exit, which can be nondeterministic. | ||
698 | .br | ||
699 | .TP | ||
696 | \fB\-\-disable-mnt | 700 | \fB\-\-disable-mnt |
697 | Blacklist /mnt, /media, /run/mount and /run/media access. | 701 | Blacklist /mnt, /media, /run/mount and /run/media access. |
698 | .br | 702 | .br |
@@ -703,10 +707,6 @@ Example: | |||
703 | $ firejail \-\-disable-mnt firefox | 707 | $ firejail \-\-disable-mnt firefox |
704 | 708 | ||
705 | .TP | 709 | .TP |
706 | \fB\-\-deterministic-exit-code | ||
707 | Always exit firejail with the first child's exit status. The default behavior is to use the exit status of the final child to exit, which can be nondeterministic. | ||
708 | |||
709 | .TP | ||
710 | \fB\-\-dns=address | 710 | \fB\-\-dns=address |
711 | Set a DNS server for the sandbox. Up to three DNS servers can be defined. | 711 | Set a DNS server for the sandbox. Up to three DNS servers can be defined. |
712 | Use this option if you don't trust the DNS setup on your network. | 712 | Use this option if you don't trust the DNS setup on your network. |
@@ -1317,7 +1317,7 @@ $ firejail --netfilter=/etc/firejail/webserver.net --net=eth0 \\ | |||
1317 | .br | 1317 | .br |
1318 | 1318 | ||
1319 | .br | 1319 | .br |
1320 | .B nolocal.net | 1320 | .B nolocal.net/nolocal6.net |
1321 | is a desktop client firewall that disable access to local network. Example: | 1321 | is a desktop client firewall that disable access to local network. Example: |
1322 | .br | 1322 | .br |
1323 | 1323 | ||
@@ -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. |
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 | } |