diff options
-rw-r--r-- | RELNOTES | 5 | ||||
-rw-r--r-- | etc/firejail.config | 3 | ||||
-rw-r--r-- | src/firejail/checkcfg.c | 22 | ||||
-rw-r--r-- | src/firejail/firejail.h | 5 | ||||
-rw-r--r-- | src/firejail/main.c | 32 | ||||
-rw-r--r-- | src/firejail/profile.c | 29 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 5 | ||||
-rw-r--r-- | src/firejail/sbox.c | 55 | ||||
-rw-r--r-- | src/firejail/seccomp.c | 35 | ||||
-rw-r--r-- | src/firejail/usage.c | 1 | ||||
-rw-r--r-- | src/fsec-print/main.c | 8 | ||||
-rw-r--r-- | src/fseccomp/main.c | 13 | ||||
-rw-r--r-- | src/fseccomp/seccomp.c | 20 | ||||
-rw-r--r-- | src/fseccomp/seccomp_file.c | 15 | ||||
-rw-r--r-- | src/fseccomp/seccomp_secondary.c | 2 | ||||
-rw-r--r-- | src/include/seccomp.h | 9 | ||||
-rw-r--r-- | src/include/syscall.h | 1 | ||||
-rw-r--r-- | src/lib/syscall.c | 31 | ||||
-rw-r--r-- | src/man/firejail-profile.txt | 3 | ||||
-rw-r--r-- | src/man/firejail.txt | 33 |
20 files changed, 266 insertions, 61 deletions
@@ -1,5 +1,10 @@ | |||
1 | firejail (0.9.63) baseline; urgency=low | 1 | firejail (0.9.63) baseline; urgency=low |
2 | * work in progress | 2 | * work in progress |
3 | * The blocking action of seccomp filters has been changed from | ||
4 | killing the process to returning EPERM to the caller. To get the | ||
5 | previous behaviour, use --seccomp-error-action=kill or | ||
6 | syscall:kill syntax when constructing filters, or override in | ||
7 | /etc/firejail/firejail.config file. | ||
3 | * DHCP client support | 8 | * DHCP client support |
4 | * SELinux labeling support | 9 | * SELinux labeling support |
5 | * 32-bit seccomp filter | 10 | * 32-bit seccomp filter |
diff --git a/etc/firejail.config b/etc/firejail.config index 6fb7d829a..410bd0ccb 100644 --- a/etc/firejail.config +++ b/etc/firejail.config | |||
@@ -146,3 +146,6 @@ | |||
146 | 146 | ||
147 | # Xvfb command extra parameters. None by default; this is an example. | 147 | # Xvfb command extra parameters. None by default; this is an example. |
148 | # xvfb-extra-params -pixdepths 8 24 32 | 148 | # xvfb-extra-params -pixdepths 8 24 32 |
149 | |||
150 | # Seccomp error action, kill or errno (EPERM, ENOSYS etc) | ||
151 | # seccomp-error-action EPERM | ||
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index fbe150b34..eb4841210 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c | |||
@@ -18,6 +18,8 @@ | |||
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 "firejail.h" | 20 | #include "firejail.h" |
21 | #include "../include/seccomp.h" | ||
22 | #include "../include/syscall.h" | ||
21 | #include <sys/stat.h> | 23 | #include <sys/stat.h> |
22 | #include <linux/loop.h> | 24 | #include <linux/loop.h> |
23 | 25 | ||
@@ -32,6 +34,7 @@ char *xvfb_screen = "800x600x24"; | |||
32 | char *xvfb_extra_params = ""; | 34 | char *xvfb_extra_params = ""; |
33 | char *netfilter_default = NULL; | 35 | char *netfilter_default = NULL; |
34 | unsigned long join_timeout = 5000000; // microseconds | 36 | unsigned long join_timeout = 5000000; // microseconds |
37 | char *config_seccomp_error_action_str = "EPERM"; | ||
35 | 38 | ||
36 | int checkcfg(int val) { | 39 | int checkcfg(int val) { |
37 | assert(val < CFG_MAX); | 40 | assert(val < CFG_MAX); |
@@ -51,6 +54,7 @@ int checkcfg(int val) { | |||
51 | cfg_val[CFG_DISABLE_MNT] = 0; | 54 | cfg_val[CFG_DISABLE_MNT] = 0; |
52 | cfg_val[CFG_ARP_PROBES] = DEFAULT_ARP_PROBES; | 55 | cfg_val[CFG_ARP_PROBES] = DEFAULT_ARP_PROBES; |
53 | cfg_val[CFG_XPRA_ATTACH] = 0; | 56 | cfg_val[CFG_XPRA_ATTACH] = 0; |
57 | cfg_val[CFG_SECCOMP_ERROR_ACTION] = -1; | ||
54 | 58 | ||
55 | // open configuration file | 59 | // open configuration file |
56 | const char *fname = SYSCONFDIR "/firejail.config"; | 60 | const char *fname = SYSCONFDIR "/firejail.config"; |
@@ -219,6 +223,24 @@ int checkcfg(int val) { | |||
219 | else if (strncmp(ptr, "join-timeout ", 13) == 0) | 223 | else if (strncmp(ptr, "join-timeout ", 13) == 0) |
220 | join_timeout = strtoul(ptr + 13, NULL, 10) * 1000000; // seconds to microseconds | 224 | join_timeout = strtoul(ptr + 13, NULL, 10) * 1000000; // seconds to microseconds |
221 | 225 | ||
226 | // seccomp error action | ||
227 | else if (strncmp(ptr, "seccomp-error-action ", 21) == 0) { | ||
228 | #ifdef HAVE_SECCOMP | ||
229 | if (strcmp(ptr + 21, "kill") == 0) | ||
230 | cfg_val[CFG_SECCOMP_ERROR_ACTION] = SECCOMP_RET_KILL; | ||
231 | else { | ||
232 | cfg_val[CFG_SECCOMP_ERROR_ACTION] = errno_find_name(ptr + 21); | ||
233 | if (cfg_val[CFG_SECCOMP_ERROR_ACTION] == -1) | ||
234 | errExit("seccomp-error-action: unknown errno"); | ||
235 | } | ||
236 | config_seccomp_error_action_str = strdup(ptr + 21); | ||
237 | if (!config_seccomp_error_action_str) | ||
238 | errExit("strdup"); | ||
239 | #else | ||
240 | warning_feature_disabled("seccomp"); | ||
241 | #endif | ||
242 | } | ||
243 | |||
222 | else | 244 | else |
223 | goto errout; | 245 | goto errout; |
224 | 246 | ||
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 1be2bc1da..1cb8b2d22 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -186,6 +186,7 @@ typedef struct config_t { | |||
186 | char *seccomp_list_drop, *seccomp_list_drop32; // seccomp drop list | 186 | char *seccomp_list_drop, *seccomp_list_drop32; // seccomp drop list |
187 | char *seccomp_list_keep, *seccomp_list_keep32; // seccomp keep list | 187 | char *seccomp_list_keep, *seccomp_list_keep32; // seccomp keep list |
188 | char *protocol; // protocol list | 188 | char *protocol; // protocol list |
189 | char *seccomp_error_action; // error action: kill or errno | ||
189 | 190 | ||
190 | // rlimits | 191 | // rlimits |
191 | long long unsigned rlimit_cpu; | 192 | long long unsigned rlimit_cpu; |
@@ -572,6 +573,7 @@ int seccomp_install_filters(void); | |||
572 | int seccomp_load(const char *fname); | 573 | int seccomp_load(const char *fname); |
573 | int seccomp_filter_drop(bool native); | 574 | int seccomp_filter_drop(bool native); |
574 | int seccomp_filter_keep(bool native); | 575 | int seccomp_filter_keep(bool native); |
576 | int seccomp_filter_mdwx(bool native); | ||
575 | void seccomp_print_filter(pid_t pid); | 577 | void seccomp_print_filter(pid_t pid); |
576 | 578 | ||
577 | // caps.c | 579 | // caps.c |
@@ -754,6 +756,7 @@ enum { | |||
754 | CFG_PRIVATE_CACHE, | 756 | CFG_PRIVATE_CACHE, |
755 | CFG_CGROUP, | 757 | CFG_CGROUP, |
756 | CFG_NAME_CHANGE, | 758 | CFG_NAME_CHANGE, |
759 | CFG_SECCOMP_ERROR_ACTION, | ||
757 | // CFG_FILE_COPY_LIMIT - file copy limit handled using setenv/getenv | 760 | // CFG_FILE_COPY_LIMIT - file copy limit handled using setenv/getenv |
758 | CFG_MAX // this should always be the last entry | 761 | CFG_MAX // this should always be the last entry |
759 | }; | 762 | }; |
@@ -764,6 +767,8 @@ extern char *xvfb_screen; | |||
764 | extern char *xvfb_extra_params; | 767 | extern char *xvfb_extra_params; |
765 | extern char *netfilter_default; | 768 | extern char *netfilter_default; |
766 | extern unsigned long join_timeout; | 769 | extern unsigned long join_timeout; |
770 | extern char *config_seccomp_error_action_str; | ||
771 | |||
767 | int checkcfg(int val); | 772 | int checkcfg(int val); |
768 | void print_compiletime_support(void); | 773 | void print_compiletime_support(void); |
769 | 774 | ||
diff --git a/src/firejail/main.c b/src/firejail/main.c index 9bff960cb..d01725c95 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "../include/pid.h" | 21 | #include "../include/pid.h" |
22 | #include "../include/firejail_user.h" | 22 | #include "../include/firejail_user.h" |
23 | #include "../include/syscall.h" | 23 | #include "../include/syscall.h" |
24 | #include "../include/seccomp.h" | ||
24 | #define _GNU_SOURCE | 25 | #define _GNU_SOURCE |
25 | #include <sys/utsname.h> | 26 | #include <sys/utsname.h> |
26 | #include <sched.h> | 27 | #include <sched.h> |
@@ -76,6 +77,7 @@ int arg_seccomp = 0; // enable default seccomp filter | |||
76 | int arg_seccomp32 = 0; // enable default seccomp filter for 32 bit arch | 77 | int arg_seccomp32 = 0; // enable default seccomp filter for 32 bit arch |
77 | int arg_seccomp_postexec = 0; // need postexec ld.preload library? | 78 | int arg_seccomp_postexec = 0; // need postexec ld.preload library? |
78 | int arg_seccomp_block_secondary = 0; // block any secondary architectures | 79 | int arg_seccomp_block_secondary = 0; // block any secondary architectures |
80 | int arg_seccomp_error_action = 0; | ||
79 | 81 | ||
80 | int arg_caps_default_filter = 0; // enable default capabilities filter | 82 | int arg_caps_default_filter = 0; // enable default capabilities filter |
81 | int arg_caps_drop = 0; // drop list | 83 | int arg_caps_drop = 0; // drop list |
@@ -349,6 +351,9 @@ static void init_cfg(int argc, char **argv) { | |||
349 | sandbox_pid = getpid(); | 351 | sandbox_pid = getpid(); |
350 | time_t t = time(NULL); | 352 | time_t t = time(NULL); |
351 | srand(t ^ sandbox_pid); | 353 | srand(t ^ sandbox_pid); |
354 | |||
355 | arg_seccomp_error_action = EPERM; | ||
356 | cfg.seccomp_error_action = "EPERM"; | ||
352 | } | 357 | } |
353 | 358 | ||
354 | static void check_network(Bridge *br) { | 359 | static void check_network(Bridge *br) { |
@@ -973,6 +978,13 @@ void filter_add_errno(int fd, int syscall, int arg, void *ptrarg, bool native) { | |||
973 | (void) ptrarg; | 978 | (void) ptrarg; |
974 | (void) native; | 979 | (void) native; |
975 | } | 980 | } |
981 | void filter_add_blacklist_override(int fd, int syscall, int arg, void *ptrarg, bool native) { | ||
982 | (void) fd; | ||
983 | (void) syscall; | ||
984 | (void) arg; | ||
985 | (void) ptrarg; | ||
986 | (void) native; | ||
987 | } | ||
976 | 988 | ||
977 | #ifdef HAVE_SECCOMP | 989 | #ifdef HAVE_SECCOMP |
978 | static int check_postexec(const char *list) { | 990 | static int check_postexec(const char *list) { |
@@ -1398,6 +1410,26 @@ int main(int argc, char **argv, char **envp) { | |||
1398 | else | 1410 | else |
1399 | exit_err_feature("seccomp"); | 1411 | exit_err_feature("seccomp"); |
1400 | } | 1412 | } |
1413 | else if (strncmp(argv[i], "--seccomp-error-action=", 23) == 0) { | ||
1414 | if (checkcfg(CFG_SECCOMP)) { | ||
1415 | int config_seccomp_error_action = checkcfg(CFG_SECCOMP_ERROR_ACTION); | ||
1416 | if (config_seccomp_error_action == -1) { | ||
1417 | if (strcmp(argv[i] + 23, "kill") == 0) | ||
1418 | arg_seccomp_error_action = SECCOMP_RET_KILL; | ||
1419 | else { | ||
1420 | arg_seccomp_error_action = errno_find_name(argv[i] + 23); | ||
1421 | if (arg_seccomp_error_action == -1) | ||
1422 | errExit("seccomp-error-action: unknown errno"); | ||
1423 | } | ||
1424 | cfg.seccomp_error_action = strdup(argv[i] + 23); | ||
1425 | if (!cfg.seccomp_error_action) | ||
1426 | errExit("strdup"); | ||
1427 | } else | ||
1428 | exit_err_feature("seccomp-error-action"); | ||
1429 | |||
1430 | } else | ||
1431 | exit_err_feature("seccomp"); | ||
1432 | } | ||
1401 | #endif | 1433 | #endif |
1402 | else if (strcmp(argv[i], "--caps") == 0) { | 1434 | else if (strcmp(argv[i], "--caps") == 0) { |
1403 | arg_caps_default_filter = 1; | 1435 | arg_caps_default_filter = 1; |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 2200fec01..d709a7951 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -18,6 +18,8 @@ | |||
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 "firejail.h" | 20 | #include "firejail.h" |
21 | #include "../include/seccomp.h" | ||
22 | #include "../include/syscall.h" | ||
21 | #include <dirent.h> | 23 | #include <dirent.h> |
22 | #include <sys/stat.h> | 24 | #include <sys/stat.h> |
23 | extern char *xephyr_screen; | 25 | extern char *xephyr_screen; |
@@ -870,6 +872,33 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
870 | return 0; | 872 | return 0; |
871 | } | 873 | } |
872 | 874 | ||
875 | // seccomp error action | ||
876 | if (strncmp(ptr, "seccomp-error-action ", 21) == 0) { | ||
877 | #ifdef HAVE_SECCOMP | ||
878 | if (checkcfg(CFG_SECCOMP)) { | ||
879 | int config_seccomp_error_action = checkcfg(CFG_SECCOMP_ERROR_ACTION); | ||
880 | if (config_seccomp_error_action == -1) { | ||
881 | if (strcmp(ptr + 21, "kill") == 0) | ||
882 | arg_seccomp_error_action = SECCOMP_RET_KILL; | ||
883 | else { | ||
884 | arg_seccomp_error_action = errno_find_name(ptr + 21); | ||
885 | if (arg_seccomp_error_action == -1) | ||
886 | errExit("seccomp-error-action: unknown errno"); | ||
887 | } | ||
888 | cfg.seccomp_error_action = strdup(ptr + 21); | ||
889 | if (!cfg.seccomp_error_action) | ||
890 | errExit("strdup"); | ||
891 | } else { | ||
892 | arg_seccomp_error_action = config_seccomp_error_action; | ||
893 | cfg.seccomp_error_action = config_seccomp_error_action_str; | ||
894 | warning_feature_disabled("seccomp-error-action"); | ||
895 | } | ||
896 | } else | ||
897 | warning_feature_disabled("seccomp"); | ||
898 | #endif | ||
899 | return 0; | ||
900 | } | ||
901 | |||
873 | // caps drop list | 902 | // caps drop list |
874 | if (strncmp(ptr, "caps.drop ", 10) == 0) { | 903 | if (strncmp(ptr, "caps.drop ", 10) == 0) { |
875 | arg_caps_drop = 1; | 904 | arg_caps_drop = 1; |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 9abf94a7f..e20ec603c 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -19,6 +19,7 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include "firejail.h" | 21 | #include "firejail.h" |
22 | #include "../include/seccomp.h" | ||
22 | #include <sys/mount.h> | 23 | #include <sys/mount.h> |
23 | #include <sys/wait.h> | 24 | #include <sys/wait.h> |
24 | #include <sys/stat.h> | 25 | #include <sys/stat.h> |
@@ -1124,6 +1125,10 @@ int sandbox(void* sandbox_arg) { | |||
1124 | } | 1125 | } |
1125 | 1126 | ||
1126 | if (arg_memory_deny_write_execute) { | 1127 | if (arg_memory_deny_write_execute) { |
1128 | if (arg_seccomp_error_action != EPERM) { | ||
1129 | seccomp_filter_mdwx(true); | ||
1130 | seccomp_filter_mdwx(false); | ||
1131 | } | ||
1127 | if (arg_debug) | 1132 | if (arg_debug) |
1128 | printf("Install memory write&execute filter\n"); | 1133 | printf("Install memory write&execute filter\n"); |
1129 | seccomp_load(RUN_SECCOMP_MDWX); // install filter | 1134 | seccomp_load(RUN_SECCOMP_MDWX); // install filter |
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c index 0c7b13f1c..e96b9cf79 100644 --- a/src/firejail/sbox.c +++ b/src/firejail/sbox.c | |||
@@ -31,7 +31,27 @@ | |||
31 | #define O_PATH 010000000 | 31 | #define O_PATH 010000000 |
32 | #endif | 32 | #endif |
33 | 33 | ||
34 | static struct sock_filter filter[] = { | 34 | int sbox_run(unsigned filtermask, int num, ...) { |
35 | va_list valist; | ||
36 | va_start(valist, num); | ||
37 | |||
38 | // build argument list | ||
39 | char **arg = malloc((num + 1) * sizeof(char *)); | ||
40 | int i; | ||
41 | for (i = 0; i < num; i++) | ||
42 | arg[i] = va_arg(valist, char*); | ||
43 | arg[i] = NULL; | ||
44 | va_end(valist); | ||
45 | |||
46 | int status = sbox_run_v(filtermask, arg); | ||
47 | |||
48 | free(arg); | ||
49 | |||
50 | return status; | ||
51 | } | ||
52 | |||
53 | int sbox_run_v(unsigned filtermask, char * const arg[]) { | ||
54 | struct sock_filter filter[] = { | ||
35 | VALIDATE_ARCHITECTURE, | 55 | VALIDATE_ARCHITECTURE, |
36 | EXAMINE_SYSCALL, | 56 | EXAMINE_SYSCALL, |
37 | 57 | ||
@@ -105,33 +125,13 @@ static struct sock_filter filter[] = { | |||
105 | BLACKLIST(SYS_syslog), // kernel printk control | 125 | BLACKLIST(SYS_syslog), // kernel printk control |
106 | #endif | 126 | #endif |
107 | RETURN_ALLOW | 127 | RETURN_ALLOW |
108 | }; | 128 | }; |
109 | 129 | ||
110 | static struct sock_fprog prog = { | 130 | struct sock_fprog prog = { |
111 | .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), | 131 | .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), |
112 | .filter = filter, | 132 | .filter = filter, |
113 | }; | 133 | }; |
114 | 134 | ||
115 | int sbox_run(unsigned filtermask, int num, ...) { | ||
116 | va_list valist; | ||
117 | va_start(valist, num); | ||
118 | |||
119 | // build argument list | ||
120 | char **arg = malloc((num + 1) * sizeof(char *)); | ||
121 | int i; | ||
122 | for (i = 0; i < num; i++) | ||
123 | arg[i] = va_arg(valist, char*); | ||
124 | arg[i] = NULL; | ||
125 | va_end(valist); | ||
126 | |||
127 | int status = sbox_run_v(filtermask, arg); | ||
128 | |||
129 | free(arg); | ||
130 | |||
131 | return status; | ||
132 | } | ||
133 | |||
134 | int sbox_run_v(unsigned filtermask, char * const arg[]) { | ||
135 | EUID_ROOT(); | 135 | EUID_ROOT(); |
136 | 136 | ||
137 | if (arg_debug) { | 137 | if (arg_debug) { |
@@ -161,6 +161,9 @@ int sbox_run_v(unsigned filtermask, char * const arg[]) { | |||
161 | new_environment[env_index++] = "FIREJAIL_QUIET=yes"; | 161 | new_environment[env_index++] = "FIREJAIL_QUIET=yes"; |
162 | if (arg_debug) // --debug is passed as an environment variable | 162 | if (arg_debug) // --debug is passed as an environment variable |
163 | new_environment[env_index++] = "FIREJAIL_DEBUG=yes"; | 163 | new_environment[env_index++] = "FIREJAIL_DEBUG=yes"; |
164 | if (cfg.seccomp_error_action) | ||
165 | if (asprintf(&new_environment[env_index++], "FIREJAIL_SECCOMP_ERROR_ACTION=%s", cfg.seccomp_error_action) == -1) | ||
166 | errExit("asprintf"); | ||
164 | 167 | ||
165 | if (filtermask & SBOX_STDIN_FROM_FILE) { | 168 | if (filtermask & SBOX_STDIN_FROM_FILE) { |
166 | int fd; | 169 | int fd; |
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index 612ece85d..b42a1eeb0 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c | |||
@@ -208,8 +208,8 @@ int seccomp_filter_drop(bool native) { | |||
208 | // - seccomp list | 208 | // - seccomp list |
209 | // - seccomp | 209 | // - seccomp |
210 | if (cfg.seccomp_list_drop == NULL) { | 210 | if (cfg.seccomp_list_drop == NULL) { |
211 | // default seccomp | 211 | // default seccomp if error action is not changed |
212 | if (cfg.seccomp_list == NULL) { | 212 | if (cfg.seccomp_list == NULL && cfg.seccomp_error_action) { |
213 | if (arg_seccomp_block_secondary) | 213 | if (arg_seccomp_block_secondary) |
214 | seccomp_filter_block_secondary(); | 214 | seccomp_filter_block_secondary(); |
215 | else { | 215 | else { |
@@ -243,6 +243,8 @@ int seccomp_filter_drop(bool native) { | |||
243 | list = cfg.seccomp_list32; | 243 | list = cfg.seccomp_list32; |
244 | } | 244 | } |
245 | 245 | ||
246 | if (list == NULL) | ||
247 | list = ""; | ||
246 | // build the seccomp filter as a regular user | 248 | // build the seccomp filter as a regular user |
247 | int rv; | 249 | int rv; |
248 | if (arg_allow_debuggers) | 250 | if (arg_allow_debuggers) |
@@ -365,6 +367,35 @@ int seccomp_filter_keep(bool native) { | |||
365 | return 0; | 367 | return 0; |
366 | } | 368 | } |
367 | 369 | ||
370 | // create mdwx filter for non-default error action | ||
371 | int seccomp_filter_mdwx(bool native) { | ||
372 | if (arg_debug) | ||
373 | printf("Build memory-deny-write-execute filter\n"); | ||
374 | |||
375 | const char *command, *filter, *postexec_filter, *list; | ||
376 | if (native) { | ||
377 | command = "memory-deny-write-execute"; | ||
378 | filter = RUN_SECCOMP_MDWX; | ||
379 | } else { | ||
380 | command = "memory-deny-write-execute.32"; | ||
381 | filter = RUN_SECCOMP_MDWX_32; | ||
382 | } | ||
383 | |||
384 | // build the seccomp filter as a regular user | ||
385 | int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, | ||
386 | PATH_FSECCOMP, command, filter); | ||
387 | |||
388 | if (rv) { | ||
389 | fprintf(stderr, "Error: cannot build memory-deny-write-execute filter\n"); | ||
390 | exit(rv); | ||
391 | } | ||
392 | |||
393 | if (arg_debug) | ||
394 | printf("Memory-deny-write-execute filter configured\n"); | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
368 | void seccomp_print_filter(pid_t pid) { | 399 | void seccomp_print_filter(pid_t pid) { |
369 | EUID_ASSERT(); | 400 | EUID_ASSERT(); |
370 | 401 | ||
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 77bfea8c6..81a1a6099 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -209,6 +209,7 @@ static char *usage_str = | |||
209 | " --seccomp.print=name|pid - print the seccomp filter for the sandbox\n" | 209 | " --seccomp.print=name|pid - print the seccomp filter for the sandbox\n" |
210 | "\tidentified by name or PID.\n" | 210 | "\tidentified by name or PID.\n" |
211 | " --seccomp.32[.drop,.keep][=syscall] - like above but for 32 bit architecture.\n" | 211 | " --seccomp.32[.drop,.keep][=syscall] - like above but for 32 bit architecture.\n" |
212 | " --seccomp-error-action=errno|kill - change error code or kill process.\n" | ||
212 | #endif | 213 | #endif |
213 | " --shell=none - run the program directly without a user shell.\n" | 214 | " --shell=none - run the program directly without a user shell.\n" |
214 | " --shell=program - set default user shell.\n" | 215 | " --shell=program - set default user shell.\n" |
diff --git a/src/fsec-print/main.c b/src/fsec-print/main.c index 8b7c68434..ade45c881 100644 --- a/src/fsec-print/main.c +++ b/src/fsec-print/main.c | |||
@@ -33,6 +33,14 @@ void filter_add_errno(int fd, int syscall, int arg, void *ptrarg, bool native) { | |||
33 | (void) native; | 33 | (void) native; |
34 | } | 34 | } |
35 | 35 | ||
36 | void filter_add_blacklist_override(int fd, int syscall, int arg, void *ptrarg, bool native) { | ||
37 | (void) fd; | ||
38 | (void) syscall; | ||
39 | (void) arg; | ||
40 | (void) ptrarg; | ||
41 | (void) native; | ||
42 | } | ||
43 | |||
36 | int main(int argc, char **argv) { | 44 | int main(int argc, char **argv) { |
37 | #if 0 | 45 | #if 0 |
38 | { | 46 | { |
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index b3161a6db..98e32cdf4 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c | |||
@@ -18,7 +18,9 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "fseccomp.h" | 20 | #include "fseccomp.h" |
21 | #include "../include/seccomp.h" | ||
21 | int arg_quiet = 0; | 22 | int arg_quiet = 0; |
23 | int arg_seccomp_error_action = EPERM; // error action: errno or kill | ||
22 | 24 | ||
23 | static void usage(void) { | 25 | static void usage(void) { |
24 | printf("Usage:\n"); | 26 | printf("Usage:\n"); |
@@ -67,6 +69,17 @@ printf("\n"); | |||
67 | if (quiet && strcmp(quiet, "yes") == 0) | 69 | if (quiet && strcmp(quiet, "yes") == 0) |
68 | arg_quiet = 1; | 70 | arg_quiet = 1; |
69 | 71 | ||
72 | char *error_action = getenv("FIREJAIL_SECCOMP_ERROR_ACTION"); | ||
73 | if (error_action) | ||
74 | if (strcmp(error_action, "kill") == 0) | ||
75 | arg_seccomp_error_action = SECCOMP_RET_KILL; | ||
76 | else { | ||
77 | arg_seccomp_error_action = errno_find_name(error_action); | ||
78 | if (arg_seccomp_error_action == -1) | ||
79 | errExit("seccomp-error-action: unknown errno"); | ||
80 | arg_seccomp_error_action |= SECCOMP_RET_ERRNO; | ||
81 | } | ||
82 | |||
70 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { | 83 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { |
71 | usage(); | 84 | usage(); |
72 | return 0; | 85 | return 0; |
diff --git a/src/fseccomp/seccomp.c b/src/fseccomp/seccomp.c index 0db7b5954..e808538b0 100644 --- a/src/fseccomp/seccomp.c +++ b/src/fseccomp/seccomp.c | |||
@@ -255,7 +255,7 @@ void memory_deny_write_execute(const char *fname) { | |||
255 | EXAMINE_ARGUMENT(2), | 255 | EXAMINE_ARGUMENT(2), |
256 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_WRITE|PROT_EXEC), | 256 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_WRITE|PROT_EXEC), |
257 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_WRITE|PROT_EXEC, 0, 1), | 257 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_WRITE|PROT_EXEC, 0, 1), |
258 | KILL_PROCESS, | 258 | KILL_OR_RETURN_ERRNO, |
259 | RETURN_ALLOW, | 259 | RETURN_ALLOW, |
260 | #endif | 260 | #endif |
261 | 261 | ||
@@ -264,7 +264,7 @@ void memory_deny_write_execute(const char *fname) { | |||
264 | EXAMINE_ARGUMENT(2), | 264 | EXAMINE_ARGUMENT(2), |
265 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC), | 265 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC), |
266 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1), | 266 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1), |
267 | KILL_PROCESS, | 267 | KILL_OR_RETURN_ERRNO, |
268 | RETURN_ALLOW, | 268 | RETURN_ALLOW, |
269 | 269 | ||
270 | // same for pkey_mprotect(,,PROT_EXEC), where available | 270 | // same for pkey_mprotect(,,PROT_EXEC), where available |
@@ -273,7 +273,7 @@ void memory_deny_write_execute(const char *fname) { | |||
273 | EXAMINE_ARGUMENT(2), | 273 | EXAMINE_ARGUMENT(2), |
274 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC), | 274 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC), |
275 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1), | 275 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1), |
276 | KILL_PROCESS, | 276 | KILL_OR_RETURN_ERRNO, |
277 | RETURN_ALLOW, | 277 | RETURN_ALLOW, |
278 | #endif | 278 | #endif |
279 | 279 | ||
@@ -284,7 +284,7 @@ void memory_deny_write_execute(const char *fname) { | |||
284 | EXAMINE_ARGUMENT(2), | 284 | EXAMINE_ARGUMENT(2), |
285 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, SHM_EXEC), | 285 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, SHM_EXEC), |
286 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SHM_EXEC, 0, 1), | 286 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SHM_EXEC, 0, 1), |
287 | KILL_PROCESS, | 287 | KILL_OR_RETURN_ERRNO, |
288 | RETURN_ALLOW, | 288 | RETURN_ALLOW, |
289 | #endif | 289 | #endif |
290 | #ifdef SYS_memfd_create | 290 | #ifdef SYS_memfd_create |
@@ -292,7 +292,7 @@ void memory_deny_write_execute(const char *fname) { | |||
292 | // arbitrary memory contents which can be later mapped | 292 | // arbitrary memory contents which can be later mapped |
293 | // as executable | 293 | // as executable |
294 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_memfd_create, 0, 1), | 294 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_memfd_create, 0, 1), |
295 | KILL_PROCESS, | 295 | KILL_OR_RETURN_ERRNO, |
296 | RETURN_ALLOW | 296 | RETURN_ALLOW |
297 | #endif | 297 | #endif |
298 | }; | 298 | }; |
@@ -327,7 +327,7 @@ void memory_deny_write_execute_32(const char *fname) { | |||
327 | EXAMINE_ARGUMENT(2), | 327 | EXAMINE_ARGUMENT(2), |
328 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_WRITE|PROT_EXEC), | 328 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_WRITE|PROT_EXEC), |
329 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_WRITE|PROT_EXEC, 0, 1), | 329 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_WRITE|PROT_EXEC, 0, 1), |
330 | KILL_PROCESS, | 330 | KILL_OR_RETURN_ERRNO, |
331 | RETURN_ALLOW, | 331 | RETURN_ALLOW, |
332 | #endif | 332 | #endif |
333 | #ifdef mprotect_32 | 333 | #ifdef mprotect_32 |
@@ -336,7 +336,7 @@ void memory_deny_write_execute_32(const char *fname) { | |||
336 | EXAMINE_ARGUMENT(2), | 336 | EXAMINE_ARGUMENT(2), |
337 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC), | 337 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC), |
338 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1), | 338 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1), |
339 | KILL_PROCESS, | 339 | KILL_OR_RETURN_ERRNO, |
340 | RETURN_ALLOW, | 340 | RETURN_ALLOW, |
341 | #endif | 341 | #endif |
342 | #ifdef pkey_mprotect_32 | 342 | #ifdef pkey_mprotect_32 |
@@ -345,7 +345,7 @@ void memory_deny_write_execute_32(const char *fname) { | |||
345 | EXAMINE_ARGUMENT(2), | 345 | EXAMINE_ARGUMENT(2), |
346 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC), | 346 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC), |
347 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1), | 347 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1), |
348 | KILL_PROCESS, | 348 | KILL_OR_RETURN_ERRNO, |
349 | RETURN_ALLOW, | 349 | RETURN_ALLOW, |
350 | #endif | 350 | #endif |
351 | 351 | ||
@@ -355,7 +355,7 @@ void memory_deny_write_execute_32(const char *fname) { | |||
355 | EXAMINE_ARGUMENT(2), | 355 | EXAMINE_ARGUMENT(2), |
356 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, SHM_EXEC), | 356 | BPF_STMT(BPF_ALU+BPF_AND+BPF_K, SHM_EXEC), |
357 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SHM_EXEC, 0, 1), | 357 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SHM_EXEC, 0, 1), |
358 | KILL_PROCESS, | 358 | KILL_OR_RETURN_ERRNO, |
359 | RETURN_ALLOW, | 359 | RETURN_ALLOW, |
360 | #endif | 360 | #endif |
361 | #ifdef memfd_create_32 | 361 | #ifdef memfd_create_32 |
@@ -363,7 +363,7 @@ void memory_deny_write_execute_32(const char *fname) { | |||
363 | // arbitrary memory contents which can be later mapped | 363 | // arbitrary memory contents which can be later mapped |
364 | // as executable | 364 | // as executable |
365 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, memfd_create_32, 0, 1), | 365 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, memfd_create_32, 0, 1), |
366 | KILL_PROCESS, | 366 | KILL_OR_RETURN_ERRNO, |
367 | #endif | 367 | #endif |
368 | #endif | 368 | #endif |
369 | RETURN_ALLOW | 369 | RETURN_ALLOW |
diff --git a/src/fseccomp/seccomp_file.c b/src/fseccomp/seccomp_file.c index 872b41261..9e8ceb898 100644 --- a/src/fseccomp/seccomp_file.c +++ b/src/fseccomp/seccomp_file.c | |||
@@ -112,6 +112,19 @@ void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg, bool nativ | |||
112 | } | 112 | } |
113 | } | 113 | } |
114 | 114 | ||
115 | void filter_add_blacklist_override(int fd, int syscall, int arg, void *ptrarg, bool native) { | ||
116 | (void) arg; | ||
117 | (void) ptrarg; | ||
118 | (void) native; | ||
119 | |||
120 | if (syscall >= 0) { | ||
121 | int saved_error_action = arg_seccomp_error_action; | ||
122 | arg_seccomp_error_action = SECCOMP_RET_KILL; | ||
123 | write_blacklist(fd, syscall); | ||
124 | arg_seccomp_error_action = saved_error_action; | ||
125 | } | ||
126 | } | ||
127 | |||
115 | // handle seccomp list exceptions (seccomp x,y,!z) | 128 | // handle seccomp list exceptions (seccomp x,y,!z) |
116 | void filter_add_blacklist_for_excluded(int fd, int syscall, int arg, void *ptrarg, bool native) { | 129 | void filter_add_blacklist_for_excluded(int fd, int syscall, int arg, void *ptrarg, bool native) { |
117 | (void) arg; | 130 | (void) arg; |
@@ -142,7 +155,7 @@ void filter_end_blacklist(int fd) { | |||
142 | 155 | ||
143 | void filter_end_whitelist(int fd) { | 156 | void filter_end_whitelist(int fd) { |
144 | struct sock_filter filter[] = { | 157 | struct sock_filter filter[] = { |
145 | KILL_PROCESS | 158 | KILL_OR_RETURN_ERRNO |
146 | }; | 159 | }; |
147 | write_to_file(fd, filter, sizeof(filter)); | 160 | write_to_file(fd, filter, sizeof(filter)); |
148 | } | 161 | } |
diff --git a/src/fseccomp/seccomp_secondary.c b/src/fseccomp/seccomp_secondary.c index 9a00d1884..f024859d3 100644 --- a/src/fseccomp/seccomp_secondary.c +++ b/src/fseccomp/seccomp_secondary.c | |||
@@ -142,7 +142,7 @@ void seccomp_secondary_block(const char *fname) { | |||
142 | // 5: if MSW(arg0) == 0, goto 7 (allow) else continue to 6 (kill) | 142 | // 5: if MSW(arg0) == 0, goto 7 (allow) else continue to 6 (kill) |
143 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, jmp_from_to(5, 7), 0), | 143 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, jmp_from_to(5, 7), 0), |
144 | // 6: | 144 | // 6: |
145 | KILL_PROCESS, | 145 | KILL_OR_RETURN_ERRNO, |
146 | // 7: | 146 | // 7: |
147 | RETURN_ALLOW | 147 | RETURN_ALLOW |
148 | }; | 148 | }; |
diff --git a/src/include/seccomp.h b/src/include/seccomp.h index 80a83df34..50920ce3a 100644 --- a/src/include/seccomp.h +++ b/src/include/seccomp.h | |||
@@ -243,7 +243,7 @@ struct seccomp_data { | |||
243 | #define HANDLE_X32_KILL \ | 243 | #define HANDLE_X32_KILL \ |
244 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), \ | 244 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), \ |
245 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), \ | 245 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), \ |
246 | KILL_PROCESS | 246 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) |
247 | #endif | 247 | #endif |
248 | 248 | ||
249 | #define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ | 249 | #define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ |
@@ -258,7 +258,7 @@ struct seccomp_data { | |||
258 | 258 | ||
259 | #define BLACKLIST(syscall_nr) \ | 259 | #define BLACKLIST(syscall_nr) \ |
260 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ | 260 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ |
261 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) | 261 | KILL_OR_RETURN_ERRNO |
262 | 262 | ||
263 | #define WHITELIST(syscall_nr) \ | 263 | #define WHITELIST(syscall_nr) \ |
264 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ | 264 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ |
@@ -274,7 +274,8 @@ struct seccomp_data { | |||
274 | #define RETURN_ERRNO(nr) \ | 274 | #define RETURN_ERRNO(nr) \ |
275 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO | nr) | 275 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO | nr) |
276 | 276 | ||
277 | #define KILL_PROCESS \ | 277 | extern int arg_seccomp_error_action; // error action: errno or kill |
278 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) | 278 | #define KILL_OR_RETURN_ERRNO \ |
279 | BPF_STMT(BPF_RET+BPF_K, arg_seccomp_error_action) | ||
279 | 280 | ||
280 | #endif | 281 | #endif |
diff --git a/src/include/syscall.h b/src/include/syscall.h index 9841fc7ab..89b54170e 100644 --- a/src/include/syscall.h +++ b/src/include/syscall.h | |||
@@ -27,6 +27,7 @@ extern int arg_quiet; | |||
27 | 27 | ||
28 | // seccomp_file.c or dummy versions in firejail/main.c and fsec-print/main.c | 28 | // seccomp_file.c or dummy versions in firejail/main.c and fsec-print/main.c |
29 | void filter_add_errno(int fd, int syscall, int arg, void *ptrarg, bool native); | 29 | void filter_add_errno(int fd, int syscall, int arg, void *ptrarg, bool native); |
30 | void filter_add_blacklist_override(int fd, int syscall, int arg, void *ptrarg, bool native); | ||
30 | 31 | ||
31 | // errno.c | 32 | // errno.c |
32 | void errno_print(void); | 33 | void errno_print(void); |
diff --git a/src/lib/syscall.c b/src/lib/syscall.c index 1cf7f2d52..5accdcb65 100644 --- a/src/lib/syscall.c +++ b/src/lib/syscall.c | |||
@@ -20,11 +20,16 @@ | |||
20 | #define _GNU_SOURCE | 20 | #define _GNU_SOURCE |
21 | #include "../include/syscall.h" | 21 | #include "../include/syscall.h" |
22 | #include <assert.h> | 22 | #include <assert.h> |
23 | #include <limits.h> | ||
23 | #include <stdbool.h> | 24 | #include <stdbool.h> |
24 | #include <stdio.h> | 25 | #include <stdio.h> |
25 | #include <string.h> | 26 | #include <string.h> |
26 | #include <sys/syscall.h> | 27 | #include <sys/syscall.h> |
27 | #include "../include/common.h" | 28 | #include "../include/common.h" |
29 | #include "../include/seccomp.h" | ||
30 | |||
31 | #define SYSCALL_ERROR INT_MAX | ||
32 | #define ERRNO_KILL -2 | ||
28 | 33 | ||
29 | typedef struct { | 34 | typedef struct { |
30 | const char * const name; | 35 | const char * const name; |
@@ -1430,7 +1435,7 @@ static const SyscallGroupList sysgroups[] = { | |||
1430 | } | 1435 | } |
1431 | }; | 1436 | }; |
1432 | 1437 | ||
1433 | // return -1 if error, or syscall number | 1438 | // return SYSCALL_ERROR if error, or syscall number |
1434 | static int syscall_find_name(const char *name) { | 1439 | static int syscall_find_name(const char *name) { |
1435 | int i; | 1440 | int i; |
1436 | int elems = sizeof(syslist) / sizeof(syslist[0]); | 1441 | int elems = sizeof(syslist) / sizeof(syslist[0]); |
@@ -1439,7 +1444,7 @@ static int syscall_find_name(const char *name) { | |||
1439 | return syslist[i].nr; | 1444 | return syslist[i].nr; |
1440 | } | 1445 | } |
1441 | 1446 | ||
1442 | return -1; | 1447 | return SYSCALL_ERROR; |
1443 | } | 1448 | } |
1444 | 1449 | ||
1445 | static int syscall_find_name_32(const char *name) { | 1450 | static int syscall_find_name_32(const char *name) { |
@@ -1450,7 +1455,7 @@ static int syscall_find_name_32(const char *name) { | |||
1450 | return syslist32[i].nr; | 1455 | return syslist32[i].nr; |
1451 | } | 1456 | } |
1452 | 1457 | ||
1453 | return -1; | 1458 | return SYSCALL_ERROR; |
1454 | } | 1459 | } |
1455 | 1460 | ||
1456 | const char *syscall_find_nr(int nr) { | 1461 | const char *syscall_find_nr(int nr) { |
@@ -1538,9 +1543,13 @@ static void syscall_process_name(const char *name, int *syscall_nr, int *error_n | |||
1538 | *syscall_nr = syscall_find_name_32(syscall_name); | 1543 | *syscall_nr = syscall_find_name_32(syscall_name); |
1539 | } | 1544 | } |
1540 | if (error_name) { | 1545 | if (error_name) { |
1541 | *error_nr = errno_find_name(error_name); | 1546 | if (strcmp(error_name, "kill") == 0) |
1542 | if (*error_nr == -1) | 1547 | *error_nr = ERRNO_KILL; |
1543 | *syscall_nr = -1; | 1548 | else { |
1549 | *error_nr = errno_find_name(error_name); | ||
1550 | if (*error_nr == -1) | ||
1551 | *syscall_nr = SYSCALL_ERROR; | ||
1552 | } | ||
1544 | } | 1553 | } |
1545 | 1554 | ||
1546 | free(str); | 1555 | free(str); |
@@ -1589,15 +1598,15 @@ int syscall_check_list(const char *slist, filter_fn *callback, int fd, int arg, | |||
1589 | ptr++; | 1598 | ptr++; |
1590 | } | 1599 | } |
1591 | syscall_process_name(ptr, &syscall_nr, &error_nr, native); | 1600 | syscall_process_name(ptr, &syscall_nr, &error_nr, native); |
1592 | if (syscall_nr == -1) {;} | 1601 | if (syscall_nr != SYSCALL_ERROR && callback != NULL) { |
1593 | else if (callback != NULL) { | ||
1594 | if (negate) { | 1602 | if (negate) { |
1595 | syscall_nr = -syscall_nr; | 1603 | syscall_nr = -syscall_nr; |
1596 | } | 1604 | } |
1597 | if (error_nr != -1 && fd > 0) { | 1605 | if (error_nr >= 0 && fd > 0) |
1598 | filter_add_errno(fd, syscall_nr, error_nr, ptrarg, native); | 1606 | filter_add_errno(fd, syscall_nr, error_nr, ptrarg, native); |
1599 | } | 1607 | else if (error_nr == ERRNO_KILL && fd > 0) |
1600 | else if (error_nr != -1 && fd == 0) { | 1608 | filter_add_blacklist_override(fd, syscall_nr, 0, ptrarg, native); |
1609 | else if (error_nr >= 0 && fd == 0) { | ||
1601 | callback(fd, syscall_nr, error_nr, ptrarg, native); | 1610 | callback(fd, syscall_nr, error_nr, ptrarg, native); |
1602 | } | 1611 | } |
1603 | else { | 1612 | else { |
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 511194ff3..203d4543d 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt | |||
@@ -411,6 +411,9 @@ Enable seccomp filter and whitelist the system calls in the list. | |||
411 | \fBseccomp.32.keep syscall,syscall,syscall | 411 | \fBseccomp.32.keep syscall,syscall,syscall |
412 | Enable seccomp filter and whitelist the system calls in the list for 32 bit system calls on a 64 bit architecture system. | 412 | Enable seccomp filter and whitelist the system calls in the list for 32 bit system calls on a 64 bit architecture system. |
413 | .TP | 413 | .TP |
414 | \fBseccomp-error-action kill | ERRNO | ||
415 | Return a different error instead of EPERM to the process or kill it when an attempt is made to call a blocked system call. | ||
416 | .TP | ||
414 | \fBx11 | 417 | \fBx11 |
415 | Enable X11 sandboxing. | 418 | Enable X11 sandboxing. |
416 | .TP | 419 | .TP |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 1bed40015..02c1d27b2 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -814,8 +814,9 @@ $ firejail \-\-machine-id | |||
814 | Install a seccomp filter to block attempts to create memory mappings | 814 | Install a seccomp filter to block attempts to create memory mappings |
815 | that are both writable and executable, to change mappings to be | 815 | that are both writable and executable, to change mappings to be |
816 | executable, or to create executable shared memory. The filter examines | 816 | executable, or to create executable shared memory. The filter examines |
817 | the arguments of mmap, mmap2, mprotect, pkey_mprotect, memfd_create and | 817 | the arguments of mmap, mmap2, mprotect, pkey_mprotect, memfd_create |
818 | shmat system calls and kills the process if necessary. | 818 | and shmat system calls and returns error EPERM to the process (or |
819 | kills it, see \-\-seccomp-error-action below) if necessary. | ||
819 | .br | 820 | .br |
820 | 821 | ||
821 | .br | 822 | .br |
@@ -1865,8 +1866,12 @@ $ firejail \-\-seccomp=@clock,mkdir,unlinkat transmission-gtk | |||
1865 | .br | 1866 | .br |
1866 | 1867 | ||
1867 | .br | 1868 | .br |
1868 | Instead of dropping the syscall, a specific error number can be returned | 1869 | Instead of dropping the syscall by returning EPERM, another error |
1869 | using \fBsyscall:errorno\fR syntax. | 1870 | number can be returned using \fBsyscall:errno\fR syntax. This can be |
1871 | also changed globally with \-\-seccomp-error-action or | ||
1872 | in /etc/firejail/firejail.config file. The process can also be killed | ||
1873 | by using \fBsyscall:kill\fR syntax. | ||
1874 | |||
1870 | .br | 1875 | .br |
1871 | 1876 | ||
1872 | .br | 1877 | .br |
@@ -1932,8 +1937,11 @@ $ firejail \-\-seccomp.drop=utime,utimensat,utimes,@clock | |||
1932 | .br | 1937 | .br |
1933 | 1938 | ||
1934 | .br | 1939 | .br |
1935 | Instead of dropping the syscall, a specific error number can be returned | 1940 | Instead of dropping the syscall by returning EPERM, another error |
1936 | using \fBsyscall:errorno\fR syntax. | 1941 | number can be returned using \fBsyscall:errno\fR syntax. This can be |
1942 | also changed globally with \-\-seccomp-error-action or | ||
1943 | in /etc/firejail/firejail.config file. The process can also be killed | ||
1944 | by using \fBsyscall:kill\fR syntax. | ||
1937 | .br | 1945 | .br |
1938 | 1946 | ||
1939 | .br | 1947 | .br |
@@ -2135,6 +2143,19 @@ $ firejail --seccomp.print=browser | |||
2135 | 0049: 06 00 01 00000000 ret KILL | 2143 | 0049: 06 00 01 00000000 ret KILL |
2136 | .br | 2144 | .br |
2137 | $ | 2145 | $ |
2146 | |||
2147 | .TP | ||
2148 | \fB\-\-seccomp-error-action= kill | ERRNO | ||
2149 | By default, if a seccomp filter blocks a system call, the process gets | ||
2150 | EPERM as the error. With \-\-seccomp-error-action=error, another error | ||
2151 | number can be returned, for example ENOSYS or EACCES. The process can | ||
2152 | also be killed (like in versions <0.9.63 of Firejail) by using | ||
2153 | \-\-seccomp-error-action=kill syntax. Not killing the process weakens | ||
2154 | Firejail slightly when trying to contain intrusion, but it may also | ||
2155 | allow tighter filters if the only alternative is to allow a system | ||
2156 | call. | ||
2157 | .br | ||
2158 | |||
2138 | .TP | 2159 | .TP |
2139 | \fB\-\-shell=none | 2160 | \fB\-\-shell=none |
2140 | Run the program directly, without a user shell. | 2161 | Run the program directly, without a user shell. |