aboutsummaryrefslogtreecommitdiffstats
path: root/src/fseccomp/seccomp.c
diff options
context:
space:
mode:
authorLibravatar Topi Miettinen <toiwoton@gmail.com>2020-03-14 00:07:06 +0200
committerLibravatar Topi Miettinen <topimiettinen@users.noreply.github.com>2020-03-28 11:24:25 +0000
commit88eadbf31fe25dcd7c224a5d92f71c79ccf6c9d3 (patch)
tree6b4d2a805a2900755bfc857586a10948b3c8395e /src/fseccomp/seccomp.c
parentAdded compatibility with BetterDiscord (#3300) (diff)
downloadfirejail-88eadbf31fe25dcd7c224a5d92f71c79ccf6c9d3.tar.gz
firejail-88eadbf31fe25dcd7c224a5d92f71c79ccf6c9d3.tar.zst
firejail-88eadbf31fe25dcd7c224a5d92f71c79ccf6c9d3.zip
seccomp: allow defining separate filters for 32-bit arch
System calls (names and numbers) are not exactly the same for 32 bit and 64 bit architectures. Let's allow defining separate filters for 32-bit arch using seccomp.32, seccomp.32.drop, seccomp.32.keep. This is useful for mixed 64/32 bit application environments like Steam and Wine. Implement protocol and mdwx filtering also for 32 bit arch. It's still better to block secondary archs completely if not needed. Lists of supported system calls are also updated. Warn if preload libraries would be needed due to trace, tracelog or postexecseccomp (seccomp.drop=execve etc), because a 32-bit dynamic linker does not understand the 64 bit preload libraries. Closes #3267. Signed-off-by: Topi Miettinen <toiwoton@gmail.com>
Diffstat (limited to 'src/fseccomp/seccomp.c')
-rw-r--r--src/fseccomp/seccomp.c143
1 files changed, 115 insertions, 28 deletions
diff --git a/src/fseccomp/seccomp.c b/src/fseccomp/seccomp.c
index 29aa2f2f5..0db7b5954 100644
--- a/src/fseccomp/seccomp.c
+++ b/src/fseccomp/seccomp.c
@@ -24,12 +24,12 @@
24#include <sys/syscall.h> 24#include <sys/syscall.h>
25#include <sys/types.h> 25#include <sys/types.h>
26 26
27static void add_default_list(int fd, int allow_debuggers) { 27static void add_default_list(int fd, int allow_debuggers, bool native) {
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, NULL); 30 r = syscall_check_list("@default-nodebuggers", filter_add_blacklist, fd, 0, NULL, native);
31 else 31 else
32 r = syscall_check_list("@default", filter_add_blacklist, fd, 0, NULL); 32 r = syscall_check_list("@default", filter_add_blacklist, fd, 0, NULL, native);
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
@@ -46,7 +46,7 @@ static void add_default_list(int fd, int allow_debuggers) {
46} 46}
47 47
48// default list 48// default list
49void seccomp_default(const char *fname, int allow_debuggers) { 49void seccomp_default(const char *fname, int allow_debuggers, bool native) {
50 assert(fname); 50 assert(fname);
51 51
52 // open file 52 // open file
@@ -57,8 +57,8 @@ void seccomp_default(const char *fname, int allow_debuggers) {
57 } 57 }
58 58
59 // build filter (no post-exec filter needed because default list is fine for us) 59 // build filter (no post-exec filter needed because default list is fine for us)
60 filter_init(fd); 60 filter_init(fd, native);
61 add_default_list(fd, allow_debuggers); 61 add_default_list(fd, allow_debuggers, native);
62 filter_end_blacklist(fd); 62 filter_end_blacklist(fd);
63 63
64 // close file 64 // close file
@@ -66,7 +66,7 @@ void seccomp_default(const char *fname, int allow_debuggers) {
66} 66}
67 67
68// drop list 68// drop list
69void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers) { 69void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers, bool native) {
70 assert(fname1); 70 assert(fname1);
71 assert(fname2); 71 assert(fname2);
72 (void) allow_debuggers; // todo: to implemnet it 72 (void) allow_debuggers; // todo: to implemnet it
@@ -79,15 +79,15 @@ void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_
79 } 79 }
80 80
81 // build pre-exec filter: don't blacklist any syscalls in @default-keep 81 // build pre-exec filter: don't blacklist any syscalls in @default-keep
82 filter_init(fd); 82 filter_init(fd, native);
83 83
84 // allow exceptions in form of !syscall 84 // allow exceptions in form of !syscall
85 syscall_check_list(list, filter_add_whitelist_for_excluded, fd, 0, NULL); 85 syscall_check_list(list, filter_add_whitelist_for_excluded, fd, 0, NULL, native);
86 86
87 char *prelist, *postlist; 87 char *prelist, *postlist;
88 syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist); 88 syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist, native);
89 if (prelist) 89 if (prelist)
90 if (syscall_check_list(prelist, filter_add_blacklist, fd, 0, NULL)) { 90 if (syscall_check_list(prelist, filter_add_blacklist, fd, 0, NULL, native)) {
91 fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); 91 fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n");
92 exit(1); 92 exit(1);
93 } 93 }
@@ -106,8 +106,8 @@ void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_
106 } 106 }
107 107
108 // build post-exec filter: blacklist remaining syscalls 108 // build post-exec filter: blacklist remaining syscalls
109 filter_init(fd); 109 filter_init(fd, native);
110 if (syscall_check_list(postlist, filter_add_blacklist, fd, 0, NULL)) { 110 if (syscall_check_list(postlist, filter_add_blacklist, fd, 0, NULL, native)) {
111 fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); 111 fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n");
112 exit(1); 112 exit(1);
113 } 113 }
@@ -118,7 +118,7 @@ void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_
118} 118}
119 119
120// default+drop 120// default+drop
121void seccomp_default_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers) { 121void seccomp_default_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers, bool native) {
122 assert(fname1); 122 assert(fname1);
123 assert(fname2); 123 assert(fname2);
124 124
@@ -131,16 +131,16 @@ void seccomp_default_drop(const char *fname1, const char *fname2, char *list, in
131 131
132 // build pre-exec filter: blacklist @default, don't blacklist 132 // build pre-exec filter: blacklist @default, don't blacklist
133 // any listed syscalls in @default-keep 133 // any listed syscalls in @default-keep
134 filter_init(fd); 134 filter_init(fd, native);
135 135
136 // allow exceptions in form of !syscall 136 // allow exceptions in form of !syscall
137 syscall_check_list(list, filter_add_whitelist_for_excluded, fd, 0, NULL); 137 syscall_check_list(list, filter_add_whitelist_for_excluded, fd, 0, NULL, native);
138 138
139 add_default_list(fd, allow_debuggers); 139 add_default_list(fd, allow_debuggers, native);
140 char *prelist, *postlist; 140 char *prelist, *postlist;
141 syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist); 141 syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist, native);
142 if (prelist) 142 if (prelist)
143 if (syscall_check_list(prelist, filter_add_blacklist, fd, 0, NULL)) { 143 if (syscall_check_list(prelist, filter_add_blacklist, fd, 0, NULL, native)) {
144 fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); 144 fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n");
145 exit(1); 145 exit(1);
146 } 146 }
@@ -160,8 +160,8 @@ void seccomp_default_drop(const char *fname1, const char *fname2, char *list, in
160 } 160 }
161 161
162 // build post-exec filter: blacklist remaining syscalls 162 // build post-exec filter: blacklist remaining syscalls
163 filter_init(fd); 163 filter_init(fd, native);
164 if (syscall_check_list(postlist, filter_add_blacklist, fd, 0, NULL)) { 164 if (syscall_check_list(postlist, filter_add_blacklist, fd, 0, NULL, native)) {
165 fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); 165 fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n");
166 exit(1); 166 exit(1);
167 } 167 }
@@ -171,7 +171,7 @@ void seccomp_default_drop(const char *fname1, const char *fname2, char *list, in
171 close(fd); 171 close(fd);
172} 172}
173 173
174void seccomp_keep(const char *fname1, const char *fname2, char *list) { 174void seccomp_keep(const char *fname1, const char *fname2, char *list, bool native) {
175 (void) fname2; 175 (void) fname2;
176 176
177 // open file for pre-exec filter 177 // open file for pre-exec filter
@@ -182,17 +182,17 @@ void seccomp_keep(const char *fname1, const char *fname2, char *list) {
182 } 182 }
183 183
184 // build pre-exec filter: whitelist also @default-keep 184 // build pre-exec filter: whitelist also @default-keep
185 filter_init(fd); 185 filter_init(fd, native);
186 186
187 // allow exceptions in form of !syscall 187 // allow exceptions in form of !syscall
188 syscall_check_list(list, filter_add_blacklist_for_excluded, fd, 0, NULL); 188 syscall_check_list(list, filter_add_blacklist_for_excluded, fd, 0, NULL, native);
189 189
190 // these syscalls are used by firejail after the seccomp filter is initialized 190 // these syscalls are used by firejail after the seccomp filter is initialized
191 int r; 191 int r;
192 r = syscall_check_list("@default-keep", filter_add_whitelist, fd, 0, NULL); 192 r = syscall_check_list("@default-keep", filter_add_whitelist, fd, 0, NULL, native);
193 assert(r == 0); 193 assert(r == 0);
194 194
195 if (syscall_check_list(list, filter_add_whitelist, fd, 0, NULL)) { 195 if (syscall_check_list(list, filter_add_whitelist, fd, 0, NULL, native)) {
196 fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); 196 fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n");
197 exit(1); 197 exit(1);
198 } 198 }
@@ -206,6 +206,15 @@ void seccomp_keep(const char *fname1, const char *fname2, char *list) {
206#if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) 206#if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__)
207# define filter_syscall SYS_mmap 207# define filter_syscall SYS_mmap
208# undef block_syscall 208# undef block_syscall
209#if defined(__x86_64__)
210// i386 syscalls
211# define filter_syscall_32 192
212# define block_syscall_32 90
213# define mprotect_32 125
214# define pkey_mprotect_32 380
215# define shmat_32 397
216# define memfd_create_32 356
217#endif
209#elif defined(__i386__) 218#elif defined(__i386__)
210# define filter_syscall SYS_mmap2 219# define filter_syscall SYS_mmap2
211# define block_syscall SYS_mmap 220# define block_syscall SYS_mmap
@@ -216,6 +225,12 @@ void seccomp_keep(const char *fname1, const char *fname2, char *list) {
216# warning "Platform does not support seccomp memory-deny-write-execute filter yet" 225# warning "Platform does not support seccomp memory-deny-write-execute filter yet"
217# undef filter_syscall 226# undef filter_syscall
218# undef block_syscall 227# undef block_syscall
228# undef filter_syscall_32
229# undef block_syscall_32
230# undef mprotect_32
231# undef pkey_mprotect_32
232# undef shmat_32
233# undef memfd_create_32
219#endif 234#endif
220 235
221void memory_deny_write_execute(const char *fname) { 236void memory_deny_write_execute(const char *fname) {
@@ -226,10 +241,10 @@ void memory_deny_write_execute(const char *fname) {
226 exit(1); 241 exit(1);
227 } 242 }
228 243
229 filter_init(fd); 244 filter_init(fd, true);
230 245
231 // build filter 246 // build filter
232 static const struct sock_filter filter[] = { 247 struct sock_filter filter[] = {
233#ifdef block_syscall 248#ifdef block_syscall
234 // block old multiplexing mmap syscall for i386 249 // block old multiplexing mmap syscall for i386
235 BLACKLIST(block_syscall), 250 BLACKLIST(block_syscall),
@@ -288,3 +303,75 @@ void memory_deny_write_execute(const char *fname) {
288 // close file 303 // close file
289 close(fd); 304 close(fd);
290} 305}
306
307void memory_deny_write_execute_32(const char *fname) {
308 // open file
309 int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
310 if (fd < 0) {
311 fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname);
312 exit(1);
313 }
314
315 filter_init(fd, false);
316
317 // build filter
318 struct sock_filter filter[] = {
319#if defined(__x86_64__)
320#ifdef block_syscall_32
321 // block old multiplexing mmap syscall for i386
322 BLACKLIST(block_syscall_32),
323#endif
324#ifdef filter_syscall_32
325 // block mmap(,,x|PROT_WRITE|PROT_EXEC) so W&X memory can't be created
326 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, filter_syscall_32, 0, 5),
327 EXAMINE_ARGUMENT(2),
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),
330 KILL_PROCESS,
331 RETURN_ALLOW,
332#endif
333#ifdef mprotect_32
334 // block mprotect(,,PROT_EXEC) so writable memory can't be turned into executable
335 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, mprotect_32, 0, 5),
336 EXAMINE_ARGUMENT(2),
337 BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC),
338 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1),
339 KILL_PROCESS,
340 RETURN_ALLOW,
341#endif
342#ifdef pkey_mprotect_32
343 // same for pkey_mprotect(,,PROT_EXEC), where available
344 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, pkey_mprotect_32, 0, 5),
345 EXAMINE_ARGUMENT(2),
346 BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC),
347 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1),
348 KILL_PROCESS,
349 RETURN_ALLOW,
350#endif
351
352#ifdef shmat_32
353 // block shmat(,,x|SHM_EXEC) so W&X shared memory can't be created
354 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, shmat_32, 0, 5),
355 EXAMINE_ARGUMENT(2),
356 BPF_STMT(BPF_ALU+BPF_AND+BPF_K, SHM_EXEC),
357 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SHM_EXEC, 0, 1),
358 KILL_PROCESS,
359 RETURN_ALLOW,
360#endif
361#ifdef memfd_create_32
362 // block memfd_create as it can be used to create
363 // arbitrary memory contents which can be later mapped
364 // as executable
365 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, memfd_create_32, 0, 1),
366 KILL_PROCESS,
367#endif
368#endif
369 RETURN_ALLOW
370 };
371 write_to_file(fd, filter, sizeof(filter));
372
373 filter_end_blacklist(fd);
374
375 // close file
376 close(fd);
377}