diff options
-rw-r--r-- | Makefile.in | 5 | ||||
-rwxr-xr-x | configure | 3 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/firejail/firejail.h | 4 | ||||
-rw-r--r-- | src/firejail/fs_trace.c | 5 | ||||
-rw-r--r-- | src/firejail/main.c | 1 | ||||
-rw-r--r-- | src/firejail/preproc.c | 5 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 13 | ||||
-rw-r--r-- | src/firejail/seccomp.c | 34 | ||||
-rw-r--r-- | src/fseccomp/fseccomp.h | 15 | ||||
-rw-r--r-- | src/fseccomp/main.c | 30 | ||||
-rw-r--r-- | src/fseccomp/seccomp.c | 118 | ||||
-rw-r--r-- | src/fseccomp/seccomp_file.c | 9 | ||||
-rw-r--r-- | src/fseccomp/syscall.c | 64 | ||||
-rw-r--r-- | src/libpostexecseccomp/Makefile.in | 26 | ||||
-rw-r--r-- | src/libpostexecseccomp/libpostexecseccomp.c | 59 | ||||
-rw-r--r-- | src/libpostexecseccomp/libpostexecseccomp.h | 25 | ||||
-rw-r--r-- | src/man/firejail.txt | 26 |
18 files changed, 369 insertions, 75 deletions
diff --git a/Makefile.in b/Makefile.in index 6d8bf5f72..d9d7bcd37 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -1,6 +1,6 @@ | |||
1 | all: apps man filters | 1 | all: apps man filters |
2 | MYLIBS = src/lib | 2 | MYLIBS = src/lib |
3 | APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/fnet src/fseccomp src/fcopy src/fldd | 3 | APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/fnet src/fseccomp src/fcopy src/fldd src/libpostexecseccomp |
4 | MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 | 4 | MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 |
5 | SECCOMP_FILTERS = seccomp seccomp.i386 seccomp.amd64 | 5 | SECCOMP_FILTERS = seccomp seccomp.i386 seccomp.amd64 |
6 | 6 | ||
@@ -85,6 +85,7 @@ realinstall: | |||
85 | install -m 0755 -d $(DESTDIR)/$(libdir)/firejail | 85 | install -m 0755 -d $(DESTDIR)/$(libdir)/firejail |
86 | install -c -m 0644 src/libtrace/libtrace.so $(DESTDIR)/$(libdir)/firejail/. | 86 | install -c -m 0644 src/libtrace/libtrace.so $(DESTDIR)/$(libdir)/firejail/. |
87 | install -c -m 0644 src/libtracelog/libtracelog.so $(DESTDIR)/$(libdir)/firejail/. | 87 | install -c -m 0644 src/libtracelog/libtracelog.so $(DESTDIR)/$(libdir)/firejail/. |
88 | install -c -m 0644 src/libpostexecseccomp/libpostexecseccomp.so $(DESTDIR)/$(libdir)/firejail/. | ||
88 | install -c -m 0755 src/ftee/ftee $(DESTDIR)/$(libdir)/firejail/. | 89 | install -c -m 0755 src/ftee/ftee $(DESTDIR)/$(libdir)/firejail/. |
89 | install -c -m 0755 src/fshaper/fshaper.sh $(DESTDIR)/$(libdir)/firejail/. | 90 | install -c -m 0755 src/fshaper/fshaper.sh $(DESTDIR)/$(libdir)/firejail/. |
90 | ifeq ($(HAVE_GIT_INSTALL),-DHAVE_GIT_INSTALL) | 91 | ifeq ($(HAVE_GIT_INSTALL),-DHAVE_GIT_INSTALL) |
@@ -159,11 +160,13 @@ install-strip: all | |||
159 | strip src/firecfg/firecfg | 160 | strip src/firecfg/firecfg |
160 | strip src/libtrace/libtrace.so | 161 | strip src/libtrace/libtrace.so |
161 | strip src/libtracelog/libtracelog.so | 162 | strip src/libtracelog/libtracelog.so |
163 | strip src/libpostexecseccomp/libpostexecseccomp.so | ||
162 | strip src/ftee/ftee | 164 | strip src/ftee/ftee |
163 | strip src/faudit/faudit | 165 | strip src/faudit/faudit |
164 | strip src/fnet/fnet | 166 | strip src/fnet/fnet |
165 | strip src/fseccomp/fseccomp | 167 | strip src/fseccomp/fseccomp |
166 | strip src/fcopy/fcopy | 168 | strip src/fcopy/fcopy |
169 | strip src/fldd/fldd | ||
167 | $(MAKE) realinstall | 170 | $(MAKE) realinstall |
168 | 171 | ||
169 | uninstall: | 172 | uninstall: |
@@ -3823,7 +3823,7 @@ if test "$prefix" = /usr; then | |||
3823 | sysconfdir="/etc" | 3823 | sysconfdir="/etc" |
3824 | fi | 3824 | fi |
3825 | 3825 | ||
3826 | ac_config_files="$ac_config_files Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/fseccomp/Makefile src/fldd/Makefile" | 3826 | ac_config_files="$ac_config_files Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/fseccomp/Makefile src/fldd/Makefile src/libpostexecseccomp/Makefile" |
3827 | 3827 | ||
3828 | cat >confcache <<\_ACEOF | 3828 | cat >confcache <<\_ACEOF |
3829 | # This file is a shell script that caches the results of configure | 3829 | # This file is a shell script that caches the results of configure |
@@ -4545,6 +4545,7 @@ do | |||
4545 | "src/faudit/Makefile") CONFIG_FILES="$CONFIG_FILES src/faudit/Makefile" ;; | 4545 | "src/faudit/Makefile") CONFIG_FILES="$CONFIG_FILES src/faudit/Makefile" ;; |
4546 | "src/fseccomp/Makefile") CONFIG_FILES="$CONFIG_FILES src/fseccomp/Makefile" ;; | 4546 | "src/fseccomp/Makefile") CONFIG_FILES="$CONFIG_FILES src/fseccomp/Makefile" ;; |
4547 | "src/fldd/Makefile") CONFIG_FILES="$CONFIG_FILES src/fldd/Makefile" ;; | 4547 | "src/fldd/Makefile") CONFIG_FILES="$CONFIG_FILES src/fldd/Makefile" ;; |
4548 | "src/libpostexecseccomp/Makefile") CONFIG_FILES="$CONFIG_FILES src/libpostexecseccomp/Makefile" ;; | ||
4548 | 4549 | ||
4549 | *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; | 4550 | *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; |
4550 | esac | 4551 | esac |
diff --git a/configure.ac b/configure.ac index 09fc3f587..8552c48eb 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -177,7 +177,7 @@ fi | |||
177 | 177 | ||
178 | AC_OUTPUT(Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile \ | 178 | AC_OUTPUT(Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile \ |
179 | src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile \ | 179 | src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile \ |
180 | src/ftee/Makefile src/faudit/Makefile src/fseccomp/Makefile src/fldd/Makefile) | 180 | src/ftee/Makefile src/faudit/Makefile src/fseccomp/Makefile src/fldd/Makefile src/libpostexecseccomp/Makefile) |
181 | 181 | ||
182 | echo | 182 | echo |
183 | echo "Configuration options:" | 183 | echo "Configuration options:" |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index b19aded44..5f16d1a5d 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -57,6 +57,7 @@ | |||
57 | #define RUN_SECCOMP_AMD64 "/run/firejail/mnt/seccomp.amd64" // amd64 filter installed on i386 architectures | 57 | #define RUN_SECCOMP_AMD64 "/run/firejail/mnt/seccomp.amd64" // amd64 filter installed on i386 architectures |
58 | #define RUN_SECCOMP_I386 "/run/firejail/mnt/seccomp.i386" // i386 filter installed on amd64 architectures | 58 | #define RUN_SECCOMP_I386 "/run/firejail/mnt/seccomp.i386" // i386 filter installed on amd64 architectures |
59 | #define RUN_SECCOMP_MDWX "/run/firejail/mnt/seccomp.mdwx" // filter for memory-deny-write-execute | 59 | #define RUN_SECCOMP_MDWX "/run/firejail/mnt/seccomp.mdwx" // filter for memory-deny-write-execute |
60 | #define RUN_SECCOMP_POSTEXEC "/run/firejail/mnt/seccomp.postexec" // filter for post-exec library | ||
60 | #define PATH_SECCOMP_DEFAULT (LIBDIR "/firejail/seccomp") // default filter built during make | 61 | #define PATH_SECCOMP_DEFAULT (LIBDIR "/firejail/seccomp") // default filter built during make |
61 | #define PATH_SECCOMP_DEFAULT_DEBUG (LIBDIR "/firejail/seccomp.debug") // default filter built during make | 62 | #define PATH_SECCOMP_DEFAULT_DEBUG (LIBDIR "/firejail/seccomp.debug") // default filter built during make |
62 | #define PATH_SECCOMP_AMD64 (LIBDIR "/firejail/seccomp.amd64") // amd64 filter built during make | 63 | #define PATH_SECCOMP_AMD64 (LIBDIR "/firejail/seccomp.amd64") // amd64 filter built during make |
@@ -305,6 +306,7 @@ extern int arg_overlay_keep; // place overlay diff in a known directory | |||
305 | extern int arg_overlay_reuse; // allow the reuse of overlays | 306 | extern int arg_overlay_reuse; // allow the reuse of overlays |
306 | 307 | ||
307 | extern int arg_seccomp; // enable default seccomp filter | 308 | extern int arg_seccomp; // enable default seccomp filter |
309 | extern int arg_seccomp_postexec; // need postexec ld.preload library? | ||
308 | 310 | ||
309 | extern int arg_caps_default_filter; // enable default capabilities filter | 311 | extern int arg_caps_default_filter; // enable default capabilities filter |
310 | extern int arg_caps_drop; // drop list | 312 | extern int arg_caps_drop; // drop list |
@@ -553,8 +555,6 @@ void caps_drop_dac_override(void); | |||
553 | 555 | ||
554 | // syscall.c | 556 | // syscall.c |
555 | const char *syscall_find_nr(int nr); | 557 | const char *syscall_find_nr(int nr); |
556 | // return -1 if error, 0 if no error | ||
557 | int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg); | ||
558 | 558 | ||
559 | // fs_trace.c | 559 | // fs_trace.c |
560 | void fs_trace_preload(void); | 560 | void fs_trace_preload(void); |
diff --git a/src/firejail/fs_trace.c b/src/firejail/fs_trace.c index df76f4fe1..c87d29b5c 100644 --- a/src/firejail/fs_trace.c +++ b/src/firejail/fs_trace.c | |||
@@ -63,6 +63,11 @@ void fs_trace(void) { | |||
63 | if (!arg_quiet) | 63 | if (!arg_quiet) |
64 | printf("Blacklist violations are logged to syslog\n"); | 64 | printf("Blacklist violations are logged to syslog\n"); |
65 | } | 65 | } |
66 | if (arg_seccomp_postexec) { | ||
67 | fprintf(fp, "%s/libpostexecseccomp.so\n", prefix); | ||
68 | if (!arg_quiet) | ||
69 | printf("Post-exec seccomp protector enabled\n"); | ||
70 | } | ||
66 | 71 | ||
67 | SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 72 | SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); |
68 | fclose(fp); | 73 | fclose(fp); |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 407902676..9726c0b8a 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -56,6 +56,7 @@ int arg_overlay_keep = 0; // place overlay diff in a known directory | |||
56 | int arg_overlay_reuse = 0; // allow the reuse of overlays | 56 | int arg_overlay_reuse = 0; // allow the reuse of overlays |
57 | 57 | ||
58 | int arg_seccomp = 0; // enable default seccomp filter | 58 | int arg_seccomp = 0; // enable default seccomp filter |
59 | int arg_seccomp_postexec = 0; // need postexec ld.preload library? | ||
59 | 60 | ||
60 | int arg_caps_default_filter = 0; // enable default capabilities filter | 61 | int arg_caps_default_filter = 0; // enable default capabilities filter |
61 | int arg_caps_drop = 0; // drop list | 62 | int arg_caps_drop = 0; // drop list |
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c index 9c474415d..583cc4610 100644 --- a/src/firejail/preproc.c +++ b/src/firejail/preproc.c | |||
@@ -85,9 +85,12 @@ void preproc_mount_mnt_dir(void) { | |||
85 | 85 | ||
86 | if (arg_memory_deny_write_execute) | 86 | if (arg_memory_deny_write_execute) |
87 | copy_file(PATH_SECCOMP_MDWX, RUN_SECCOMP_MDWX, getuid(), getgid(), 0644); // root needed | 87 | copy_file(PATH_SECCOMP_MDWX, RUN_SECCOMP_MDWX, getuid(), getgid(), 0644); // root needed |
88 | // as root, create an empty RUN_SECCOMP_PROTOCOL file | 88 | // as root, create empty RUN_SECCOMP_PROTOCOL and RUN_SECCOMP_POSTEXEC files |
89 | create_empty_file_as_root(RUN_SECCOMP_PROTOCOL, 0644); | 89 | create_empty_file_as_root(RUN_SECCOMP_PROTOCOL, 0644); |
90 | if (set_perms(RUN_SECCOMP_PROTOCOL, getuid(), getgid(), 0644)) | 90 | if (set_perms(RUN_SECCOMP_PROTOCOL, getuid(), getgid(), 0644)) |
91 | errExit("set_perms"); | 91 | errExit("set_perms"); |
92 | create_empty_file_as_root(RUN_SECCOMP_POSTEXEC, 0644); | ||
93 | if (set_perms(RUN_SECCOMP_POSTEXEC, getuid(), getgid(), 0644)) | ||
94 | errExit("set_perms"); | ||
92 | } | 95 | } |
93 | } | 96 | } |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 472f09355..568549cbf 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -664,10 +664,15 @@ int sandbox(void* sandbox_arg) { | |||
664 | if (rv) | 664 | if (rv) |
665 | exit(rv); | 665 | exit(rv); |
666 | } | 666 | } |
667 | if (arg_seccomp && (cfg.seccomp_list || cfg.seccomp_list_drop || cfg.seccomp_list_keep)) | ||
668 | arg_seccomp_postexec = 1; | ||
667 | #endif | 669 | #endif |
668 | 670 | ||
671 | // need ld.so.preload if tracing or seccomp with any non-default lists | ||
672 | bool need_preload = arg_trace || arg_tracelog || arg_seccomp_postexec; | ||
673 | |||
669 | // trace pre-install | 674 | // trace pre-install |
670 | if (arg_trace || arg_tracelog) | 675 | if (need_preload) |
671 | fs_trace_preload(); | 676 | fs_trace_preload(); |
672 | 677 | ||
673 | // store hosts file | 678 | // store hosts file |
@@ -704,7 +709,7 @@ int sandbox(void* sandbox_arg) { | |||
704 | //**************************** | 709 | //**************************** |
705 | // trace pre-install, this time inside chroot | 710 | // trace pre-install, this time inside chroot |
706 | //**************************** | 711 | //**************************** |
707 | if (arg_trace || arg_tracelog) | 712 | if (need_preload) |
708 | fs_trace_preload(); | 713 | fs_trace_preload(); |
709 | } | 714 | } |
710 | else | 715 | else |
@@ -767,7 +772,7 @@ int sandbox(void* sandbox_arg) { | |||
767 | else { | 772 | else { |
768 | fs_private_dir_list("/etc", RUN_ETC_DIR, cfg.etc_private_keep); | 773 | fs_private_dir_list("/etc", RUN_ETC_DIR, cfg.etc_private_keep); |
769 | // create /etc/ld.so.preload file again | 774 | // create /etc/ld.so.preload file again |
770 | if (arg_trace || arg_tracelog) | 775 | if (need_preload) |
771 | fs_trace_preload(); | 776 | fs_trace_preload(); |
772 | } | 777 | } |
773 | } | 778 | } |
@@ -903,7 +908,7 @@ int sandbox(void* sandbox_arg) { | |||
903 | //**************************** | 908 | //**************************** |
904 | // install trace | 909 | // install trace |
905 | //**************************** | 910 | //**************************** |
906 | if (arg_trace || arg_tracelog) | 911 | if (need_preload) |
907 | fs_trace(); | 912 | fs_trace(); |
908 | 913 | ||
909 | //**************************** | 914 | //**************************** |
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index 7cbd79d6b..516c97fa0 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c | |||
@@ -145,11 +145,11 @@ int seccomp_filter_drop(int enforce_seccomp) { | |||
145 | // build the seccomp filter as a regular user | 145 | // build the seccomp filter as a regular user |
146 | int rv; | 146 | int rv; |
147 | if (arg_allow_debuggers) | 147 | if (arg_allow_debuggers) |
148 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 6, | 148 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, |
149 | PATH_FSECCOMP, "default", "drop", RUN_SECCOMP_CFG, cfg.seccomp_list, "allow-debuggers"); | 149 | PATH_FSECCOMP, "default", "drop", RUN_SECCOMP_CFG, RUN_SECCOMP_POSTEXEC, cfg.seccomp_list, "allow-debuggers"); |
150 | else | 150 | else |
151 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5, | 151 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 6, |
152 | PATH_FSECCOMP, "default", "drop", RUN_SECCOMP_CFG, cfg.seccomp_list); | 152 | PATH_FSECCOMP, "default", "drop", RUN_SECCOMP_CFG, RUN_SECCOMP_POSTEXEC, cfg.seccomp_list); |
153 | if (rv) | 153 | if (rv) |
154 | exit(rv); | 154 | exit(rv); |
155 | } | 155 | } |
@@ -163,11 +163,11 @@ int seccomp_filter_drop(int enforce_seccomp) { | |||
163 | // build the seccomp filter as a regular user | 163 | // build the seccomp filter as a regular user |
164 | int rv; | 164 | int rv; |
165 | if (arg_allow_debuggers) | 165 | if (arg_allow_debuggers) |
166 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5, | 166 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 6, |
167 | PATH_FSECCOMP, "drop", RUN_SECCOMP_CFG, cfg.seccomp_list_drop, "allow-debuggers"); | 167 | PATH_FSECCOMP, "drop", RUN_SECCOMP_CFG, RUN_SECCOMP_POSTEXEC, cfg.seccomp_list_drop, "allow-debuggers"); |
168 | else | 168 | else |
169 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, | 169 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5, |
170 | PATH_FSECCOMP, "drop", RUN_SECCOMP_CFG, cfg.seccomp_list_drop); | 170 | PATH_FSECCOMP, "drop", RUN_SECCOMP_CFG, RUN_SECCOMP_POSTEXEC, cfg.seccomp_list_drop); |
171 | 171 | ||
172 | if (rv) | 172 | if (rv) |
173 | exit(rv); | 173 | exit(rv); |
@@ -183,9 +183,14 @@ int seccomp_filter_drop(int enforce_seccomp) { | |||
183 | exit(1); | 183 | exit(1); |
184 | } | 184 | } |
185 | 185 | ||
186 | if (arg_debug && access(PATH_FSECCOMP, X_OK) == 0) | 186 | if (arg_debug && access(PATH_FSECCOMP, X_OK) == 0) { |
187 | sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, | 187 | sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, |
188 | PATH_FSECCOMP, "print", RUN_SECCOMP_CFG); | 188 | PATH_FSECCOMP, "print", RUN_SECCOMP_CFG); |
189 | struct stat st; | ||
190 | if (stat(RUN_SECCOMP_POSTEXEC, &st) != -1 && st.st_size != 0) | ||
191 | sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, | ||
192 | PATH_FSECCOMP, "print", RUN_SECCOMP_POSTEXEC); | ||
193 | } | ||
189 | 194 | ||
190 | return 0; | 195 | return 0; |
191 | } | 196 | } |
@@ -196,14 +201,19 @@ int seccomp_filter_keep(void) { | |||
196 | printf("Build drop seccomp filter\n"); | 201 | printf("Build drop seccomp filter\n"); |
197 | 202 | ||
198 | // build the seccomp filter as a regular user | 203 | // build the seccomp filter as a regular user |
199 | sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, | 204 | sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5, |
200 | PATH_FSECCOMP, "keep", RUN_SECCOMP_CFG, cfg.seccomp_list_keep); | 205 | PATH_FSECCOMP, "keep", RUN_SECCOMP_CFG, RUN_SECCOMP_POSTEXEC, cfg.seccomp_list_keep); |
201 | if (arg_debug) | 206 | if (arg_debug) |
202 | printf("seccomp filter configured\n"); | 207 | printf("seccomp filter configured\n"); |
203 | 208 | ||
204 | 209 | ||
205 | if (arg_debug && access(PATH_FSECCOMP, X_OK) == 0) | 210 | if (arg_debug && access(PATH_FSECCOMP, X_OK) == 0) { |
206 | sbox_run(SBOX_ROOT | SBOX_SECCOMP, 3, PATH_FSECCOMP, "print", RUN_SECCOMP_CFG); | 211 | sbox_run(SBOX_ROOT | SBOX_SECCOMP, 3, PATH_FSECCOMP, "print", RUN_SECCOMP_CFG); |
212 | struct stat st; | ||
213 | if (stat(RUN_SECCOMP_POSTEXEC, &st) != -1 && st.st_size != 0) | ||
214 | sbox_run(SBOX_ROOT | SBOX_SECCOMP, 3, PATH_FSECCOMP, "print", RUN_SECCOMP_POSTEXEC); | ||
215 | } | ||
216 | |||
207 | return seccomp_load(RUN_SECCOMP_CFG); | 217 | return seccomp_load(RUN_SECCOMP_CFG); |
208 | } | 218 | } |
209 | 219 | ||
diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h index 0db670380..144b612ae 100644 --- a/src/fseccomp/fseccomp.h +++ b/src/fseccomp/fseccomp.h | |||
@@ -30,8 +30,9 @@ extern int arg_quiet; | |||
30 | 30 | ||
31 | // syscall.c | 31 | // syscall.c |
32 | void syscall_print(void); | 32 | void syscall_print(void); |
33 | int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg), int fd, int arg); | 33 | int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg, void *ptrarg), int fd, int arg, void *ptrarg); |
34 | const char *syscall_find_nr(int nr); | 34 | const char *syscall_find_nr(int nr); |
35 | void syscalls_in_list(const char *list, const char *slist, int fd, char **prelist, char **postlist); | ||
35 | 36 | ||
36 | // errno.c | 37 | // errno.c |
37 | void errno_print(void); | 38 | void errno_print(void); |
@@ -49,9 +50,9 @@ void seccomp_secondary_32(const char *fname); | |||
49 | // seccomp_file.c | 50 | // seccomp_file.c |
50 | void write_to_file(int fd, const void *data, int size); | 51 | void write_to_file(int fd, const void *data, int size); |
51 | void filter_init(int fd); | 52 | void filter_init(int fd); |
52 | void filter_add_whitelist(int fd, int syscall, int arg); | 53 | void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg); |
53 | void filter_add_blacklist(int fd, int syscall, int arg); | 54 | void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg); |
54 | void filter_add_errno(int fd, int syscall, int arg); | 55 | void filter_add_errno(int fd, int syscall, int arg, void *ptrarg); |
55 | void filter_end_blacklist(int fd); | 56 | void filter_end_blacklist(int fd); |
56 | void filter_end_whitelist(int fd); | 57 | void filter_end_whitelist(int fd); |
57 | 58 | ||
@@ -59,11 +60,11 @@ void filter_end_whitelist(int fd); | |||
59 | // default list | 60 | // default list |
60 | void seccomp_default(const char *fname, int allow_debuggers); | 61 | void seccomp_default(const char *fname, int allow_debuggers); |
61 | // drop list | 62 | // drop list |
62 | void seccomp_drop(const char *fname, char *list, int allow_debuggers); | 63 | void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers); |
63 | // default+drop list | 64 | // default+drop list |
64 | void seccomp_default_drop(const char *fname, char *list, int allow_debuggers); | 65 | void seccomp_default_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers); |
65 | // whitelisted filter | 66 | // whitelisted filter |
66 | void seccomp_keep(const char *fname, char *list); | 67 | void seccomp_keep(const char *fname1, const char *fname2, char *list); |
67 | // block writable and executable memory | 68 | // block writable and executable memory |
68 | void memory_deny_write_execute(const char *fname); | 69 | void memory_deny_write_execute(const char *fname); |
69 | 70 | ||
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index 3d95d5bb2..3bf7de0fa 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c | |||
@@ -30,11 +30,11 @@ static void usage(void) { | |||
30 | printf("\tfseccomp secondary 32 file\n"); | 30 | printf("\tfseccomp secondary 32 file\n"); |
31 | printf("\tfseccomp default file\n"); | 31 | printf("\tfseccomp default file\n"); |
32 | printf("\tfseccomp default file allow-debuggers\n"); | 32 | printf("\tfseccomp default file allow-debuggers\n"); |
33 | printf("\tfseccomp drop file list\n"); | 33 | printf("\tfseccomp drop file1 file2 list\n"); |
34 | printf("\tfseccomp drop file list allow-debuggers\n"); | 34 | printf("\tfseccomp drop file1 file2 list allow-debuggers\n"); |
35 | printf("\tfseccomp default drop file list\n"); | 35 | printf("\tfseccomp default drop file1 file2 list\n"); |
36 | printf("\tfseccomp default drop file list allow-debuggers\n"); | 36 | printf("\tfseccomp default drop file1 file2 list allow-debuggers\n"); |
37 | printf("\tfseccomp keep file list\n"); | 37 | printf("\tfseccomp keep file1 file2 list\n"); |
38 | printf("\tfseccomp memory-deny-write-execute file\n"); | 38 | printf("\tfseccomp memory-deny-write-execute file\n"); |
39 | printf("\tfseccomp print file\n"); | 39 | printf("\tfseccomp print file\n"); |
40 | } | 40 | } |
@@ -78,16 +78,16 @@ printf("\n"); | |||
78 | seccomp_default(argv[2], 0); | 78 | seccomp_default(argv[2], 0); |
79 | else if (argc == 4 && strcmp(argv[1], "default") == 0 && strcmp(argv[3], "allow-debuggers") == 0) | 79 | else if (argc == 4 && strcmp(argv[1], "default") == 0 && strcmp(argv[3], "allow-debuggers") == 0) |
80 | seccomp_default(argv[2], 1); | 80 | seccomp_default(argv[2], 1); |
81 | else if (argc == 4 && strcmp(argv[1], "drop") == 0) | 81 | else if (argc == 5 && strcmp(argv[1], "drop") == 0) |
82 | seccomp_drop(argv[2], argv[3], 0); | 82 | seccomp_drop(argv[2], argv[3], argv[4], 0); |
83 | else if (argc == 5 && strcmp(argv[1], "drop") == 0 && strcmp(argv[4], "allow-debuggers") == 0) | 83 | else if (argc == 6 && strcmp(argv[1], "drop") == 0 && strcmp(argv[5], "allow-debuggers") == 0) |
84 | seccomp_drop(argv[2], argv[3], 1); | 84 | seccomp_drop(argv[2], argv[3], argv[4], 1); |
85 | else if (argc == 5 && strcmp(argv[1], "default") == 0 && strcmp(argv[2], "drop") == 0) | 85 | else if (argc == 6 && strcmp(argv[1], "default") == 0 && strcmp(argv[2], "drop") == 0) |
86 | seccomp_default_drop(argv[3], argv[4], 0); | 86 | seccomp_default_drop(argv[3], argv[4], argv[5], 0); |
87 | else if (argc == 6 && strcmp(argv[1], "default") == 0 && strcmp(argv[2], "drop") == 0 && strcmp(argv[5], "allow-debuggers") == 0) | 87 | else if (argc == 7 && strcmp(argv[1], "default") == 0 && strcmp(argv[2], "drop") == 0 && strcmp(argv[6], "allow-debuggers") == 0) |
88 | seccomp_default_drop(argv[3], argv[4], 1); | 88 | seccomp_default_drop(argv[3], argv[4], argv[5], 1); |
89 | else if (argc == 4 && strcmp(argv[1], "keep") == 0) | 89 | else if (argc == 5 && strcmp(argv[1], "keep") == 0) |
90 | seccomp_keep(argv[2], argv[3]); | 90 | seccomp_keep(argv[2], argv[3], argv[4]); |
91 | else if (argc == 3 && strcmp(argv[1], "memory-deny-write-execute") == 0) | 91 | else if (argc == 3 && strcmp(argv[1], "memory-deny-write-execute") == 0) |
92 | memory_deny_write_execute(argv[2]); | 92 | memory_deny_write_execute(argv[2]); |
93 | else if (argc == 3 && strcmp(argv[1], "print") == 0) | 93 | else if (argc == 3 && strcmp(argv[1], "print") == 0) |
diff --git a/src/fseccomp/seccomp.c b/src/fseccomp/seccomp.c index a3db46aad..577f3fdc9 100644 --- a/src/fseccomp/seccomp.c +++ b/src/fseccomp/seccomp.c | |||
@@ -27,9 +27,9 @@ | |||
27 | static void add_default_list(int fd, int allow_debuggers) { | 27 | static void add_default_list(int fd, int allow_debuggers) { |
28 | int r; | 28 | int r; |
29 | if (!allow_debuggers) | 29 | if (!allow_debuggers) |
30 | r = syscall_check_list("@default-nodebuggers", filter_add_blacklist, fd, 0); | 30 | r = syscall_check_list("@default-nodebuggers", filter_add_blacklist, fd, 0, NULL); |
31 | else | 31 | else |
32 | r = syscall_check_list("@default", filter_add_blacklist, fd, 0); | 32 | r = syscall_check_list("@default", filter_add_blacklist, fd, 0, NULL); |
33 | 33 | ||
34 | assert(r == 0); | 34 | assert(r == 0); |
35 | //#ifdef SYS_mknod - emoved in 0.9.29 - it breaks Zotero extension | 35 | //#ifdef SYS_mknod - emoved in 0.9.29 - it breaks Zotero extension |
@@ -56,7 +56,7 @@ void seccomp_default(const char *fname, int allow_debuggers) { | |||
56 | exit(1); | 56 | exit(1); |
57 | } | 57 | } |
58 | 58 | ||
59 | // build filter | 59 | // build filter (no post-exec filter needed because default list is fine for us) |
60 | filter_init(fd); | 60 | filter_init(fd); |
61 | add_default_list(fd, allow_debuggers); | 61 | add_default_list(fd, allow_debuggers); |
62 | filter_end_blacklist(fd); | 62 | filter_end_blacklist(fd); |
@@ -66,44 +66,94 @@ void seccomp_default(const char *fname, int allow_debuggers) { | |||
66 | } | 66 | } |
67 | 67 | ||
68 | // drop list | 68 | // drop list |
69 | void seccomp_drop(const char *fname, char *list, int allow_debuggers) { | 69 | void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers) { |
70 | assert(fname); | 70 | assert(fname1); |
71 | assert(fname2); | ||
71 | (void) allow_debuggers; // todo: to implemnet it | 72 | (void) allow_debuggers; // todo: to implemnet it |
72 | 73 | ||
73 | // open file | 74 | // open file for pre-exec filter |
74 | int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | 75 | int fd = open(fname1, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
75 | if (fd < 0) { | 76 | if (fd < 0) { |
76 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); | 77 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname1); |
77 | exit(1); | 78 | exit(1); |
78 | } | 79 | } |
79 | 80 | ||
80 | // build filter | 81 | // build pre-exec filter: don't blacklist any syscalls in @default-keep |
82 | filter_init(fd); | ||
83 | char *prelist, *postlist; | ||
84 | syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist); | ||
85 | if (prelist) | ||
86 | if (syscall_check_list(prelist, filter_add_blacklist, fd, 0, NULL)) { | ||
87 | fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); | ||
88 | exit(1); | ||
89 | } | ||
90 | filter_end_whitelist(fd); | ||
91 | // close file | ||
92 | close(fd); | ||
93 | |||
94 | if (!postlist) | ||
95 | return; | ||
96 | |||
97 | // open file for post-exec filter | ||
98 | fd = open(fname2, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
99 | if (fd < 0) { | ||
100 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname2); | ||
101 | exit(1); | ||
102 | } | ||
103 | |||
104 | // build post-exec filter: blacklist remaining syscalls | ||
81 | filter_init(fd); | 105 | filter_init(fd); |
82 | if (syscall_check_list(list, filter_add_blacklist, fd, 0)) { | 106 | if (syscall_check_list(postlist, filter_add_blacklist, fd, 0, NULL)) { |
83 | fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); | 107 | fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); |
84 | exit(1); | 108 | exit(1); |
85 | } | 109 | } |
86 | filter_end_blacklist(fd); | 110 | filter_end_whitelist(fd); |
87 | 111 | ||
88 | // close file | 112 | // close file |
89 | close(fd); | 113 | close(fd); |
90 | } | 114 | } |
91 | 115 | ||
92 | // default+drop | 116 | // default+drop |
93 | void seccomp_default_drop(const char *fname, char *list, int allow_debuggers) { | 117 | void seccomp_default_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers) { |
94 | assert(fname); | 118 | assert(fname1); |
119 | assert(fname2); | ||
95 | 120 | ||
96 | // open file | 121 | // open file |
97 | int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | 122 | int fd = open(fname1, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
98 | if (fd < 0) { | 123 | if (fd < 0) { |
99 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); | 124 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname1); |
100 | exit(1); | 125 | exit(1); |
101 | } | 126 | } |
102 | 127 | ||
103 | // build filter | 128 | // build pre-exec filter: blacklist @default, don't blacklist |
129 | // any listed syscalls in @default-keep | ||
104 | filter_init(fd); | 130 | filter_init(fd); |
105 | add_default_list(fd, allow_debuggers); | 131 | add_default_list(fd, allow_debuggers); |
106 | if (syscall_check_list(list, filter_add_blacklist, fd, 0)) { | 132 | char *prelist, *postlist; |
133 | syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist); | ||
134 | if (prelist) | ||
135 | if (syscall_check_list(prelist, filter_add_blacklist, fd, 0, NULL)) { | ||
136 | fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); | ||
137 | exit(1); | ||
138 | } | ||
139 | filter_end_blacklist(fd); | ||
140 | |||
141 | // close file | ||
142 | close(fd); | ||
143 | |||
144 | if (!postlist) | ||
145 | return; | ||
146 | |||
147 | // open file for post-exec filter | ||
148 | fd = open(fname2, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
149 | if (fd < 0) { | ||
150 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname2); | ||
151 | exit(1); | ||
152 | } | ||
153 | |||
154 | // build post-exec filter: blacklist remaining syscalls | ||
155 | filter_init(fd); | ||
156 | if (syscall_check_list(postlist, filter_add_blacklist, fd, 0, NULL)) { | ||
107 | fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); | 157 | fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); |
108 | exit(1); | 158 | exit(1); |
109 | } | 159 | } |
@@ -113,22 +163,42 @@ void seccomp_default_drop(const char *fname, char *list, int allow_debuggers) { | |||
113 | close(fd); | 163 | close(fd); |
114 | } | 164 | } |
115 | 165 | ||
116 | void seccomp_keep(const char *fname, char *list) { | 166 | void seccomp_keep(const char *fname1, const char *fname2, char *list) { |
117 | // open file | 167 | // open file for pre-exec filter |
118 | int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | 168 | int fd = open(fname1, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
119 | if (fd < 0) { | 169 | if (fd < 0) { |
120 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); | 170 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname1); |
121 | exit(1); | 171 | exit(1); |
122 | } | 172 | } |
123 | 173 | ||
124 | // build filter | 174 | // build pre-exec filter: whitelist also @default-keep |
125 | filter_init(fd); | 175 | filter_init(fd); |
126 | // these syscalls are used by firejail after the seccomp filter is initialized | 176 | // these syscalls are used by firejail after the seccomp filter is initialized |
127 | int r; | 177 | int r; |
128 | r = syscall_check_list("@default-keep", filter_add_whitelist, fd, 0); | 178 | r = syscall_check_list("@default-keep", filter_add_whitelist, fd, 0, NULL); |
129 | assert(r == 0); | 179 | assert(r == 0); |
130 | 180 | ||
131 | if (syscall_check_list(list, filter_add_whitelist, fd, 0)) { | 181 | if (syscall_check_list(list, filter_add_whitelist, fd, 0, NULL)) { |
182 | fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); | ||
183 | exit(1); | ||
184 | } | ||
185 | |||
186 | filter_end_whitelist(fd); | ||
187 | |||
188 | // close file | ||
189 | close(fd); | ||
190 | |||
191 | // open file for post-exec filter | ||
192 | fd = open(fname2, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
193 | if (fd < 0) { | ||
194 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname2); | ||
195 | exit(1); | ||
196 | } | ||
197 | |||
198 | // build post-exec filter: whitelist without @default-keep | ||
199 | filter_init(fd); | ||
200 | |||
201 | if (syscall_check_list(list, filter_add_whitelist, fd, 0, NULL)) { | ||
132 | fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); | 202 | fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); |
133 | exit(1); | 203 | exit(1); |
134 | } | 204 | } |
diff --git a/src/fseccomp/seccomp_file.c b/src/fseccomp/seccomp_file.c index 16ffd5302..2d5ee115d 100644 --- a/src/fseccomp/seccomp_file.c +++ b/src/fseccomp/seccomp_file.c | |||
@@ -60,8 +60,9 @@ void filter_init(int fd) { | |||
60 | write_to_file(fd, filter, sizeof(filter)); | 60 | write_to_file(fd, filter, sizeof(filter)); |
61 | } | 61 | } |
62 | 62 | ||
63 | void filter_add_whitelist(int fd, int syscall, int arg) { | 63 | void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg) { |
64 | (void) arg; | 64 | (void) arg; |
65 | (void) ptrarg; | ||
65 | 66 | ||
66 | struct sock_filter filter[] = { | 67 | struct sock_filter filter[] = { |
67 | WHITELIST(syscall) | 68 | WHITELIST(syscall) |
@@ -69,8 +70,9 @@ void filter_add_whitelist(int fd, int syscall, int arg) { | |||
69 | write_to_file(fd, filter, sizeof(filter)); | 70 | write_to_file(fd, filter, sizeof(filter)); |
70 | } | 71 | } |
71 | 72 | ||
72 | void filter_add_blacklist(int fd, int syscall, int arg) { | 73 | void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg) { |
73 | (void) arg; | 74 | (void) arg; |
75 | (void) ptrarg; | ||
74 | 76 | ||
75 | struct sock_filter filter[] = { | 77 | struct sock_filter filter[] = { |
76 | BLACKLIST(syscall) | 78 | BLACKLIST(syscall) |
@@ -78,7 +80,8 @@ void filter_add_blacklist(int fd, int syscall, int arg) { | |||
78 | write_to_file(fd, filter, sizeof(filter)); | 80 | write_to_file(fd, filter, sizeof(filter)); |
79 | } | 81 | } |
80 | 82 | ||
81 | void filter_add_errno(int fd, int syscall, int arg) { | 83 | void filter_add_errno(int fd, int syscall, int arg, void *ptrarg) { |
84 | (void) ptrarg; | ||
82 | struct sock_filter filter[] = { | 85 | struct sock_filter filter[] = { |
83 | BLACKLIST_ERRNO(syscall, arg) | 86 | BLACKLIST_ERRNO(syscall, arg) |
84 | }; | 87 | }; |
diff --git a/src/fseccomp/syscall.c b/src/fseccomp/syscall.c index 5893a2ea8..b9e6d995b 100644 --- a/src/fseccomp/syscall.c +++ b/src/fseccomp/syscall.c | |||
@@ -17,7 +17,9 @@ | |||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
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 | #define _GNU_SOURCE | ||
20 | #include "fseccomp.h" | 21 | #include "fseccomp.h" |
22 | #include <stdio.h> | ||
21 | #include <sys/syscall.h> | 23 | #include <sys/syscall.h> |
22 | 24 | ||
23 | typedef struct { | 25 | typedef struct { |
@@ -30,6 +32,13 @@ typedef struct { | |||
30 | const char * const list; | 32 | const char * const list; |
31 | } SyscallGroupList; | 33 | } SyscallGroupList; |
32 | 34 | ||
35 | typedef struct { | ||
36 | const char *slist; | ||
37 | char *prelist, *postlist; | ||
38 | bool found; | ||
39 | int syscall; | ||
40 | } SyscallCheckList; | ||
41 | |||
33 | static const SyscallEntry syslist[] = { | 42 | static const SyscallEntry syslist[] = { |
34 | // | 43 | // |
35 | // code generated using tools/extract-syscall | 44 | // code generated using tools/extract-syscall |
@@ -174,6 +183,7 @@ static const SyscallGroupList sysgroups[] = { | |||
174 | }, | 183 | }, |
175 | { .name = "@default-keep", .list = | 184 | { .name = "@default-keep", .list = |
176 | "dup," | 185 | "dup," |
186 | "execve," | ||
177 | "prctl," | 187 | "prctl," |
178 | "setgid," | 188 | "setgid," |
179 | "setgroups," | 189 | "setgroups," |
@@ -449,7 +459,7 @@ error: | |||
449 | } | 459 | } |
450 | 460 | ||
451 | // return 1 if error, 0 if OK | 461 | // return 1 if error, 0 if OK |
452 | int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg), int fd, int arg) { | 462 | int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg, void *ptrarg), int fd, int arg, void *ptrarg) { |
453 | // don't allow empty lists | 463 | // don't allow empty lists |
454 | if (slist == NULL || *slist == '\0') { | 464 | if (slist == NULL || *slist == '\0') { |
455 | fprintf(stderr, "Error fseccomp: empty syscall lists are not allowed\n"); | 465 | fprintf(stderr, "Error fseccomp: empty syscall lists are not allowed\n"); |
@@ -477,7 +487,7 @@ int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, | |||
477 | fprintf(stderr, "Error fseccomp: unknown syscall group %s\n", ptr); | 487 | fprintf(stderr, "Error fseccomp: unknown syscall group %s\n", ptr); |
478 | exit(1); | 488 | exit(1); |
479 | } | 489 | } |
480 | syscall_check_list(new_list, callback, fd, arg); | 490 | syscall_check_list(new_list, callback, fd, arg, ptrarg); |
481 | } | 491 | } |
482 | else { | 492 | else { |
483 | syscall_process_name(ptr, &syscall_nr, &error_nr); | 493 | syscall_process_name(ptr, &syscall_nr, &error_nr); |
@@ -487,9 +497,9 @@ int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, | |||
487 | } | 497 | } |
488 | else if (callback != NULL) { | 498 | else if (callback != NULL) { |
489 | if (error_nr != -1) | 499 | if (error_nr != -1) |
490 | filter_add_errno(fd, syscall_nr, error_nr); | 500 | filter_add_errno(fd, syscall_nr, error_nr, ptrarg); |
491 | else | 501 | else |
492 | callback(fd, syscall_nr, arg); | 502 | callback(fd, syscall_nr, arg, ptrarg); |
493 | } | 503 | } |
494 | } | 504 | } |
495 | ptr = strtok_r(NULL, ",", &saveptr); | 505 | ptr = strtok_r(NULL, ",", &saveptr); |
@@ -498,3 +508,49 @@ int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, | |||
498 | free(str); | 508 | free(str); |
499 | return 0; | 509 | return 0; |
500 | } | 510 | } |
511 | |||
512 | static void find_syscall(int fd, int syscall, int arg, void *ptrarg) { | ||
513 | (void)fd; | ||
514 | SyscallCheckList *ptr = ptrarg; | ||
515 | if (syscall == ptr->syscall) | ||
516 | ptr->found = true; | ||
517 | } | ||
518 | |||
519 | // go through list2 and find matches for problem syscall | ||
520 | static void syscall_in_list(int fd, int syscall, int arg, void *ptrarg) { | ||
521 | (void)arg; | ||
522 | SyscallCheckList *ptr = ptrarg; | ||
523 | SyscallCheckList sl; | ||
524 | sl.found = false; | ||
525 | sl.syscall = syscall; | ||
526 | syscall_check_list(ptr->slist, find_syscall, fd, 0, &sl); | ||
527 | // if found in the problem list, add to post-exec list | ||
528 | if (sl.found) | ||
529 | if (ptr->postlist) { | ||
530 | if (asprintf(&ptr->postlist, "%s,%s", ptr->postlist, syscall_find_nr(syscall)) == -1) | ||
531 | errExit("asprintf"); | ||
532 | } | ||
533 | else | ||
534 | ptr->postlist = strdup(syscall_find_nr(syscall)); | ||
535 | else // no problem, add to pre-exec list | ||
536 | if (ptr->prelist) { | ||
537 | if (asprintf(&ptr->prelist, "%s,%s", ptr->prelist, syscall_find_nr(syscall)) == -1) | ||
538 | errExit("asprintf"); | ||
539 | } | ||
540 | else | ||
541 | ptr->prelist = strdup(syscall_find_nr(syscall)); | ||
542 | } | ||
543 | |||
544 | // go through list and find matches for syscalls in list @default-keep | ||
545 | void syscalls_in_list(const char *list, const char *slist, int fd, char **prelist, char **postlist) { | ||
546 | SyscallCheckList sl; | ||
547 | // these syscalls are used by firejail after the seccomp filter is initialized | ||
548 | sl.slist = slist; | ||
549 | sl.prelist = NULL; | ||
550 | sl.postlist = NULL; | ||
551 | syscall_check_list(list, syscall_in_list, 0, 0, &sl); | ||
552 | if (!arg_quiet) | ||
553 | printf("list in: %s, check list: %s prelist: %s, postlist: %s\n", list, sl.slist, sl.prelist, sl.postlist); | ||
554 | *prelist = sl.prelist; | ||
555 | *postlist = sl.postlist; | ||
556 | } | ||
diff --git a/src/libpostexecseccomp/Makefile.in b/src/libpostexecseccomp/Makefile.in new file mode 100644 index 000000000..92803342c --- /dev/null +++ b/src/libpostexecseccomp/Makefile.in | |||
@@ -0,0 +1,26 @@ | |||
1 | CC=@CC@ | ||
2 | PREFIX=@prefix@ | ||
3 | VERSION=@PACKAGE_VERSION@ | ||
4 | NAME=@PACKAGE_NAME@ | ||
5 | HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@ | ||
6 | |||
7 | H_FILE_LIST = $(sort $(wildcard *.[h])) | ||
8 | C_FILE_LIST = $(sort $(wildcard *.c)) | ||
9 | OBJS = $(C_FILE_LIST:.c=.o) | ||
10 | BINOBJS = $(foreach file, $(OBJS), $file) | ||
11 | CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC -Wformat -Wformat-security | ||
12 | LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now | ||
13 | |||
14 | all: libpostexecseccomp.so | ||
15 | |||
16 | %.o : %.c $(H_FILE_LIST) | ||
17 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ | ||
18 | |||
19 | libpostexecseccomp.so: $(OBJS) | ||
20 | $(CC) $(LDFLAGS) -shared -fPIC -z relro -o $@ $(OBJS) -ldl | ||
21 | |||
22 | |||
23 | clean:; rm -f $(OBJS) libpostexecseccomp.so | ||
24 | |||
25 | distclean: clean | ||
26 | rm -fr Makefile | ||
diff --git a/src/libpostexecseccomp/libpostexecseccomp.c b/src/libpostexecseccomp/libpostexecseccomp.c new file mode 100644 index 000000000..801f968a6 --- /dev/null +++ b/src/libpostexecseccomp/libpostexecseccomp.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | #include "libpostexecseccomp.h" | ||
21 | #include <fcntl.h> | ||
22 | #include <linux/audit.h> | ||
23 | #include <linux/bpf.h> | ||
24 | #include <linux/filter.h> | ||
25 | #include <linux/seccomp.h> | ||
26 | #include <sys/mman.h> | ||
27 | #include <sys/prctl.h> | ||
28 | #include <sys/ptrace.h> | ||
29 | #include <sys/stat.h> | ||
30 | #include <sys/types.h> | ||
31 | #include <unistd.h> | ||
32 | |||
33 | __attribute__((constructor)) | ||
34 | static void load_seccomp(void) { | ||
35 | int fd = open(RUN_SECCOMP_POSTEXEC, O_RDONLY); | ||
36 | if (fd == -1) | ||
37 | return; | ||
38 | |||
39 | int size = lseek(fd, 0, SEEK_END); | ||
40 | unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter); | ||
41 | struct sock_filter *filter = MAP_FAILED; | ||
42 | if (size != 0) | ||
43 | filter = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); | ||
44 | |||
45 | close(fd); | ||
46 | |||
47 | if (size == 0 || filter == MAP_FAILED) | ||
48 | return; | ||
49 | |||
50 | // install filter | ||
51 | struct sock_fprog prog = { | ||
52 | .len = entries, | ||
53 | .filter = filter, | ||
54 | }; | ||
55 | |||
56 | prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | ||
57 | prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); | ||
58 | munmap(filter, size); | ||
59 | } | ||
diff --git a/src/libpostexecseccomp/libpostexecseccomp.h b/src/libpostexecseccomp/libpostexecseccomp.h new file mode 100644 index 000000000..c4aca540a --- /dev/null +++ b/src/libpostexecseccomp/libpostexecseccomp.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | #ifndef LIBPOSTEXECSECCOMP_H | ||
21 | #define LIBPOSTEXECSECCOMP_H | ||
22 | |||
23 | #define RUN_SECCOMP_POSTEXEC "/run/firejail/mnt/seccomp.postexec" | ||
24 | |||
25 | #endif | ||
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 2c8dca09a..be73429bc 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -1578,6 +1578,32 @@ $ rm testfile | |||
1578 | rm: cannot remove `testfile': Operation not permitted | 1578 | rm: cannot remove `testfile': Operation not permitted |
1579 | .br | 1579 | .br |
1580 | 1580 | ||
1581 | .br | ||
1582 | If the blocked system calls would also block Firejail from operating, | ||
1583 | they are handled by adding a preloaded library which performs seccomp | ||
1584 | system calls later. | ||
1585 | .br | ||
1586 | |||
1587 | .br | ||
1588 | Example: | ||
1589 | .br | ||
1590 | |||
1591 | .br | ||
1592 | $ firejail \-\-noprofile \-\-shell=none \-\-seccomp=execve bash | ||
1593 | .br | ||
1594 | Parent pid 32751, child pid 32752 | ||
1595 | .br | ||
1596 | Post-exec seccomp protector enabled | ||
1597 | .br | ||
1598 | list in: execve, check list: @default-keep prelist: (null), postlist: execve | ||
1599 | .br | ||
1600 | Child process initialized in 46.44 ms | ||
1601 | .br | ||
1602 | $ ls | ||
1603 | .br | ||
1604 | Bad system call | ||
1605 | .br | ||
1606 | |||
1581 | .TP | 1607 | .TP |
1582 | \fB\-\-seccomp.drop=syscall,syscall,syscall | 1608 | \fB\-\-seccomp.drop=syscall,syscall,syscall |
1583 | Enable seccomp filter, and blacklist the syscalls specified by the command. | 1609 | Enable seccomp filter, and blacklist the syscalls specified by the command. |