diff options
author | netblue30 <netblue30@yahoo.com> | 2020-08-22 07:45:58 -0400 |
---|---|---|
committer | netblue30 <netblue30@yahoo.com> | 2020-08-22 07:45:58 -0400 |
commit | 07472ed702f416f8c684de8baff3b32761ebc32a (patch) | |
tree | 4bfeb5e53e2ae379dd30a80421ff29cdf1293a09 | |
parent | cleaning up POSTMORTEM code (diff) | |
parent | Merge pull request #3572 from smitsohu/dumpable (diff) | |
download | firejail-07472ed702f416f8c684de8baff3b32761ebc32a.tar.gz firejail-07472ed702f416f8c684de8baff3b32761ebc32a.tar.zst firejail-07472ed702f416f8c684de8baff3b32761ebc32a.zip |
Merge branch 'master' of https://github.com/netblue30/firejail
-rw-r--r-- | Makefile.in | 12 | ||||
-rw-r--r-- | src/fcopy/main.c | 6 | ||||
-rw-r--r-- | src/firejail/firejail.h | 3 | ||||
-rw-r--r-- | src/firejail/ls.c | 169 | ||||
-rw-r--r-- | src/firejail/main.c | 35 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 40 | ||||
-rw-r--r-- | src/firejail/sbox.c | 1 | ||||
-rw-r--r-- | src/firejail/usage.c | 3 | ||||
-rw-r--r-- | src/firejail/x11.c | 173 | ||||
-rw-r--r-- | src/fldd/main.c | 6 | ||||
-rw-r--r-- | src/fnet/main.c | 16 | ||||
-rw-r--r-- | src/fnetfilter/main.c | 6 | ||||
-rw-r--r-- | src/fsec-optimize/fsec_optimize.h | 1 | ||||
-rw-r--r-- | src/fsec-optimize/main.c | 6 | ||||
-rw-r--r-- | src/fsec-print/fsec_print.h | 1 | ||||
-rw-r--r-- | src/fsec-print/main.c | 5 | ||||
-rw-r--r-- | src/fseccomp/fseccomp.h | 1 | ||||
-rw-r--r-- | src/fseccomp/main.c | 16 | ||||
-rw-r--r-- | src/include/common.h | 3 | ||||
-rw-r--r-- | src/include/rundefs.h | 5 | ||||
-rw-r--r-- | src/man/firejail.txt | 20 |
21 files changed, 314 insertions, 214 deletions
diff --git a/Makefile.in b/Makefile.in index f1002f892..890ba1b0a 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -18,15 +18,16 @@ HAVE_SUID=@HAVE_SUID@ | |||
18 | 18 | ||
19 | all: all_items man filters | 19 | all: all_items man filters |
20 | APPS = src/firecfg/firecfg src/firejail/firejail src/firemon/firemon src/profstats/profstats | 20 | APPS = src/firecfg/firecfg src/firejail/firejail src/firemon/firemon src/profstats/profstats |
21 | SBOX_APPS = src/faudit/faudit src/fbuilder/fbuilder src/fcopy/fcopy src/fldd/fldd src/fnet/fnet src/fnetfilter/fnetfilter src/ftee/ftee | 21 | SBOX_APPS = src/faudit/faudit src/fbuilder/fbuilder src/ftee/ftee |
22 | SBOX_APPS_NON_DUMPABLE = src/fcopy/fcopy src/fldd/fldd src/fnet/fnet src/fnetfilter/fnetfilter | ||
22 | MYDIRS = src/lib | 23 | MYDIRS = src/lib |
23 | MYLIBS = src/libpostexecseccomp/libpostexecseccomp.so src/libtrace/libtrace.so src/libtracelog/libtracelog.so | 24 | MYLIBS = src/libpostexecseccomp/libpostexecseccomp.so src/libtrace/libtrace.so src/libtracelog/libtracelog.so |
24 | MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 firejail-users.5 | 25 | MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 firejail-users.5 |
25 | ifeq ($(HAVE_SECCOMP),-DHAVE_SECCOMP) | 26 | ifeq ($(HAVE_SECCOMP),-DHAVE_SECCOMP) |
26 | SBOX_APPS += src/fsec-optimize/fsec-optimize src/fsec-print/fsec-print src/fseccomp/fseccomp | 27 | SBOX_APPS_NON_DUMPABLE += src/fsec-optimize/fsec-optimize src/fsec-print/fsec-print src/fseccomp/fseccomp |
27 | SECCOMP_FILTERS = seccomp seccomp.debug seccomp.32 seccomp.block_secondary seccomp.mdwx seccomp.mdwx.32 | 28 | SECCOMP_FILTERS = seccomp seccomp.debug seccomp.32 seccomp.block_secondary seccomp.mdwx seccomp.mdwx.32 |
28 | endif | 29 | endif |
29 | ALL_ITEMS = $(APPS) $(SBOX_APPS) $(MYLIBS) | 30 | ALL_ITEMS = $(APPS) $(SBOX_APPS) $(SBOX_APPS_NON_DUMPABLE) $(MYLIBS) |
30 | 31 | ||
31 | .PHONY: all_items $(ALL_ITEMS) | 32 | .PHONY: all_items $(ALL_ITEMS) |
32 | all_items: $(ALL_ITEMS) | 33 | all_items: $(ALL_ITEMS) |
@@ -43,7 +44,7 @@ $(MANPAGES): $(wildcard src/man/*.txt) | |||
43 | 44 | ||
44 | man: $(MANPAGES) | 45 | man: $(MANPAGES) |
45 | 46 | ||
46 | filters: $(SECCOMP_FILTERS) $(SBOX_APPS) | 47 | filters: $(SECCOMP_FILTERS) $(SBOX_APPS_NON_DUMPABLE) |
47 | ifeq ($(HAVE_SECCOMP),-DHAVE_SECCOMP) | 48 | ifeq ($(HAVE_SECCOMP),-DHAVE_SECCOMP) |
48 | seccomp: src/fseccomp/fseccomp src/fsec-optimize/fsec-optimize | 49 | seccomp: src/fseccomp/fseccomp src/fsec-optimize/fsec-optimize |
49 | src/fseccomp/fseccomp default seccomp | 50 | src/fseccomp/fseccomp default seccomp |
@@ -106,7 +107,10 @@ endif | |||
106 | install -m 0755 -d $(DESTDIR)$(libdir)/firejail | 107 | install -m 0755 -d $(DESTDIR)$(libdir)/firejail |
107 | install -m 0644 -t $(DESTDIR)$(libdir)/firejail $(MYLIBS) $(SECCOMP_FILTERS) src/firecfg/firecfg.config | 108 | install -m 0644 -t $(DESTDIR)$(libdir)/firejail $(MYLIBS) $(SECCOMP_FILTERS) src/firecfg/firecfg.config |
108 | install -m 0755 -t $(DESTDIR)$(libdir)/firejail $(SBOX_APPS) | 109 | install -m 0755 -t $(DESTDIR)$(libdir)/firejail $(SBOX_APPS) |
110 | # non-dumpable plugins | ||
111 | install -m 0711 -t $(DESTDIR)$(libdir)/firejail $(SBOX_APPS_NON_DUMPABLE) | ||
109 | ifeq ($(HAVE_CONTRIB_INSTALL),yes) | 112 | ifeq ($(HAVE_CONTRIB_INSTALL),yes) |
113 | # contrib scripts | ||
110 | install -m 0755 -t $(DESTDIR)$(libdir)/firejail contrib/*.py contrib/*.sh | 114 | install -m 0755 -t $(DESTDIR)$(libdir)/firejail contrib/*.py contrib/*.sh |
111 | # vim syntax | 115 | # vim syntax |
112 | install -m 0755 -d $(DESTDIR)$(datarootdir)/vim/vimfiles/ftdetect | 116 | install -m 0755 -d $(DESTDIR)$(datarootdir)/vim/vimfiles/ftdetect |
diff --git a/src/fcopy/main.c b/src/fcopy/main.c index 83d9c17e6..67237b4ea 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c | |||
@@ -23,6 +23,7 @@ | |||
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> | ||
26 | 27 | ||
27 | #if HAVE_SELINUX | 28 | #if HAVE_SELINUX |
28 | #include <sys/stat.h> | 29 | #include <sys/stat.h> |
@@ -411,6 +412,11 @@ int main(int argc, char **argv) { | |||
411 | exit(1); | 412 | exit(1); |
412 | } | 413 | } |
413 | 414 | ||
415 | #ifdef 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 | |||
414 | // trim trailing chars | 420 | // trim trailing chars |
415 | if (src[strlen(src) - 1] == '/') | 421 | if (src[strlen(src) - 1] == '/') |
416 | src[strlen(src) - 1] = '\0'; | 422 | src[strlen(src) - 1] = '\0'; |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index c98f80d13..49d19e33d 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -728,10 +728,13 @@ void x11_xorg(void); | |||
728 | // ls.c | 728 | // ls.c |
729 | enum { | 729 | enum { |
730 | SANDBOX_FS_LS = 0, | 730 | SANDBOX_FS_LS = 0, |
731 | SANDBOX_FS_CAT, | ||
731 | SANDBOX_FS_GET, | 732 | SANDBOX_FS_GET, |
732 | SANDBOX_FS_PUT, | 733 | SANDBOX_FS_PUT, |
733 | SANDBOX_FS_MAX // this should always be the last entry | 734 | SANDBOX_FS_MAX // this should always be the last entry |
734 | }; | 735 | }; |
736 | void ls(const char *path); | ||
737 | void cat(const char *path); | ||
735 | void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) __attribute__((noreturn)); | 738 | void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) __attribute__((noreturn)); |
736 | 739 | ||
737 | // checkcfg.c | 740 | // checkcfg.c |
diff --git a/src/firejail/ls.c b/src/firejail/ls.c index aa33d838b..4d0a001b6 100644 --- a/src/firejail/ls.c +++ b/src/firejail/ls.c | |||
@@ -34,18 +34,12 @@ | |||
34 | static uid_t c_uid = 0; | 34 | static uid_t c_uid = 0; |
35 | static char *c_uid_name = NULL; | 35 | static char *c_uid_name = NULL; |
36 | 36 | ||
37 | static void print_file_or_dir(const char *path, const char *fname, int separator) { | 37 | static void print_file_or_dir(const char *path, const char *fname) { |
38 | assert(fname); | 38 | assert(fname); |
39 | 39 | ||
40 | char *name; | 40 | char *name; |
41 | if (separator) { | 41 | if (asprintf(&name, "%s/%s", path, fname) == -1) |
42 | if (asprintf(&name, "%s/%s", path, fname) == -1) | 42 | errExit("asprintf"); |
43 | errExit("asprintf"); | ||
44 | } | ||
45 | else { | ||
46 | if (asprintf(&name, "%s%s", path, fname) == -1) | ||
47 | errExit("asprintf"); | ||
48 | } | ||
49 | 43 | ||
50 | struct stat s; | 44 | struct stat s; |
51 | if (stat(name, &s) == -1) { | 45 | if (stat(name, &s) == -1) { |
@@ -178,13 +172,81 @@ static void print_directory(const char *path) { | |||
178 | errExit("scandir"); | 172 | errExit("scandir"); |
179 | else { | 173 | else { |
180 | for (i = 0; i < n; i++) { | 174 | for (i = 0; i < n; i++) { |
181 | print_file_or_dir(path, namelist[i]->d_name, 0); | 175 | print_file_or_dir(path, namelist[i]->d_name); |
182 | free(namelist[i]); | 176 | free(namelist[i]); |
183 | } | 177 | } |
184 | } | 178 | } |
185 | free(namelist); | 179 | free(namelist); |
186 | } | 180 | } |
187 | 181 | ||
182 | void ls(const char *path) { | ||
183 | EUID_ASSERT(); | ||
184 | assert(path); | ||
185 | |||
186 | char *rp = realpath(path, NULL); | ||
187 | if (!rp || access(rp, R_OK) == -1) { | ||
188 | fprintf(stderr, "Error: cannot access %s\n", path); | ||
189 | exit(1); | ||
190 | } | ||
191 | if (arg_debug) | ||
192 | printf("ls %s\n", rp); | ||
193 | |||
194 | // list directory contents | ||
195 | struct stat s; | ||
196 | if (stat(rp, &s) == -1) { | ||
197 | fprintf(stderr, "Error: cannot access %s\n", rp); | ||
198 | exit(1); | ||
199 | } | ||
200 | if (S_ISDIR(s.st_mode)) | ||
201 | print_directory(rp); | ||
202 | else { | ||
203 | char *split = strrchr(rp, '/'); | ||
204 | if (split) { | ||
205 | *split = '\0'; | ||
206 | char *rp2 = split + 1; | ||
207 | if (arg_debug) | ||
208 | printf("path %s, file %s\n", rp, rp2); | ||
209 | print_file_or_dir(rp, rp2); | ||
210 | } | ||
211 | } | ||
212 | free(rp); | ||
213 | } | ||
214 | |||
215 | void cat(const char *path) { | ||
216 | EUID_ASSERT(); | ||
217 | assert(path); | ||
218 | |||
219 | if (arg_debug) | ||
220 | printf("cat %s\n", path); | ||
221 | FILE *fp = fopen(path, "r"); | ||
222 | if (!fp) { | ||
223 | fprintf(stderr, "Error: cannot read %s\n", path); | ||
224 | exit(1); | ||
225 | } | ||
226 | int fd = fileno(fp); | ||
227 | if (fd == -1) | ||
228 | errExit("fileno"); | ||
229 | struct stat s; | ||
230 | if (fstat(fd, &s) == -1) | ||
231 | errExit("fstat"); | ||
232 | if (!S_ISREG(s.st_mode)) { | ||
233 | fprintf(stderr, "Error: %s is not a regular file\n", path); | ||
234 | exit(1); | ||
235 | } | ||
236 | bool tty = isatty(STDOUT_FILENO); | ||
237 | |||
238 | int c; | ||
239 | while ((c = fgetc(fp)) != EOF) { | ||
240 | // file is untrusted | ||
241 | // replace control characters when printing to a terminal | ||
242 | if (tty && c != '\t' && c != '\n' && iscntrl((unsigned char) c)) | ||
243 | c = '?'; | ||
244 | fputc(c, stdout); | ||
245 | } | ||
246 | fflush(stdout); | ||
247 | fclose(fp); | ||
248 | } | ||
249 | |||
188 | char *expand_path(const char *path) { | 250 | char *expand_path(const char *path) { |
189 | char *fname = NULL; | 251 | char *fname = NULL; |
190 | if (*path == '/') { | 252 | if (*path == '/') { |
@@ -219,14 +281,14 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
219 | check_join_permission(pid); | 281 | check_join_permission(pid); |
220 | 282 | ||
221 | // expand paths | 283 | // expand paths |
222 | char *fname1 = expand_path(path1);; | 284 | char *fname1 = expand_path(path1); |
223 | char *fname2 = NULL; | 285 | char *fname2 = NULL; |
224 | if (path2 != NULL) { | 286 | if (path2 != NULL) { |
225 | fname2 = expand_path(path2); | 287 | fname2 = expand_path(path2); |
226 | } | 288 | } |
227 | if (arg_debug) { | 289 | if (arg_debug) { |
228 | printf("file1 %s\n", fname1); | 290 | printf("file1 %s\n", fname1); |
229 | printf("file2 %s\n", fname2); | 291 | printf("file2 %s\n", fname2 ? fname2 : "(null)"); |
230 | } | 292 | } |
231 | 293 | ||
232 | // sandbox root directory | 294 | // sandbox root directory |
@@ -234,57 +296,36 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
234 | if (asprintf(&rootdir, "/proc/%d/root", pid) == -1) | 296 | if (asprintf(&rootdir, "/proc/%d/root", pid) == -1) |
235 | errExit("asprintf"); | 297 | errExit("asprintf"); |
236 | 298 | ||
237 | if (op == SANDBOX_FS_LS) { | 299 | if (op == SANDBOX_FS_LS || op == SANDBOX_FS_CAT) { |
238 | EUID_ROOT(); | 300 | pid_t child = fork(); |
239 | // chroot | 301 | if (child < 0) |
240 | if (chroot(rootdir) < 0) | 302 | errExit("fork"); |
241 | errExit("chroot"); | 303 | if (child == 0) { |
242 | if (chdir("/") < 0) | 304 | EUID_ROOT(); |
243 | errExit("chdir"); | 305 | // chroot |
244 | 306 | if (chroot(rootdir) < 0) | |
245 | // drop privileges | 307 | errExit("chroot"); |
246 | drop_privs(0); | 308 | if (chdir("/") < 0) |
247 | 309 | errExit("chdir"); | |
248 | // check access | ||
249 | if (access(fname1, R_OK) == -1) { | ||
250 | fprintf(stderr, "Error: Cannot access %s\n", fname1); | ||
251 | exit(1); | ||
252 | } | ||
253 | /* coverity[toctou] */ | ||
254 | char *rp = realpath(fname1, NULL); | ||
255 | if (!rp) { | ||
256 | fprintf(stderr, "Error: Cannot access %s\n", fname1); | ||
257 | exit(1); | ||
258 | } | ||
259 | if (arg_debug) | ||
260 | printf("realpath %s\n", rp); | ||
261 | |||
262 | 310 | ||
263 | // list directory contents | 311 | // drop privileges |
264 | struct stat s; | 312 | drop_privs(0); |
265 | if (stat(rp, &s) == -1) { | ||
266 | fprintf(stderr, "Error: Cannot access %s\n", rp); | ||
267 | exit(1); | ||
268 | } | ||
269 | if (S_ISDIR(s.st_mode)) { | ||
270 | char *dir; | ||
271 | if (asprintf(&dir, "%s/", rp) == -1) | ||
272 | errExit("asprintf"); | ||
273 | 313 | ||
274 | print_directory(dir); | 314 | if (op == SANDBOX_FS_LS) |
275 | free(dir); | 315 | ls(fname1); |
276 | } | 316 | else |
277 | else { | 317 | cat(fname1); |
278 | char *split = strrchr(rp, '/'); | 318 | #ifdef HAVE_GCOV |
279 | if (split) { | 319 | __gcov_flush(); |
280 | *split = '\0'; | 320 | #endif |
281 | char *rp2 = split + 1; | 321 | _exit(0); |
282 | if (arg_debug) | ||
283 | printf("path %s, file %s\n", rp, rp2); | ||
284 | print_file_or_dir(rp, rp2, 1); | ||
285 | } | ||
286 | } | 322 | } |
287 | free(rp); | 323 | // wait for the child to finish |
324 | int status = 0; | ||
325 | waitpid(child, &status, 0); | ||
326 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0); | ||
327 | else | ||
328 | exit(1); | ||
288 | } | 329 | } |
289 | 330 | ||
290 | // get file from sandbox and store it in the current directory | 331 | // get file from sandbox and store it in the current directory |
@@ -303,10 +344,12 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
303 | // create a user-owned temporary file in /run/firejail directory | 344 | // create a user-owned temporary file in /run/firejail directory |
304 | char tmp_fname[] = "/run/firejail/tmpget-XXXXXX"; | 345 | char tmp_fname[] = "/run/firejail/tmpget-XXXXXX"; |
305 | int fd = mkstemp(tmp_fname); | 346 | int fd = mkstemp(tmp_fname); |
306 | if (fd != -1) { | 347 | if (fd == -1) { |
307 | SET_PERMS_FD(fd, getuid(), getgid(), 0600); | 348 | fprintf(stderr, "Error: cannot create temporary file %s\n", tmp_fname); |
308 | close(fd); | 349 | exit(1); |
309 | } | 350 | } |
351 | SET_PERMS_FD(fd, getuid(), getgid(), 0600); | ||
352 | close(fd); | ||
310 | 353 | ||
311 | // copy the source file into the temporary file - we need to chroot | 354 | // copy the source file into the temporary file - we need to chroot |
312 | pid_t child = fork(); | 355 | pid_t child = fork(); |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 4c98210f5..072651c4d 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -789,6 +789,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
789 | } | 789 | } |
790 | 790 | ||
791 | // list directory contents | 791 | // list directory contents |
792 | if (!arg_debug) | ||
793 | arg_quiet = 1; | ||
792 | pid_t pid = require_pid(argv[i] + 5); | 794 | pid_t pid = require_pid(argv[i] + 5); |
793 | sandboxfs(SANDBOX_FS_LS, pid, path, NULL); | 795 | sandboxfs(SANDBOX_FS_LS, pid, path, NULL); |
794 | exit(0); | 796 | exit(0); |
@@ -796,6 +798,35 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
796 | else | 798 | else |
797 | exit_err_feature("file transfer"); | 799 | exit_err_feature("file transfer"); |
798 | } | 800 | } |
801 | else if (strncmp(argv[i], "--cat=", 6) == 0) { | ||
802 | if (checkcfg(CFG_FILE_TRANSFER)) { | ||
803 | logargs(argc, argv); | ||
804 | if (arg_private_cwd) { | ||
805 | fprintf(stderr, "Error: --cat and --private-cwd options are mutually exclusive\n"); | ||
806 | exit(1); | ||
807 | } | ||
808 | |||
809 | if ((i + 2) != argc) { | ||
810 | fprintf(stderr, "Error: invalid --cat option, path expected\n"); | ||
811 | exit(1); | ||
812 | } | ||
813 | char *path = argv[i + 1]; | ||
814 | invalid_filename(path, 0); // no globbing | ||
815 | if (strstr(path, "..")) { | ||
816 | fprintf(stderr, "Error: invalid file name %s\n", path); | ||
817 | exit(1); | ||
818 | } | ||
819 | |||
820 | // write file contents to stdout | ||
821 | if (!arg_debug) | ||
822 | arg_quiet = 1; | ||
823 | pid_t pid = require_pid(argv[i] + 6); | ||
824 | sandboxfs(SANDBOX_FS_CAT, pid, path, NULL); | ||
825 | exit(0); | ||
826 | } | ||
827 | else | ||
828 | exit_err_feature("file transfer"); | ||
829 | } | ||
799 | #endif | 830 | #endif |
800 | else if (strncmp(argv[i], "--join=", 7) == 0) { | 831 | else if (strncmp(argv[i], "--join=", 7) == 0) { |
801 | if (checkcfg(CFG_JOIN) || getuid() == 0) { | 832 | if (checkcfg(CFG_JOIN) || getuid() == 0) { |
@@ -1252,6 +1283,10 @@ int main(int argc, char **argv, char **envp) { | |||
1252 | } | 1283 | } |
1253 | EUID_ASSERT(); | 1284 | EUID_ASSERT(); |
1254 | 1285 | ||
1286 | #ifdef WARN_DUMPABLE | ||
1287 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid()) | ||
1288 | fprintf(stderr, "Error: Firejail is dumpable\n"); | ||
1289 | #endif | ||
1255 | 1290 | ||
1256 | // check for force-nonewprivs in /etc/firejail/firejail.config file | 1291 | // check for force-nonewprivs in /etc/firejail/firejail.config file |
1257 | if (checkcfg(CFG_FORCE_NONEWPRIVS)) | 1292 | if (checkcfg(CFG_FORCE_NONEWPRIVS)) |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index e42d35be5..81d535762 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -140,6 +140,20 @@ void set_apparmor(void) { | |||
140 | } | 140 | } |
141 | #endif | 141 | #endif |
142 | 142 | ||
143 | #ifdef HAVE_SECCOMP | ||
144 | void seccomp_debug(void) { | ||
145 | if (arg_debug == 0) | ||
146 | return; | ||
147 | |||
148 | EUID_USER(); | ||
149 | printf("Seccomp directory:\n"); | ||
150 | ls(RUN_SECCOMP_DIR); | ||
151 | printf("Active seccomp files:\n"); | ||
152 | cat(RUN_SECCOMP_LIST); | ||
153 | EUID_ROOT(); | ||
154 | } | ||
155 | #endif | ||
156 | |||
143 | static void save_nogroups(void) { | 157 | static void save_nogroups(void) { |
144 | if (arg_nogroups == 0) | 158 | if (arg_nogroups == 0) |
145 | return; | 159 | return; |
@@ -197,32 +211,6 @@ static FILE *create_ready_for_join_file(void) { | |||
197 | } | 211 | } |
198 | } | 212 | } |
199 | 213 | ||
200 | #ifdef HAVE_SECCOMP | ||
201 | static void seccomp_debug(void) { | ||
202 | if (arg_debug == 0) | ||
203 | return; | ||
204 | |||
205 | pid_t child = fork(); | ||
206 | if (child < 0) | ||
207 | errExit("fork"); | ||
208 | if (child == 0) { | ||
209 | // dropping privs before calling system(3) | ||
210 | drop_privs(1); | ||
211 | printf("Seccomp directory:\n"); | ||
212 | int rv = system("ls -l " RUN_SECCOMP_DIR); | ||
213 | (void) rv; | ||
214 | printf("Active seccomp files:\n"); | ||
215 | rv = system("cat " RUN_SECCOMP_LIST); | ||
216 | (void) rv; | ||
217 | #ifdef HAVE_GCOV | ||
218 | __gcov_flush(); | ||
219 | #endif | ||
220 | _exit(0); | ||
221 | } | ||
222 | waitpid(child, NULL, 0); | ||
223 | } | ||
224 | #endif | ||
225 | |||
226 | static void sandbox_if_up(Bridge *br) { | 214 | static void sandbox_if_up(Bridge *br) { |
227 | assert(br); | 215 | assert(br); |
228 | if (!br->configured) | 216 | if (!br->configured) |
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c index 57c21ce78..a92d62940 100644 --- a/src/firejail/sbox.c +++ b/src/firejail/sbox.c | |||
@@ -48,6 +48,7 @@ static int __attribute__((noreturn)) sbox_do_exec_v(unsigned filtermask, char * | |||
48 | if (cfg.seccomp_error_action) | 48 | if (cfg.seccomp_error_action) |
49 | if (asprintf(&new_environment[env_index++], "FIREJAIL_SECCOMP_ERROR_ACTION=%s", cfg.seccomp_error_action) == -1) | 49 | if (asprintf(&new_environment[env_index++], "FIREJAIL_SECCOMP_ERROR_ACTION=%s", cfg.seccomp_error_action) == -1) |
50 | errExit("asprintf"); | 50 | errExit("asprintf"); |
51 | new_environment[env_index++] = "FIREJAIL_PLUGIN="; // always set | ||
51 | 52 | ||
52 | if (filtermask & SBOX_STDIN_FROM_FILE) { | 53 | if (filtermask & SBOX_STDIN_FROM_FILE) { |
53 | int fd; | 54 | int fd; |
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 73c9a6a8b..2390706f2 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -47,6 +47,9 @@ static char *usage_str = | |||
47 | " --caps.drop=capability,capability - blacklist capabilities filter.\n" | 47 | " --caps.drop=capability,capability - blacklist capabilities filter.\n" |
48 | " --caps.keep=capability,capability - whitelist capabilities filter.\n" | 48 | " --caps.keep=capability,capability - whitelist capabilities filter.\n" |
49 | " --caps.print=name|pid - print the caps filter.\n" | 49 | " --caps.print=name|pid - print the caps filter.\n" |
50 | #ifdef HAVE_FILE_TRANSFER | ||
51 | " --cat=name|pid filename - print content of file from sandbox container.\n" | ||
52 | #endif | ||
50 | " --cgroup=tasks-file - place the sandbox in the specified control group.\n" | 53 | " --cgroup=tasks-file - place the sandbox in the specified control group.\n" |
51 | #ifdef HAVE_CHROOT | 54 | #ifdef HAVE_CHROOT |
52 | " --chroot=dirname - chroot into directory.\n" | 55 | " --chroot=dirname - chroot into directory.\n" |
diff --git a/src/firejail/x11.c b/src/firejail/x11.c index ba54ca376..e10abad4e 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -34,7 +34,7 @@ | |||
34 | 34 | ||
35 | #include <fcntl.h> | 35 | #include <fcntl.h> |
36 | #ifndef O_PATH | 36 | #ifndef O_PATH |
37 | # define O_PATH 010000000 | 37 | #define O_PATH 010000000 |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | 40 | ||
@@ -1129,28 +1129,17 @@ void x11_start(int argc, char **argv) { | |||
1129 | } | 1129 | } |
1130 | #endif | 1130 | #endif |
1131 | 1131 | ||
1132 | // Porting notes: | 1132 | |
1133 | // | ||
1134 | // 1. merge #1100 from zackw: | ||
1135 | // Attempting to run xauth -f directly on a file in /run/firejail/mnt/ directory fails on Debian 8 | ||
1136 | // with this message: | ||
1137 | // xauth: timeout in locking authority file /run/firejail/mnt/sec.Xauthority-Qt5Mu4 | ||
1138 | // Failed to create untrusted X cookie: xauth: exit 1 | ||
1139 | // For this reason we run xauth on a file in a tmpfs filesystem mounted on /tmp. This was | ||
1140 | // a partial merge. | ||
1141 | // | ||
1142 | // 2. Since we cannot deal with the TOCTOU condition when mounting .Xauthority in user home | ||
1143 | // directory, we need to make sure /usr/bin/xauth executable is the real thing, and not | ||
1144 | // something picked up on $PATH. | ||
1145 | // | ||
1146 | // 3. If for any reason xauth command fails, we exit the sandbox. On Debian 8 this happens | ||
1147 | // when using a network namespace. Somehow, xauth tries to connect to the abstract socket, | ||
1148 | // and it fails because of the network namespace - it should try to connect to the regular | ||
1149 | // Unix socket! If we ignore the fail condition, the program will be started on X server without | ||
1150 | // the security extension loaded. | ||
1151 | void x11_xorg(void) { | 1133 | void x11_xorg(void) { |
1152 | #ifdef HAVE_X11 | 1134 | #ifdef HAVE_X11 |
1153 | 1135 | ||
1136 | // get DISPLAY env | ||
1137 | char *display = getenv("DISPLAY"); | ||
1138 | if (!display) { | ||
1139 | fputs("Error: --x11=xorg requires an 'outer' X11 server to use.\n", stderr); | ||
1140 | exit(1); | ||
1141 | } | ||
1142 | |||
1154 | // check xauth utility is present in the system | 1143 | // check xauth utility is present in the system |
1155 | struct stat s; | 1144 | struct stat s; |
1156 | if (stat("/usr/bin/xauth", &s) == -1) { | 1145 | if (stat("/usr/bin/xauth", &s) == -1) { |
@@ -1160,26 +1149,27 @@ void x11_xorg(void) { | |||
1160 | fprintf(stderr, " Fedora: sudo dnf install xorg-x11-xauth\n"); | 1149 | fprintf(stderr, " Fedora: sudo dnf install xorg-x11-xauth\n"); |
1161 | exit(1); | 1150 | exit(1); |
1162 | } | 1151 | } |
1163 | if (s.st_uid != 0 && s.st_gid != 0) { | 1152 | if ((s.st_uid != 0 && s.st_gid != 0) || (s.st_mode & S_IWOTH)) { |
1164 | fprintf(stderr, "Error: invalid /usr/bin/xauth executable\n"); | 1153 | fprintf(stderr, "Error: invalid /usr/bin/xauth executable\n"); |
1165 | exit(1); | 1154 | exit(1); |
1166 | } | 1155 | } |
1167 | 1156 | if (s.st_size > 1024 * 1024) { | |
1168 | // get DISPLAY env | 1157 | fprintf(stderr, "Error: /usr/bin/xauth executable is too large\n"); |
1169 | char *display = getenv("DISPLAY"); | ||
1170 | if (!display) { | ||
1171 | fputs("Error: --x11=xorg requires an 'outer' X11 server to use.\n", stderr); | ||
1172 | exit(1); | 1158 | exit(1); |
1173 | } | 1159 | } |
1174 | 1160 | // copy /usr/bin/xauth in the sandbox and set mode to 0711 | |
1175 | // temporarily mount a tempfs on top of /tmp directory | 1161 | // users are not able to trace the running xauth this way |
1176 | if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=1777,gid=0") < 0) | ||
1177 | errExit("mounting /tmp"); | ||
1178 | |||
1179 | // create the temporary .Xauthority file | ||
1180 | if (arg_debug) | 1162 | if (arg_debug) |
1181 | printf("Generating a new .Xauthority file\n"); | 1163 | printf("Copying /usr/bin/xauth to %s\n", RUN_XAUTH_FILE); |
1182 | char tmpfname[] = "/tmp/.tmpXauth-XXXXXX"; | 1164 | if (copy_file("/usr/bin/xauth", RUN_XAUTH_FILE, 0, 0, 0711)) { |
1165 | fprintf(stderr, "Error: cannot copy /usr/bin/xauth executable\n"); | ||
1166 | exit(1); | ||
1167 | } | ||
1168 | |||
1169 | fmessage("Generating a new .Xauthority file\n"); | ||
1170 | mkdir_attr(RUN_XAUTHORITY_SEC_DIR, 0700, getuid(), getgid()); | ||
1171 | // create new Xauthority file in RUN_XAUTHORITY_SEC_DIR | ||
1172 | char tmpfname[] = RUN_XAUTHORITY_SEC_DIR "/.Xauth-XXXXXX"; | ||
1183 | int fd = mkstemp(tmpfname); | 1173 | int fd = mkstemp(tmpfname); |
1184 | if (fd == -1) { | 1174 | if (fd == -1) { |
1185 | fprintf(stderr, "Error: cannot create .Xauthority file\n"); | 1175 | fprintf(stderr, "Error: cannot create .Xauthority file\n"); |
@@ -1189,64 +1179,17 @@ void x11_xorg(void) { | |||
1189 | errExit("chown"); | 1179 | errExit("chown"); |
1190 | close(fd); | 1180 | close(fd); |
1191 | 1181 | ||
1192 | pid_t child = fork(); | 1182 | // run xauth |
1193 | if (child < 0) | ||
1194 | errExit("fork"); | ||
1195 | if (child == 0) { | ||
1196 | drop_privs(1); | ||
1197 | clearenv(); | ||
1198 | #ifdef HAVE_GCOV | ||
1199 | __gcov_flush(); | ||
1200 | #endif | ||
1201 | if (arg_debug) { | ||
1202 | execlp("/usr/bin/xauth", "/usr/bin/xauth", "-v", "-f", tmpfname, | ||
1203 | "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted", NULL); | ||
1204 | } | ||
1205 | else { | ||
1206 | execlp("/usr/bin/xauth", "/usr/bin/xauth", "-f", tmpfname, | ||
1207 | "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted", NULL); | ||
1208 | } | ||
1209 | |||
1210 | _exit(127); | ||
1211 | } | ||
1212 | |||
1213 | // wait for the xauth process to finish | ||
1214 | int status; | ||
1215 | if (waitpid(child, &status, 0) != child) | ||
1216 | errExit("waitpid"); | ||
1217 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { | ||
1218 | /* success */ | ||
1219 | } | ||
1220 | else if (WIFEXITED(status)) { | ||
1221 | fprintf(stderr, "Failed to create untrusted X cookie: xauth: exit %d\n", | ||
1222 | WEXITSTATUS(status)); | ||
1223 | exit(1); | ||
1224 | } | ||
1225 | else if (WIFSIGNALED(status)) { | ||
1226 | fprintf(stderr, "Failed to create untrusted X cookie: xauth: %s\n", | ||
1227 | strsignal(WTERMSIG(status))); | ||
1228 | exit(1); | ||
1229 | } | ||
1230 | else { | ||
1231 | fprintf(stderr, "Failed to create untrusted X cookie: " | ||
1232 | "xauth: un-decodable exit status %04x\n", status); | ||
1233 | exit(1); | ||
1234 | } | ||
1235 | |||
1236 | // move the temporary file in RUN_XAUTHORITY_SEC_FILE in order to have it deleted | ||
1237 | // automatically when the sandbox is closed (rename doesn't work) | ||
1238 | if (arg_debug) | 1183 | if (arg_debug) |
1239 | printf("Copying the new .Xauthority file\n"); | 1184 | sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 8, RUN_XAUTH_FILE, "-v", "-f", tmpfname, |
1240 | copy_file_from_user_to_root(tmpfname, RUN_XAUTHORITY_SEC_FILE, getuid(), getgid(), 0600); | 1185 | "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted"); |
1241 | 1186 | else | |
1242 | /* coverity[toctou] */ | 1187 | sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, RUN_XAUTH_FILE, "-f", tmpfname, |
1243 | unlink(tmpfname); | 1188 | "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted"); |
1244 | umount("/tmp"); | 1189 | // remove xauth copy |
1245 | 1190 | unlink(RUN_XAUTH_FILE); | |
1246 | // mount RUN_XAUTHORITY_SEC_FILE noexec, nodev, nosuid | ||
1247 | fs_remount(RUN_XAUTHORITY_SEC_FILE, MOUNT_NOEXEC, 0); | ||
1248 | 1191 | ||
1249 | // Ensure there is already a file in the usual location, so that bind-mount below will work. | 1192 | // ensure there is already a file ~/.Xauthority, so that bind-mount below will work. |
1250 | char *dest; | 1193 | char *dest; |
1251 | if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) | 1194 | if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) |
1252 | errExit("asprintf"); | 1195 | errExit("asprintf"); |
@@ -1257,13 +1200,12 @@ void x11_xorg(void) { | |||
1257 | exit(1); | 1200 | exit(1); |
1258 | } | 1201 | } |
1259 | } | 1202 | } |
1260 | 1203 | // get a file descriptor for ~/.Xauthority | |
1261 | // get a file descriptor for .Xauthority | 1204 | int dst = safe_fd(dest, O_PATH|O_NOFOLLOW|O_CLOEXEC); |
1262 | fd = safe_fd(dest, O_PATH|O_NOFOLLOW|O_CLOEXEC); | 1205 | if (dst == -1) |
1263 | if (fd == -1) | ||
1264 | errExit("safe_fd"); | 1206 | errExit("safe_fd"); |
1265 | // check if the actual mount destination is a user owned regular file | 1207 | // check if the actual mount destination is a user owned regular file |
1266 | if (fstat(fd, &s) == -1) | 1208 | if (fstat(dst, &s) == -1) |
1267 | errExit("fstat"); | 1209 | errExit("fstat"); |
1268 | if (!S_ISREG(s.st_mode) || s.st_uid != getuid()) { | 1210 | if (!S_ISREG(s.st_mode) || s.st_uid != getuid()) { |
1269 | if (S_ISLNK(s.st_mode)) | 1211 | if (S_ISLNK(s.st_mode)) |
@@ -1274,31 +1216,49 @@ void x11_xorg(void) { | |||
1274 | } | 1216 | } |
1275 | // preserve a read-only mount | 1217 | // preserve a read-only mount |
1276 | struct statvfs vfs; | 1218 | struct statvfs vfs; |
1277 | if (fstatvfs(fd, &vfs) == -1) | 1219 | if (fstatvfs(dst, &vfs) == -1) |
1278 | errExit("fstatvfs"); | 1220 | errExit("fstatvfs"); |
1279 | if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY) | 1221 | if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY) |
1280 | fs_remount(RUN_XAUTHORITY_SEC_FILE, MOUNT_READONLY, 0); | 1222 | fs_remount(RUN_XAUTHORITY_SEC_DIR, MOUNT_READONLY, 0); |
1223 | |||
1224 | // always mounting the new Xauthority file noexec,nodev,nosuid | ||
1225 | fs_remount(RUN_XAUTHORITY_SEC_DIR, MOUNT_NOEXEC, 0); | ||
1226 | |||
1227 | // get a file descriptor for the new Xauthority file | ||
1228 | int src = safe_fd(tmpfname, O_PATH|O_NOFOLLOW|O_CLOEXEC); | ||
1229 | if (src == -1) | ||
1230 | errExit("safe_fd"); | ||
1231 | if (fstat(src, &s) == -1) | ||
1232 | errExit("fstat"); | ||
1233 | if (!S_ISREG(s.st_mode)) { | ||
1234 | errno = EPERM; | ||
1235 | errExit("mounting Xauthority file"); | ||
1236 | } | ||
1281 | 1237 | ||
1282 | // mount via the link in /proc/self/fd | 1238 | // mount via the link in /proc/self/fd |
1283 | if (arg_debug) | 1239 | if (arg_debug) |
1284 | printf("Mounting %s on %s\n", RUN_XAUTHORITY_SEC_FILE, dest); | 1240 | printf("Mounting %s on %s\n", tmpfname, dest); |
1285 | char *proc; | 1241 | char *proc_src, *proc_dst; |
1286 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | 1242 | if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1) |
1243 | errExit("asprintf"); | ||
1244 | if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1) | ||
1287 | errExit("asprintf"); | 1245 | errExit("asprintf"); |
1288 | if (mount(RUN_XAUTHORITY_SEC_FILE, proc, "none", MS_BIND, "mode=0600") == -1) { | 1246 | if (mount(proc_src, proc_dst, NULL, MS_BIND, NULL) == -1) { |
1289 | fprintf(stderr, "Error: cannot mount the new .Xauthority file\n"); | 1247 | fprintf(stderr, "Error: cannot mount the new .Xauthority file\n"); |
1290 | exit(1); | 1248 | exit(1); |
1291 | } | 1249 | } |
1292 | free(proc); | ||
1293 | close(fd); | ||
1294 | // check /proc/self/mountinfo to confirm the mount is ok | 1250 | // check /proc/self/mountinfo to confirm the mount is ok |
1295 | MountData *mptr = get_last_mount(); | 1251 | MountData *mptr = get_last_mount(); |
1296 | if (strcmp(mptr->dir, dest) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) | 1252 | if (strcmp(mptr->dir, dest) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) |
1297 | errLogExit("invalid .Xauthority mount"); | 1253 | errLogExit("invalid .Xauthority mount"); |
1254 | free(proc_src); | ||
1255 | free(proc_dst); | ||
1256 | close(src); | ||
1257 | close(dst); | ||
1298 | 1258 | ||
1299 | ASSERT_PERMS(dest, getuid(), getgid(), 0600); | 1259 | ASSERT_PERMS(dest, getuid(), getgid(), 0600); |
1300 | 1260 | ||
1301 | // blacklist .Xauthority file if it is not masked already | 1261 | // blacklist user .Xauthority file if it is not masked already |
1302 | char *envar = getenv("XAUTHORITY"); | 1262 | char *envar = getenv("XAUTHORITY"); |
1303 | if (envar) { | 1263 | if (envar) { |
1304 | char *rp = realpath(envar, NULL); | 1264 | char *rp = realpath(envar, NULL); |
@@ -1312,6 +1272,11 @@ void x11_xorg(void) { | |||
1312 | if (setenv("XAUTHORITY", dest, 1) < 0) | 1272 | if (setenv("XAUTHORITY", dest, 1) < 0) |
1313 | errExit("setenv"); | 1273 | errExit("setenv"); |
1314 | free(dest); | 1274 | free(dest); |
1275 | |||
1276 | // mask RUN_XAUTHORITY_SEC_DIR | ||
1277 | if (mount("tmpfs", RUN_XAUTHORITY_SEC_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
1278 | errExit("mounting tmpfs"); | ||
1279 | fs_logger2("tmpfs", RUN_XAUTHORITY_SEC_DIR); | ||
1315 | #endif | 1280 | #endif |
1316 | } | 1281 | } |
1317 | 1282 | ||
diff --git a/src/fldd/main.c b/src/fldd/main.c index dd22e601e..d68504f6b 100644 --- a/src/fldd/main.c +++ b/src/fldd/main.c | |||
@@ -24,6 +24,7 @@ | |||
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> | ||
27 | #include <sys/stat.h> | 28 | #include <sys/stat.h> |
28 | #include <sys/types.h> | 29 | #include <sys/types.h> |
29 | #include <unistd.h> | 30 | #include <unistd.h> |
@@ -302,6 +303,11 @@ printf("\n"); | |||
302 | return 0; | 303 | return 0; |
303 | } | 304 | } |
304 | 305 | ||
306 | #ifdef 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 | |||
305 | // check program access | 311 | // check program access |
306 | if (access(argv[1], R_OK)) { | 312 | if (access(argv[1], R_OK)) { |
307 | fprintf(stderr, "Error fldd: cannot access %s\n", argv[1]); | 313 | fprintf(stderr, "Error fldd: cannot access %s\n", argv[1]); |
diff --git a/src/fnet/main.c b/src/fnet/main.c index 95e12164e..f6316a7fe 100644 --- a/src/fnet/main.c +++ b/src/fnet/main.c | |||
@@ -21,6 +21,7 @@ | |||
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> | ||
24 | 25 | ||
25 | int arg_quiet = 0; | 26 | int arg_quiet = 0; |
26 | 27 | ||
@@ -64,16 +65,19 @@ printf("\n"); | |||
64 | usage(); | 65 | usage(); |
65 | return 1; | 66 | return 1; |
66 | } | 67 | } |
67 | |||
68 | char *quiet = getenv("FIREJAIL_QUIET"); | ||
69 | if (quiet && strcmp(quiet, "yes") == 0) | ||
70 | arg_quiet = 1; | ||
71 | |||
72 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { | 68 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { |
73 | usage(); | 69 | usage(); |
74 | return 0; | 70 | return 0; |
75 | } | 71 | } |
76 | else if (argc == 3 && strcmp(argv[1], "ifup") == 0) { | 72 | #ifdef WARN_DUMPABLE |
73 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid()) | ||
74 | fprintf(stderr, "Error fnet: I am dumpable\n"); | ||
75 | #endif | ||
76 | char *quiet = getenv("FIREJAIL_QUIET"); | ||
77 | if (quiet && strcmp(quiet, "yes") == 0) | ||
78 | arg_quiet = 1; | ||
79 | |||
80 | if (argc == 3 && strcmp(argv[1], "ifup") == 0) { | ||
77 | net_if_up(argv[2]); | 81 | net_if_up(argv[2]); |
78 | } | 82 | } |
79 | else if (argc == 2 && strcmp(argv[1], "printif") == 0) { | 83 | else if (argc == 2 && strcmp(argv[1], "printif") == 0) { |
diff --git a/src/fnetfilter/main.c b/src/fnetfilter/main.c index 8124beb1a..1ca35ab56 100644 --- a/src/fnetfilter/main.c +++ b/src/fnetfilter/main.c | |||
@@ -18,6 +18,7 @@ | |||
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> | ||
21 | 22 | ||
22 | #define MAXBUF 4098 | 23 | #define MAXBUF 4098 |
23 | #define MAXARGS 16 | 24 | #define MAXARGS 16 |
@@ -180,7 +181,10 @@ printf("\n"); | |||
180 | usage(); | 181 | usage(); |
181 | return 1; | 182 | return 1; |
182 | } | 183 | } |
183 | 184 | #ifdef WARN_DUMPABLE | |
185 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid()) | ||
186 | fprintf(stderr, "Error fnetfilter: I am dumpable\n"); | ||
187 | #endif | ||
184 | char *destfile = (argc == 3)? argv[2]: argv[1]; | 188 | char *destfile = (argc == 3)? argv[2]: argv[1]; |
185 | char *command = (argc == 3)? argv[1]: NULL; | 189 | char *command = (argc == 3)? argv[1]: NULL; |
186 | //printf("command %s\n", command); | 190 | //printf("command %s\n", command); |
diff --git a/src/fsec-optimize/fsec_optimize.h b/src/fsec-optimize/fsec_optimize.h index 211111641..034fde2ac 100644 --- a/src/fsec-optimize/fsec_optimize.h +++ b/src/fsec-optimize/fsec_optimize.h | |||
@@ -22,6 +22,7 @@ | |||
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> | ||
25 | 26 | ||
26 | // optimize.c | 27 | // optimize.c |
27 | struct sock_filter *duplicate(struct sock_filter *filter, int entries); | 28 | 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 416d85b88..fb13eeca8 100644 --- a/src/fsec-optimize/main.c +++ b/src/fsec-optimize/main.c | |||
@@ -44,6 +44,12 @@ printf("\n"); | |||
44 | return 0; | 44 | return 0; |
45 | } | 45 | } |
46 | 46 | ||
47 | #ifdef WARN_DUMPABLE | ||
48 | // check FIREJAIL_PLUGIN in order to not print a warning during make | ||
49 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid() && getenv("FIREJAIL_PLUGIN")) | ||
50 | fprintf(stderr, "Error fsec-optimize: I am dumpable\n"); | ||
51 | #endif | ||
52 | |||
47 | char *fname = argv[1]; | 53 | char *fname = argv[1]; |
48 | 54 | ||
49 | // open input file | 55 | // open input file |
diff --git a/src/fsec-print/fsec_print.h b/src/fsec-print/fsec_print.h index 337199288..9d17e3f18 100644 --- a/src/fsec-print/fsec_print.h +++ b/src/fsec-print/fsec_print.h | |||
@@ -23,6 +23,7 @@ | |||
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> | ||
26 | 27 | ||
27 | // print.c | 28 | // print.c |
28 | void print(struct sock_filter *filter, int entries); | 29 | void print(struct sock_filter *filter, int entries); |
diff --git a/src/fsec-print/main.c b/src/fsec-print/main.c index ade45c881..d1f056e47 100644 --- a/src/fsec-print/main.c +++ b/src/fsec-print/main.c | |||
@@ -61,6 +61,11 @@ printf("\n"); | |||
61 | return 0; | 61 | return 0; |
62 | } | 62 | } |
63 | 63 | ||
64 | #ifdef 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 | |||
64 | char *fname = argv[1]; | 69 | char *fname = argv[1]; |
65 | 70 | ||
66 | // open input file | 71 | // open input file |
diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h index e8dd083b6..e40999938 100644 --- a/src/fseccomp/fseccomp.h +++ b/src/fseccomp/fseccomp.h | |||
@@ -23,6 +23,7 @@ | |||
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> | ||
26 | #include "../include/common.h" | 27 | #include "../include/common.h" |
27 | #include "../include/syscall.h" | 28 | #include "../include/syscall.h" |
28 | 29 | ||
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index 3b3c92b46..f505ca0f3 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c | |||
@@ -64,6 +64,16 @@ printf("\n"); | |||
64 | usage(); | 64 | usage(); |
65 | return 1; | 65 | return 1; |
66 | } | 66 | } |
67 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { | ||
68 | usage(); | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | #ifdef 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 | ||
67 | 77 | ||
68 | char *quiet = getenv("FIREJAIL_QUIET"); | 78 | char *quiet = getenv("FIREJAIL_QUIET"); |
69 | if (quiet && strcmp(quiet, "yes") == 0) | 79 | if (quiet && strcmp(quiet, "yes") == 0) |
@@ -83,11 +93,7 @@ printf("\n"); | |||
83 | } | 93 | } |
84 | } | 94 | } |
85 | 95 | ||
86 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { | 96 | if (argc == 2 && strcmp(argv[1], "debug-syscalls") == 0) |
87 | usage(); | ||
88 | return 0; | ||
89 | } | ||
90 | else if (argc == 2 && strcmp(argv[1], "debug-syscalls") == 0) | ||
91 | syscall_print(); | 97 | syscall_print(); |
92 | else if (argc == 2 && strcmp(argv[1], "debug-syscalls32") == 0) | 98 | else if (argc == 2 && strcmp(argv[1], "debug-syscalls32") == 0) |
93 | syscall_print_32(); | 99 | syscall_print_32(); |
diff --git a/src/include/common.h b/src/include/common.h index c65ba0d55..025f3c247 100644 --- a/src/include/common.h +++ b/src/include/common.h | |||
@@ -34,6 +34,9 @@ | |||
34 | 34 | ||
35 | #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) | 35 | #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) |
36 | 36 | ||
37 | // check if processes run with dumpable flag set | ||
38 | #define WARN_DUMPABLE | ||
39 | |||
37 | // macro to print ip addresses in a printf statement | 40 | // macro to print ip addresses in a printf statement |
38 | #define PRINT_IP(A) \ | 41 | #define PRINT_IP(A) \ |
39 | ((int) (((A) >> 24) & 0xFF)), ((int) (((A) >> 16) & 0xFF)), ((int) (((A) >> 8) & 0xFF)), ((int) ( (A) & 0xFF)) | 42 | ((int) (((A) >> 24) & 0xFF)), ((int) (((A) >> 16) & 0xFF)), ((int) (((A) >> 8) & 0xFF)), ((int) ( (A) & 0xFF)) |
diff --git a/src/include/rundefs.h b/src/include/rundefs.h index f8bcdec52..d56623907 100644 --- a/src/include/rundefs.h +++ b/src/include/rundefs.h | |||
@@ -99,8 +99,9 @@ | |||
99 | #define RUN_WHITELIST_SHARE_DIR RUN_MNT_DIR "/orig-share" | 99 | #define RUN_WHITELIST_SHARE_DIR RUN_MNT_DIR "/orig-share" |
100 | #define RUN_WHITELIST_MODULE_DIR RUN_MNT_DIR "/orig-module" | 100 | #define RUN_WHITELIST_MODULE_DIR RUN_MNT_DIR "/orig-module" |
101 | 101 | ||
102 | #define RUN_XAUTHORITY_FILE RUN_MNT_DIR "/.Xauthority" | 102 | #define RUN_XAUTHORITY_FILE RUN_MNT_DIR "/.Xauthority" // private options |
103 | #define RUN_XAUTHORITY_SEC_FILE RUN_MNT_DIR "/sec.Xauthority" | 103 | #define RUN_XAUTH_FILE RUN_MNT_DIR "/xauth" // x11=xorg |
104 | #define RUN_XAUTHORITY_SEC_DIR RUN_MNT_DIR "/.sec.Xauthority" // x11=xorg | ||
104 | #define RUN_ASOUNDRC_FILE RUN_MNT_DIR "/.asoundrc" | 105 | #define RUN_ASOUNDRC_FILE RUN_MNT_DIR "/.asoundrc" |
105 | #define RUN_HOSTNAME_FILE RUN_MNT_DIR "/hostname" | 106 | #define RUN_HOSTNAME_FILE RUN_MNT_DIR "/hostname" |
106 | #define RUN_HOSTS_FILE RUN_MNT_DIR "/hosts" | 107 | #define RUN_HOSTS_FILE RUN_MNT_DIR "/hosts" |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index e216531ae..3b7ba4e3d 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -273,6 +273,10 @@ $ firejail \-\-list | |||
273 | $ firejail \-\-caps.print=3272 | 273 | $ firejail \-\-caps.print=3272 |
274 | 274 | ||
275 | .TP | 275 | .TP |
276 | \fB\-\-cat=name|pid filename | ||
277 | Print content of file from sandbox container, see FILE TRANSFER section for more details. | ||
278 | |||
279 | .TP | ||
276 | \fB\-\-cgroup=tasks-file | 280 | \fB\-\-cgroup=tasks-file |
277 | Place the sandbox in the specified control group. tasks-file is the full path of cgroup tasks file. | 281 | Place the sandbox in the specified control group. tasks-file is the full path of cgroup tasks file. |
278 | .br | 282 | .br |
@@ -344,7 +348,7 @@ $ firejail --dbus-system=filter --dbus-system.log --dbus-log=dbus.txt | |||
344 | 348 | ||
345 | .TP | 349 | .TP |
346 | \fB\-\-dbus-system=filter|none | 350 | \fB\-\-dbus-system=filter|none |
347 | Set system DBus sandboxing policy. | 351 | Set system DBus sandboxing policy. |
348 | .br | 352 | .br |
349 | 353 | ||
350 | .br | 354 | .br |
@@ -3031,6 +3035,12 @@ These features allow the user to inspect the filesystem container of an existing | |||
3031 | and transfer files between the container and the host filesystem. | 3035 | and transfer files between the container and the host filesystem. |
3032 | 3036 | ||
3033 | .TP | 3037 | .TP |
3038 | \fB\-\-cat=name|pid filename | ||
3039 | Write content of a container file to standard out. The container is specified by name or PID. | ||
3040 | If standard out is a terminal, all ASCII control characters except new line and horizontal tab | ||
3041 | are replaced. | ||
3042 | |||
3043 | .TP | ||
3034 | \fB\-\-get=name|pid filename | 3044 | \fB\-\-get=name|pid filename |
3035 | Retrieve the container file and store it on the host in the current working directory. | 3045 | Retrieve the container file and store it on the host in the current working directory. |
3036 | The container is specified by name or PID. | 3046 | The container is specified by name or PID. |
@@ -3074,6 +3084,10 @@ $ firejail \-\-get=mybrowser ~/Downloads/xpra-clipboard.png | |||
3074 | $ firejail \-\-put=mybrowser xpra-clipboard.png ~/Downloads/xpra-clipboard.png | 3084 | $ firejail \-\-put=mybrowser xpra-clipboard.png ~/Downloads/xpra-clipboard.png |
3075 | .br | 3085 | .br |
3076 | 3086 | ||
3087 | .br | ||
3088 | $ firejail \-\-cat=mybrowser ~/.bashrc | ||
3089 | .br | ||
3090 | |||
3077 | .SH MONITORING | 3091 | .SH MONITORING |
3078 | Option \-\-list prints a list of all sandboxes. The format | 3092 | Option \-\-list prints a list of all sandboxes. The format |
3079 | for each process entry is as follows: | 3093 | for each process entry is as follows: |
@@ -3261,7 +3275,7 @@ Homepage: https://firejail.wordpress.com | |||
3261 | \&\flfirejail-profile\fR\|(5), | 3275 | \&\flfirejail-profile\fR\|(5), |
3262 | \&\flfirejail-login\fR\|(5), | 3276 | \&\flfirejail-login\fR\|(5), |
3263 | \&\flfirejail-users\fR\|(5), | 3277 | \&\flfirejail-users\fR\|(5), |
3264 | .UR https://github.com/netblue30/firejail/wiki | 3278 | .UR https://github.com/netblue30/firejail/wiki |
3265 | .UE , | 3279 | .UE , |
3266 | .UR https://github.com/netblue30/firejail | 3280 | .UR https://github.com/netblue30/firejail |
3267 | .UE | 3281 | .UE |