diff options
author | Topi Miettinen <toiwoton@gmail.com> | 2017-08-19 23:22:38 +0300 |
---|---|---|
committer | Topi Miettinen <toiwoton@gmail.com> | 2017-08-19 23:33:11 +0300 |
commit | d01216de45884300c87e7d3ccb70e53ebb461449 (patch) | |
tree | 480519f5849df4c6048a7f62ec97f96e51174c3e /src | |
parent | Merge update after #1483 (diff) | |
download | firejail-d01216de45884300c87e7d3ccb70e53ebb461449.tar.gz firejail-d01216de45884300c87e7d3ccb70e53ebb461449.tar.zst firejail-d01216de45884300c87e7d3ccb70e53ebb461449.zip |
Feature: switch/config option to block secondary architectures
Add a feature for a new (opt-in) command line switch and config file
option to block secondary architectures entirely. Also block changing
Linux execution domain with personality() system call for the primary
architecture.
Closes #1479
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/firejail.h | 5 | ||||
-rw-r--r-- | src/firejail/main.c | 12 | ||||
-rw-r--r-- | src/firejail/preproc.c | 10 | ||||
-rw-r--r-- | src/firejail/profile.c | 10 | ||||
-rw-r--r-- | src/firejail/seccomp.c | 35 | ||||
-rw-r--r-- | src/fseccomp/fseccomp.h | 1 | ||||
-rw-r--r-- | src/fseccomp/main.c | 3 | ||||
-rw-r--r-- | src/fseccomp/seccomp_print.c | 19 | ||||
-rw-r--r-- | src/fseccomp/seccomp_secondary.c | 97 | ||||
-rw-r--r-- | src/include/seccomp.h | 9 | ||||
-rw-r--r-- | src/man/firejail-profile.txt | 4 | ||||
-rw-r--r-- | src/man/firejail.txt | 15 |
12 files changed, 173 insertions, 47 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 90f88ef37..71c5ae87c 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -57,12 +57,14 @@ | |||
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_BLOCK_SECONDARY "/run/firejail/mnt/seccomp.block_secondary" // secondary arch blocking filter | ||
60 | #define RUN_SECCOMP_POSTEXEC "/run/firejail/mnt/seccomp.postexec" // filter for post-exec library | 61 | #define RUN_SECCOMP_POSTEXEC "/run/firejail/mnt/seccomp.postexec" // filter for post-exec library |
61 | #define PATH_SECCOMP_DEFAULT (LIBDIR "/firejail/seccomp") // default filter built during make | 62 | #define PATH_SECCOMP_DEFAULT (LIBDIR "/firejail/seccomp") // default filter built during make |
62 | #define PATH_SECCOMP_DEFAULT_DEBUG (LIBDIR "/firejail/seccomp.debug") // default filter built during make | 63 | #define PATH_SECCOMP_DEFAULT_DEBUG (LIBDIR "/firejail/seccomp.debug") // default filter built during make |
63 | #define PATH_SECCOMP_AMD64 (LIBDIR "/firejail/seccomp.amd64") // amd64 filter built during make | 64 | #define PATH_SECCOMP_AMD64 (LIBDIR "/firejail/seccomp.amd64") // amd64 filter built during make |
64 | #define PATH_SECCOMP_I386 (LIBDIR "/firejail/seccomp.i386") // i386 filter built during make | 65 | #define PATH_SECCOMP_I386 (LIBDIR "/firejail/seccomp.i386") // i386 filter built during make |
65 | #define PATH_SECCOMP_MDWX (LIBDIR "/firejail/seccomp.mdwx") // filter for memory-deny-write-execute built during make | 66 | #define PATH_SECCOMP_MDWX (LIBDIR "/firejail/seccomp.mdwx") // filter for memory-deny-write-execute built during make |
67 | #define PATH_SECCOMP_BLOCK_SECONDARY (LIBDIR "/firejail/seccomp.block_secondary") // secondary arch blocking filter built during make | ||
66 | 68 | ||
67 | 69 | ||
68 | #define RUN_DEV_DIR "/run/firejail/mnt/dev" | 70 | #define RUN_DEV_DIR "/run/firejail/mnt/dev" |
@@ -307,6 +309,7 @@ extern int arg_overlay_reuse; // allow the reuse of overlays | |||
307 | 309 | ||
308 | extern int arg_seccomp; // enable default seccomp filter | 310 | extern int arg_seccomp; // enable default seccomp filter |
309 | extern int arg_seccomp_postexec; // need postexec ld.preload library? | 311 | extern int arg_seccomp_postexec; // need postexec ld.preload library? |
312 | extern int arg_seccomp_block_secondary; // block any secondary architectures | ||
310 | 313 | ||
311 | extern int arg_caps_default_filter; // enable default capabilities filter | 314 | extern int arg_caps_default_filter; // enable default capabilities filter |
312 | extern int arg_caps_drop; // drop list | 315 | extern int arg_caps_drop; // drop list |
@@ -538,8 +541,6 @@ void fs_private_home_list(void); | |||
538 | char *seccomp_check_list(const char *str); | 541 | char *seccomp_check_list(const char *str); |
539 | int seccomp_install_filters(void); | 542 | int seccomp_install_filters(void); |
540 | int seccomp_load(const char *fname); | 543 | int seccomp_load(const char *fname); |
541 | void seccomp_filter_32(void); | ||
542 | void seccomp_filter_64(void); | ||
543 | int seccomp_filter_drop(int enforce_seccomp); | 544 | int seccomp_filter_drop(int enforce_seccomp); |
544 | int seccomp_filter_keep(void); | 545 | int seccomp_filter_keep(void); |
545 | void seccomp_print_filter(pid_t pid); | 546 | void seccomp_print_filter(pid_t pid); |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 71a37beb7..3f805a7e0 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -57,6 +57,7 @@ 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 | int arg_seccomp_postexec = 0; // need postexec ld.preload library? |
60 | int arg_seccomp_block_secondary = 0; // block any secondary architectures | ||
60 | 61 | ||
61 | int arg_caps_default_filter = 0; // enable default capabilities filter | 62 | int arg_caps_default_filter = 0; // enable default capabilities filter |
62 | int arg_caps_drop = 0; // drop list | 63 | int arg_caps_drop = 0; // drop list |
@@ -1147,6 +1148,13 @@ int main(int argc, char **argv) { | |||
1147 | else | 1148 | else |
1148 | exit_err_feature("seccomp"); | 1149 | exit_err_feature("seccomp"); |
1149 | } | 1150 | } |
1151 | else if (strcmp(argv[i], "--seccomp.block-secondary") == 0) { | ||
1152 | if (checkcfg(CFG_SECCOMP)) { | ||
1153 | arg_seccomp_block_secondary = 1; | ||
1154 | } | ||
1155 | else | ||
1156 | exit_err_feature("seccomp"); | ||
1157 | } | ||
1150 | else if (strcmp(argv[i], "--memory-deny-write-execute") == 0) { | 1158 | else if (strcmp(argv[i], "--memory-deny-write-execute") == 0) { |
1151 | if (checkcfg(CFG_SECCOMP)) | 1159 | if (checkcfg(CFG_SECCOMP)) |
1152 | arg_memory_deny_write_execute = 1; | 1160 | arg_memory_deny_write_execute = 1; |
@@ -2239,6 +2247,10 @@ int main(int argc, char **argv) { | |||
2239 | } | 2247 | } |
2240 | } | 2248 | } |
2241 | 2249 | ||
2250 | // enable seccomp if only seccomp.block-secondary was specified | ||
2251 | if (arg_seccomp_block_secondary) | ||
2252 | arg_seccomp = 1; | ||
2253 | |||
2242 | // log command | 2254 | // log command |
2243 | logargs(argc, argv); | 2255 | logargs(argc, argv); |
2244 | if (fullargc) { | 2256 | if (fullargc) { |
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c index 583cc4610..bf1ef0469 100644 --- a/src/firejail/preproc.c +++ b/src/firejail/preproc.c | |||
@@ -75,9 +75,13 @@ void preproc_mount_mnt_dir(void) { | |||
75 | tmpfs_mounted = 1; | 75 | tmpfs_mounted = 1; |
76 | fs_logger2("tmpfs", RUN_MNT_DIR); | 76 | fs_logger2("tmpfs", RUN_MNT_DIR); |
77 | 77 | ||
78 | //copy defaultl seccomp files | 78 | if (arg_seccomp_block_secondary) |
79 | copy_file(PATH_SECCOMP_I386, RUN_SECCOMP_I386, getuid(), getgid(), 0644); // root needed | 79 | copy_file(PATH_SECCOMP_BLOCK_SECONDARY, RUN_SECCOMP_BLOCK_SECONDARY, getuid(), getgid(), 0644); // root needed |
80 | copy_file(PATH_SECCOMP_AMD64, RUN_SECCOMP_AMD64, getuid(), getgid(), 0644); // root needed | 80 | else { |
81 | //copy default seccomp files | ||
82 | copy_file(PATH_SECCOMP_I386, RUN_SECCOMP_I386, getuid(), getgid(), 0644); // root needed | ||
83 | copy_file(PATH_SECCOMP_AMD64, RUN_SECCOMP_AMD64, getuid(), getgid(), 0644); // root needed | ||
84 | } | ||
81 | if (arg_allow_debuggers) | 85 | if (arg_allow_debuggers) |
82 | copy_file(PATH_SECCOMP_DEFAULT_DEBUG, RUN_SECCOMP_CFG, getuid(), getgid(), 0644); // root needed | 86 | copy_file(PATH_SECCOMP_DEFAULT_DEBUG, RUN_SECCOMP_CFG, getuid(), getgid(), 0644); // root needed |
83 | else | 87 | else |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 7753ee3b2..fc390c83a 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -577,6 +577,16 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
577 | return 0; | 577 | return 0; |
578 | } | 578 | } |
579 | 579 | ||
580 | if (strcmp(ptr, "seccomp.block-secondary") == 0) { | ||
581 | #ifdef HAVE_SECCOMP | ||
582 | if (checkcfg(CFG_SECCOMP)) { | ||
583 | arg_seccomp_block_secondary = 1; | ||
584 | } | ||
585 | else | ||
586 | warning_feature_disabled("seccomp"); | ||
587 | #endif | ||
588 | return 0; | ||
589 | } | ||
580 | // seccomp drop list without default list | 590 | // seccomp drop list without default list |
581 | if (strncmp(ptr, "seccomp.drop ", 13) == 0) { | 591 | if (strncmp(ptr, "seccomp.drop ", 13) == 0) { |
582 | #ifdef HAVE_SECCOMP | 592 | #ifdef HAVE_SECCOMP |
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index e855ce7ed..aaf53b2a1 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c | |||
@@ -118,7 +118,7 @@ errexit: | |||
118 | } | 118 | } |
119 | 119 | ||
120 | // i386 filter installed on amd64 architectures | 120 | // i386 filter installed on amd64 architectures |
121 | void seccomp_filter_32(void) { | 121 | static void seccomp_filter_32(void) { |
122 | if (seccomp_load(RUN_SECCOMP_I386) == 0) { | 122 | if (seccomp_load(RUN_SECCOMP_I386) == 0) { |
123 | if (arg_debug) | 123 | if (arg_debug) |
124 | printf("Dual i386/amd64 seccomp filter configured\n"); | 124 | printf("Dual i386/amd64 seccomp filter configured\n"); |
@@ -126,13 +126,20 @@ void seccomp_filter_32(void) { | |||
126 | } | 126 | } |
127 | 127 | ||
128 | // amd64 filter installed on i386 architectures | 128 | // amd64 filter installed on i386 architectures |
129 | void seccomp_filter_64(void) { | 129 | static void seccomp_filter_64(void) { |
130 | if (seccomp_load(RUN_SECCOMP_AMD64) == 0) { | 130 | if (seccomp_load(RUN_SECCOMP_AMD64) == 0) { |
131 | if (arg_debug) | 131 | if (arg_debug) |
132 | printf("Dual i386/amd64 seccomp filter configured\n"); | 132 | printf("Dual i386/amd64 seccomp filter configured\n"); |
133 | } | 133 | } |
134 | } | 134 | } |
135 | 135 | ||
136 | static void seccomp_filter_block_secondary(void) { | ||
137 | if (seccomp_load(RUN_SECCOMP_BLOCK_SECONDARY) == 0) { | ||
138 | if (arg_debug) | ||
139 | printf("Secondary arch blocking seccomp filter configured\n"); | ||
140 | } | ||
141 | } | ||
142 | |||
136 | // drop filter for seccomp option | 143 | // drop filter for seccomp option |
137 | int seccomp_filter_drop(int enforce_seccomp) { | 144 | int seccomp_filter_drop(int enforce_seccomp) { |
138 | // if we have multiple seccomp commands, only one of them is executed | 145 | // if we have multiple seccomp commands, only one of them is executed |
@@ -143,21 +150,29 @@ int seccomp_filter_drop(int enforce_seccomp) { | |||
143 | if (cfg.seccomp_list_drop == NULL) { | 150 | if (cfg.seccomp_list_drop == NULL) { |
144 | // default seccomp | 151 | // default seccomp |
145 | if (cfg.seccomp_list == NULL) { | 152 | if (cfg.seccomp_list == NULL) { |
153 | if (arg_seccomp_block_secondary) | ||
154 | seccomp_filter_block_secondary(); | ||
155 | else { | ||
146 | #if defined(__x86_64__) | 156 | #if defined(__x86_64__) |
147 | seccomp_filter_32(); | 157 | seccomp_filter_32(); |
148 | #endif | 158 | #endif |
149 | #if defined(__i386__) | 159 | #if defined(__i386__) |
150 | seccomp_filter_64(); | 160 | seccomp_filter_64(); |
151 | #endif | 161 | #endif |
162 | } | ||
152 | } | 163 | } |
153 | // default seccomp filter with additional drop list | 164 | // default seccomp filter with additional drop list |
154 | else { // cfg.seccomp_list != NULL | 165 | else { // cfg.seccomp_list != NULL |
166 | if (arg_seccomp_block_secondary) | ||
167 | seccomp_filter_block_secondary(); | ||
168 | else { | ||
155 | #if defined(__x86_64__) | 169 | #if defined(__x86_64__) |
156 | seccomp_filter_32(); | 170 | seccomp_filter_32(); |
157 | #endif | 171 | #endif |
158 | #if defined(__i386__) | 172 | #if defined(__i386__) |
159 | seccomp_filter_64(); | 173 | seccomp_filter_64(); |
160 | #endif | 174 | #endif |
175 | } | ||
161 | if (arg_debug) | 176 | if (arg_debug) |
162 | printf("Build default+drop seccomp filter\n"); | 177 | printf("Build default+drop seccomp filter\n"); |
163 | 178 | ||
@@ -175,7 +190,10 @@ int seccomp_filter_drop(int enforce_seccomp) { | |||
175 | } | 190 | } |
176 | 191 | ||
177 | // drop list without defaults - secondary filters are not installed | 192 | // drop list without defaults - secondary filters are not installed |
193 | // except when secondary architectures are explicitly blocked | ||
178 | else { // cfg.seccomp_list_drop != NULL | 194 | else { // cfg.seccomp_list_drop != NULL |
195 | if (arg_seccomp_block_secondary) | ||
196 | seccomp_filter_block_secondary(); | ||
179 | if (arg_debug) | 197 | if (arg_debug) |
180 | printf("Build drop seccomp filter\n"); | 198 | printf("Build drop seccomp filter\n"); |
181 | 199 | ||
@@ -216,6 +234,11 @@ int seccomp_filter_drop(int enforce_seccomp) { | |||
216 | 234 | ||
217 | // keep filter for seccomp option | 235 | // keep filter for seccomp option |
218 | int seccomp_filter_keep(void) { | 236 | int seccomp_filter_keep(void) { |
237 | // secondary filters are not installed except when secondary | ||
238 | // architectures are explicitly blocked | ||
239 | if (arg_seccomp_block_secondary) | ||
240 | seccomp_filter_block_secondary(); | ||
241 | |||
219 | if (arg_debug) | 242 | if (arg_debug) |
220 | printf("Build drop seccomp filter\n"); | 243 | printf("Build drop seccomp filter\n"); |
221 | 244 | ||
diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h index 144b612ae..2deb282f5 100644 --- a/src/fseccomp/fseccomp.h +++ b/src/fseccomp/fseccomp.h | |||
@@ -46,6 +46,7 @@ void protocol_build_filter(const char *prlist, const char *fname); | |||
46 | // seccomp_secondary.c | 46 | // seccomp_secondary.c |
47 | void seccomp_secondary_64(const char *fname); | 47 | void seccomp_secondary_64(const char *fname); |
48 | void seccomp_secondary_32(const char *fname); | 48 | void seccomp_secondary_32(const char *fname); |
49 | void seccomp_secondary_block(const char *fname); | ||
49 | 50 | ||
50 | // seccomp_file.c | 51 | // seccomp_file.c |
51 | void write_to_file(int fd, const void *data, int size); | 52 | void write_to_file(int fd, const void *data, int size); |
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index 3bf7de0fa..ae0ae64ef 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c | |||
@@ -28,6 +28,7 @@ static void usage(void) { | |||
28 | printf("\tfseccomp protocol build list file\n"); | 28 | printf("\tfseccomp protocol build list file\n"); |
29 | printf("\tfseccomp secondary 64 file\n"); | 29 | printf("\tfseccomp secondary 64 file\n"); |
30 | printf("\tfseccomp secondary 32 file\n"); | 30 | printf("\tfseccomp secondary 32 file\n"); |
31 | printf("\tfseccomp secondary block file\n"); | ||
31 | printf("\tfseccomp default file\n"); | 32 | printf("\tfseccomp default file\n"); |
32 | printf("\tfseccomp default file allow-debuggers\n"); | 33 | printf("\tfseccomp default file allow-debuggers\n"); |
33 | printf("\tfseccomp drop file1 file2 list\n"); | 34 | printf("\tfseccomp drop file1 file2 list\n"); |
@@ -74,6 +75,8 @@ printf("\n"); | |||
74 | seccomp_secondary_64(argv[3]); | 75 | seccomp_secondary_64(argv[3]); |
75 | else if (argc == 4 && strcmp(argv[1], "secondary") == 0 && strcmp(argv[2], "32") == 0) | 76 | else if (argc == 4 && strcmp(argv[1], "secondary") == 0 && strcmp(argv[2], "32") == 0) |
76 | seccomp_secondary_32(argv[3]); | 77 | seccomp_secondary_32(argv[3]); |
78 | else if (argc == 4 && strcmp(argv[1], "secondary") == 0 && strcmp(argv[2], "block") == 0) | ||
79 | seccomp_secondary_block(argv[3]); | ||
77 | else if (argc == 3 && strcmp(argv[1], "default") == 0) | 80 | else if (argc == 3 && strcmp(argv[1], "default") == 0) |
78 | seccomp_default(argv[2], 0); | 81 | seccomp_default(argv[2], 0); |
79 | else if (argc == 4 && strcmp(argv[1], "default") == 0 && strcmp(argv[3], "allow-debuggers") == 0) | 82 | else if (argc == 4 && strcmp(argv[1], "default") == 0 && strcmp(argv[3], "allow-debuggers") == 0) |
diff --git a/src/fseccomp/seccomp_print.c b/src/fseccomp/seccomp_print.c index 19fe7a545..7af95d51c 100644 --- a/src/fseccomp/seccomp_print.c +++ b/src/fseccomp/seccomp_print.c | |||
@@ -113,6 +113,25 @@ static int detect_filter_type(void) { | |||
113 | printf(" EXAMINE_SYSCALL\n"); | 113 | printf(" EXAMINE_SYSCALL\n"); |
114 | return sizeof(start_secondary_32) / sizeof(struct sock_filter); | 114 | return sizeof(start_secondary_32) / sizeof(struct sock_filter); |
115 | } | 115 | } |
116 | |||
117 | const struct sock_filter start_secondary_block[] = { | ||
118 | VALIDATE_ARCHITECTURE_KILL, | ||
119 | #if defined(__x86_64__) | ||
120 | EXAMINE_SYSCALL, | ||
121 | HANDLE_X32_KILL, | ||
122 | #else | ||
123 | EXAMINE_SYSCALL | ||
124 | #endif | ||
125 | }; | ||
126 | |||
127 | if (memcmp(&start_secondary_block[0], filter, sizeof(start_secondary_block)) == 0) { | ||
128 | printf(" VALIDATE_ARCHITECTURE_KILL\n"); | ||
129 | printf(" EXAMINE_SYSCALL\n"); | ||
130 | #if defined(__x86_64__) | ||
131 | printf(" HANDLE_X32_KILL\n"); | ||
132 | #endif | ||
133 | return sizeof(start_secondary_block) / sizeof(struct sock_filter); | ||
134 | } | ||
116 | 135 | ||
117 | return 0; // filter unrecognized | 136 | return 0; // filter unrecognized |
118 | } | 137 | } |
diff --git a/src/fseccomp/seccomp_secondary.c b/src/fseccomp/seccomp_secondary.c index fceb2c3ec..dd69b58cc 100644 --- a/src/fseccomp/seccomp_secondary.c +++ b/src/fseccomp/seccomp_secondary.c | |||
@@ -19,8 +19,29 @@ | |||
19 | */ | 19 | */ |
20 | #include "fseccomp.h" | 20 | #include "fseccomp.h" |
21 | #include "../include/seccomp.h" | 21 | #include "../include/seccomp.h" |
22 | #include <sys/personality.h> | ||
22 | #include <sys/syscall.h> | 23 | #include <sys/syscall.h> |
23 | 24 | ||
25 | static void write_filter(const char *fname, size_t size, const void *filter) { | ||
26 | // save filter to file | ||
27 | int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
28 | if (dst < 0) { | ||
29 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); | ||
30 | exit(1); | ||
31 | } | ||
32 | |||
33 | size_t written = 0; | ||
34 | while (written < size) { | ||
35 | ssize_t rv = write(dst, (unsigned char *) filter + written, size - written); | ||
36 | if (rv == -1) { | ||
37 | fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); | ||
38 | exit(1); | ||
39 | } | ||
40 | written += rv; | ||
41 | } | ||
42 | close(dst); | ||
43 | } | ||
44 | |||
24 | void seccomp_secondary_64(const char *fname) { | 45 | void seccomp_secondary_64(const char *fname) { |
25 | // hardcoded syscall values | 46 | // hardcoded syscall values |
26 | struct sock_filter filter[] = { | 47 | struct sock_filter filter[] = { |
@@ -84,23 +105,7 @@ void seccomp_secondary_64(const char *fname) { | |||
84 | }; | 105 | }; |
85 | 106 | ||
86 | // save filter to file | 107 | // save filter to file |
87 | int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | 108 | write_filter(fname, sizeof(filter), filter); |
88 | if (dst < 0) { | ||
89 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); | ||
90 | exit(1); | ||
91 | } | ||
92 | |||
93 | int size = (int) sizeof(filter); | ||
94 | int written = 0; | ||
95 | while (written < size) { | ||
96 | int rv = write(dst, (unsigned char *) filter + written, size - written); | ||
97 | if (rv == -1) { | ||
98 | fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); | ||
99 | exit(1); | ||
100 | } | ||
101 | written += rv; | ||
102 | } | ||
103 | close(dst); | ||
104 | } | 109 | } |
105 | 110 | ||
106 | // i386 filter installed on amd64 architectures | 111 | // i386 filter installed on amd64 architectures |
@@ -166,21 +171,47 @@ void seccomp_secondary_32(const char *fname) { | |||
166 | }; | 171 | }; |
167 | 172 | ||
168 | // save filter to file | 173 | // save filter to file |
169 | int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | 174 | write_filter(fname, sizeof(filter), filter); |
170 | if (dst < 0) { | 175 | } |
171 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); | ||
172 | exit(1); | ||
173 | } | ||
174 | 176 | ||
175 | int size = (int) sizeof(filter); | 177 | #define jmp_from_to(from_addr, to_addr) ((to_addr) - (from_addr) - 1) |
176 | int written = 0; | 178 | |
177 | while (written < size) { | 179 | #if __BYTE_ORDER == __BIG_ENDIAN |
178 | int rv = write(dst, (unsigned char *) filter + written, size - written); | 180 | #define MSW 0 |
179 | if (rv == -1) { | 181 | #define LSW (sizeof(int)) |
180 | fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); | 182 | #else |
181 | exit(1); | 183 | #define MSW (sizeof(int)) |
182 | } | 184 | #define LSW 0 |
183 | written += rv; | 185 | #endif |
184 | } | 186 | |
185 | close(dst); | 187 | void seccomp_secondary_block(const char *fname) { |
188 | struct sock_filter filter[] = { | ||
189 | // block other architectures | ||
190 | VALIDATE_ARCHITECTURE_KILL, | ||
191 | EXAMINE_SYSCALL, | ||
192 | #if defined(__x86_64__) | ||
193 | // block x32 | ||
194 | HANDLE_X32_KILL, | ||
195 | #endif | ||
196 | // block personality(2) where domain != PER_LINUX or 0xffffffff (query current personality) | ||
197 | // 0: if personality(2), continue to 1, else goto 7 (allow) | ||
198 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYS_personality, 0, jmp_from_to(0, 7)), | ||
199 | // 1: get LSW of system call argument 0 | ||
200 | BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, args[0])) + LSW), | ||
201 | // 2: if LSW(arg0) == PER_LINUX, goto step 4, else continue to 3 | ||
202 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, PER_LINUX, jmp_from_to(2, 4), 0), | ||
203 | // 3: if LSW(arg0) == 0xffffffff, continue to 4, else goto 6 (kill) | ||
204 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff, 0, jmp_from_to(3, 6)), | ||
205 | // 4: get MSW of system call argument 0 | ||
206 | BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, args[0])) + MSW), | ||
207 | // 5: if MSW(arg0) == 0, goto 7 (allow) else continue to 6 (kill) | ||
208 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, jmp_from_to(5, 7), 0), | ||
209 | // 6: | ||
210 | KILL_PROCESS, | ||
211 | // 7: | ||
212 | RETURN_ALLOW | ||
213 | }; | ||
214 | |||
215 | // save filter to file | ||
216 | write_filter(fname, sizeof(filter), filter); | ||
186 | } | 217 | } |
diff --git a/src/include/seccomp.h b/src/include/seccomp.h index b1a19a9b6..2f2b2384d 100644 --- a/src/include/seccomp.h +++ b/src/include/seccomp.h | |||
@@ -105,6 +105,11 @@ struct seccomp_data { | |||
105 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ | 105 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ |
106 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) | 106 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) |
107 | 107 | ||
108 | #define VALIDATE_ARCHITECTURE_KILL \ | ||
109 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \ | ||
110 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ | ||
111 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) | ||
112 | |||
108 | #define VALIDATE_ARCHITECTURE_64 \ | 113 | #define VALIDATE_ARCHITECTURE_64 \ |
109 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \ | 114 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \ |
110 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, AUDIT_ARCH_X86_64, 1, 0), \ | 115 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, AUDIT_ARCH_X86_64, 1, 0), \ |
@@ -122,6 +127,10 @@ struct seccomp_data { | |||
122 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), \ | 127 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), \ |
123 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), \ | 128 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), \ |
124 | RETURN_ERRNO(EPERM) | 129 | RETURN_ERRNO(EPERM) |
130 | #define HANDLE_X32_KILL \ | ||
131 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), \ | ||
132 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), \ | ||
133 | KILL_PROCESS | ||
125 | #endif | 134 | #endif |
126 | 135 | ||
127 | #define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ | 136 | #define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ |
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 2a7d926b9..050c3d7e5 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt | |||
@@ -310,6 +310,10 @@ Enable seccomp filter and blacklist the syscalls in the default list. See man 1 | |||
310 | \fBseccomp syscall,syscall,syscall | 310 | \fBseccomp syscall,syscall,syscall |
311 | Enable seccomp filter and blacklist the system calls in the list on top of default seccomp filter. | 311 | Enable seccomp filter and blacklist the system calls in the list on top of default seccomp filter. |
312 | .TP | 312 | .TP |
313 | \fBseccomp.block-secondary | ||
314 | Enable seccomp filter and filter system call architectures | ||
315 | so that only the native architecture is allowed. | ||
316 | .TP | ||
313 | \fBseccomp.drop syscall,syscall,syscall | 317 | \fBseccomp.drop syscall,syscall,syscall |
314 | Enable seccomp filter and blacklist the system calls in the list. | 318 | Enable seccomp filter and blacklist the system calls in the list. |
315 | .TP | 319 | .TP |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 89b815e02..d1970c985 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -1572,9 +1572,10 @@ system call can be specified by its number instead of name with prefix | |||
1572 | $, so for example $165 would be equal to mount on i386. | 1572 | $, so for example $165 would be equal to mount on i386. |
1573 | 1573 | ||
1574 | .br | 1574 | .br |
1575 | System architecture is not strictly imposed. The filter is applied | 1575 | System architecture is strictly imposed only if flag |
1576 | at run time only if the correct architecture was detected. For the case of I386 and AMD64 | 1576 | \-\-seccomp.block_secondary is used. The filter is applied at run time |
1577 | both 32-bit and 64-bit filters are installed. | 1577 | only if the correct architecture was detected. For the case of I386 |
1578 | and AMD64 both 32-bit and 64-bit filters are installed. | ||
1578 | .br | 1579 | .br |
1579 | 1580 | ||
1580 | .br | 1581 | .br |
@@ -1646,6 +1647,14 @@ Bad system call | |||
1646 | .br | 1647 | .br |
1647 | 1648 | ||
1648 | .TP | 1649 | .TP |
1650 | \fB\-\-seccomp.block_secondary | ||
1651 | Enable seccomp filter and filter system call architectures so that | ||
1652 | only the native architecture is allowed. For example, on amd64, i386 | ||
1653 | and x32 system calls are blocked as well as changing the execution | ||
1654 | domain with personality(2) system call. | ||
1655 | .br | ||
1656 | |||
1657 | .TP | ||
1649 | \fB\-\-seccomp.drop=syscall,syscall,syscall | 1658 | \fB\-\-seccomp.drop=syscall,syscall,syscall |
1650 | Enable seccomp filter, and blacklist the syscalls specified by the command. | 1659 | Enable seccomp filter, and blacklist the syscalls specified by the command. |
1651 | .br | 1660 | .br |