aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/seccomp.c
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2016-11-02 07:49:01 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2016-11-02 07:49:01 -0400
commit72b93c5761b5e42c5742e192f46bac1696c36f4c (patch)
tree3951e01a771ea3e8f11b8364991bb47f752f011f /src/firejail/seccomp.c
parentfixed /run/firejail/mnt problem introduced recently (diff)
downloadfirejail-72b93c5761b5e42c5742e192f46bac1696c36f4c.tar.gz
firejail-72b93c5761b5e42c5742e192f46bac1696c36f4c.tar.zst
firejail-72b93c5761b5e42c5742e192f46bac1696c36f4c.zip
major cleanup
Diffstat (limited to 'src/firejail/seccomp.c')
-rw-r--r--src/firejail/seccomp.c873
1 files changed, 143 insertions, 730 deletions
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c
index 69be04a03..74d29fc9d 100644
--- a/src/firejail/seccomp.c
+++ b/src/firejail/seccomp.c
@@ -22,760 +22,203 @@
22#include "firejail.h" 22#include "firejail.h"
23#include "../include/seccomp.h" 23#include "../include/seccomp.h"
24 24
25#define SECSIZE 128 // initial filter size 25int seccomp_load(const char *fname) {
26static struct sock_filter *sfilter = NULL; 26 assert(fname);
27static int sfilter_alloc_size = 0;
28static int sfilter_index = 0;
29
30// debug filter
31void filter_debug(void) {
32 // start filter
33 struct sock_filter filter[] = {
34 VALIDATE_ARCHITECTURE,
35 EXAMINE_SYSCALL
36 };
37 27
38 // print sizes 28 // check file
39 printf("SECCOMP Filter:\n"); 29 struct stat s;
40 if (sfilter == NULL) { 30 if (stat(fname, &s) == -1) {
41 printf("SECCOMP filter not allocated\n"); 31 fprintf(stderr, "Error: cannot read protocol filter file\n");
42 return; 32 exit(1);
43 }
44 if (sfilter_index < 4)
45 return;
46
47 // test the start of the filter
48 if (memcmp(sfilter, filter, sizeof(filter)) == 0) {
49 printf(" VALIDATE_ARCHITECTURE\n");
50 printf(" EXAMINE_SYSCAL\n");
51 } 33 }
52 34 int size = s.st_size;
53 // loop trough blacklists 35 unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter);
54 int i = 4; 36//printf("size %d, entries %d\n", s.st_size, entries);
55 while (i < sfilter_index) { 37
56 // minimal parsing! 38 // read filter
57 unsigned char *ptr = (unsigned char *) &sfilter[i]; 39 struct sock_filter filter[entries];
58 int *nr = (int *) (ptr + 4); 40 memset(&filter[0], 0, sizeof(filter));
59 if (*ptr == 0x15 && *(ptr +14) == 0xff && *(ptr + 15) == 0x7f ) { 41 int src = open(fname, O_RDONLY);
60 printf(" WHITELIST %d %s\n", *nr, syscall_find_nr(*nr)); 42 int rd = 0;
61 i += 2; 43 while (rd < size) {
62 } 44 int rv = read(src, (unsigned char *) filter + rd, size - rd);
63 else if (*ptr == 0x15 && *(ptr +14) == 0 && *(ptr + 15) == 0) { 45 if (rv == -1) {
64 printf(" BLACKLIST %d %s\n", *nr, syscall_find_nr(*nr)); 46 fprintf(stderr, "Error: cannot read %s file\n", fname);
65 i += 2; 47 exit(1);
66 }
67 else if (*ptr == 0x15 && *(ptr +14) == 0x5 && *(ptr + 15) == 0) {
68 int err = *(ptr + 13) << 8 | *(ptr + 12);
69 printf(" ERRNO %d %s %d %s\n", *nr, syscall_find_nr(*nr), err, errno_find_nr(err));
70 i += 2;
71 }
72 else if (*ptr == 0x06 && *(ptr +6) == 0 && *(ptr + 7) == 0 ) {
73 printf(" KILL_PROCESS\n");
74 i++;
75 }
76 else if (*ptr == 0x06 && *(ptr +6) == 0xff && *(ptr + 7) == 0x7f ) {
77 printf(" RETURN_ALLOW\n");
78 i++;
79 }
80 else {
81 printf(" UNKNOWN ENTRY!!!\n");
82 i++;
83 } 48 }
49 rd += rv;
84 } 50 }
85} 51 close(src);
86
87// initialize filter
88static void filter_init(void) {
89 if (sfilter) {
90 assert(0);
91 return;
92 }
93
94// if (arg_debug)
95// printf("Initialize seccomp filter\n");
96 // allocate a filter of SECSIZE
97 sfilter = malloc(sizeof(struct sock_filter) * SECSIZE);
98 if (!sfilter)
99 errExit("malloc");
100 memset(sfilter, 0, sizeof(struct sock_filter) * SECSIZE);
101 sfilter_alloc_size = SECSIZE;
102
103 // copy the start entries
104#if defined(__x86_64__)
105#define X32_SYSCALL_BIT 0x40000000
106 struct sock_filter filter[] = {
107 VALIDATE_ARCHITECTURE,
108 EXAMINE_SYSCALL,
109 // handle X32 ABI
110 BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0),
111 BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0),
112 RETURN_ERRNO(EPERM)
113 };
114#else
115 struct sock_filter filter[] = {
116 VALIDATE_ARCHITECTURE,
117 EXAMINE_SYSCALL
118 };
119#endif
120 sfilter_index = sizeof(filter) / sizeof(struct sock_filter);
121 memcpy(sfilter, filter, sizeof(filter));
122}
123
124static void filter_realloc(void) {
125 assert(sfilter);
126 assert(sfilter_alloc_size);
127 assert(sfilter_index);
128 if (arg_debug)
129 printf("Allocating more seccomp filter entries\n");
130
131 // allocate the new memory
132 struct sock_filter *old = sfilter;
133 sfilter = malloc(sizeof(struct sock_filter) * (sfilter_alloc_size + SECSIZE));
134 if (!sfilter)
135 errExit("malloc");
136 memset(sfilter, 0, sizeof(struct sock_filter) * (sfilter_alloc_size + SECSIZE));
137
138 // copy old filter
139 memcpy(sfilter, old, sizeof(struct sock_filter) * sfilter_alloc_size);
140 sfilter_alloc_size += SECSIZE;
141}
142
143static void filter_add_whitelist(int syscall, int arg) {
144 (void) arg;
145 assert(sfilter);
146 assert(sfilter_alloc_size);
147 assert(sfilter_index);
148// if (arg_debug)
149// printf("Whitelisting syscall %d %s\n", syscall, syscall_find_nr(syscall));
150
151 if ((sfilter_index + 2) > sfilter_alloc_size)
152 filter_realloc();
153
154 struct sock_filter filter[] = {
155 WHITELIST(syscall)
156 };
157#if 0
158{
159 int i;
160 unsigned char *ptr = (unsigned char *) &filter[0];
161 for (i = 0; i < sizeof(filter); i++, ptr++)
162 printf("%x, ", (*ptr) & 0xff);
163 printf("\n");
164}
165#endif
166 memcpy(&sfilter[sfilter_index], filter, sizeof(filter));
167 sfilter_index += sizeof(filter) / sizeof(struct sock_filter);
168}
169 52
170static void filter_add_blacklist(int syscall, int arg) { 53 // install filter
171 (void) arg; 54 struct sock_fprog prog = {
172 assert(sfilter); 55 .len = entries,
173 assert(sfilter_alloc_size); 56 .filter = filter,
174 assert(sfilter_index);
175// if (arg_debug)
176// printf("Blacklisting syscall %d %s\n", syscall, syscall_find_nr(syscall));
177
178 if ((sfilter_index + 2) > sfilter_alloc_size)
179 filter_realloc();
180
181 struct sock_filter filter[] = {
182 BLACKLIST(syscall)
183 };
184#if 0
185{
186 int i;
187 unsigned char *ptr = (unsigned char *) &filter[0];
188 for (i = 0; i < sizeof(filter); i++, ptr++)
189 printf("%x, ", (*ptr) & 0xff);
190 printf("\n");
191}
192#endif
193 memcpy(&sfilter[sfilter_index], filter, sizeof(filter));
194 sfilter_index += sizeof(filter) / sizeof(struct sock_filter);
195}
196
197static void filter_add_errno(int syscall, int arg) {
198 assert(sfilter);
199 assert(sfilter_alloc_size);
200 assert(sfilter_index);
201// if (arg_debug)
202// printf("Errno syscall %d %d %s\n", syscall, arg, syscall_find_nr(syscall));
203
204 if ((sfilter_index + 2) > sfilter_alloc_size)
205 filter_realloc();
206
207 struct sock_filter filter[] = {
208 BLACKLIST_ERRNO(syscall, arg)
209 };
210#if 0
211{
212 int i;
213 unsigned char *ptr = (unsigned char *) &filter[0];
214 for (i = 0; i < sizeof(filter); i++, ptr++)
215 printf("%x, ", (*ptr) & 0xff);
216 printf("\n");
217}
218#endif
219 memcpy(&sfilter[sfilter_index], filter, sizeof(filter));
220 sfilter_index += sizeof(filter) / sizeof(struct sock_filter);
221}
222
223static void filter_end_blacklist(void) {
224 assert(sfilter);
225 assert(sfilter_alloc_size);
226 assert(sfilter_index);
227// if (arg_debug)
228// printf("Ending syscall filter\n");
229
230 if ((sfilter_index + 2) > sfilter_alloc_size)
231 filter_realloc();
232
233 struct sock_filter filter[] = {
234 RETURN_ALLOW
235 };
236#if 0
237{
238 int i;
239 unsigned char *ptr = (unsigned char *) &filter[0];
240 for (i = 0; i < sizeof(filter); i++, ptr++)
241 printf("%x, ", (*ptr) & 0xff);
242 printf("\n");
243}
244#endif
245 memcpy(&sfilter[sfilter_index], filter, sizeof(filter));
246 sfilter_index += sizeof(filter) / sizeof(struct sock_filter);
247}
248
249static void filter_end_whitelist(void) {
250 assert(sfilter);
251 assert(sfilter_alloc_size);
252 assert(sfilter_index);
253 if (arg_debug)
254 printf("Ending syscall filter\n");
255
256 if ((sfilter_index + 2) > sfilter_alloc_size)
257 filter_realloc();
258
259 struct sock_filter filter[] = {
260 KILL_PROCESS
261 }; 57 };
262#if 0
263{
264 int i;
265 unsigned char *ptr = (unsigned char *) &filter[0];
266 for (i = 0; i < sizeof(filter); i++, ptr++)
267 printf("%x, ", (*ptr) & 0xff);
268 printf("\n");
269}
270#endif
271 memcpy(&sfilter[sfilter_index], filter, sizeof(filter));
272 sfilter_index += sizeof(filter) / sizeof(struct sock_filter);
273}
274
275
276// save seccomp filter in /run/firejail/mnt/seccomp
277static void write_seccomp_file(void) {
278 assert(sfilter);
279
280 int fd = open(RUN_SECCOMP_CFG, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
281 if (fd == -1)
282 errExit("open");
283 58
284 if (arg_debug) 59 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
285 printf("Save seccomp filter, size %u bytes\n", (unsigned) (sfilter_index * sizeof(struct sock_filter))); 60 fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
286 errno = 0; 61 return 1;
287 ssize_t sz = write(fd, sfilter, sfilter_index * sizeof(struct sock_filter));
288 if (sz != (ssize_t)(sfilter_index * sizeof(struct sock_filter))) {
289 fprintf(stderr, "Error: cannot save seccomp filter\n");
290 exit(1);
291 } 62 }
292 SET_PERMS_FD(fd, 0, 0, S_IRUSR | S_IWUSR); 63
293 close(fd); 64 return 0;
294} 65}
295 66
296// read seccomp filter from /run/firejail/mnt/seccomp
297static void read_seccomp_file(const char *fname) {
298 assert(sfilter == NULL && sfilter_index == 0);
299 67
300 // check file
301 struct stat s;
302 if (stat(fname, &s) == -1) {
303 fprintf(stderr, "Warning: seccomp file not found\n");
304 return;
305 }
306 ssize_t sz = s.st_size;
307 if (sz == 0 || (sz % sizeof(struct sock_filter)) != 0) {
308 fprintf(stderr, "Error: invalid seccomp file\n");
309 exit(1);
310 }
311 sfilter = malloc(sz);
312 if (!sfilter)
313 errExit("malloc");
314
315 // read file
316 /* coverity[toctou] */
317 int fd = open(fname,O_RDONLY);
318 if (fd == -1)
319 errExit("open");
320 errno = 0;
321 ssize_t size = read(fd, sfilter, sz);
322 if (size != sz) {
323 fprintf(stderr, "Error: invalid seccomp file\n");
324 exit(1);
325 }
326 sfilter_index = sz / sizeof(struct sock_filter);
327 68
328 if (arg_debug)
329 printf("Read seccomp filter, size %u bytes\n", (unsigned) (sfilter_index * sizeof(struct sock_filter)));
330
331 close(fd);
332
333 if (arg_debug)
334 filter_debug();
335}
336 69
337// i386 filter installed on amd64 architectures 70// i386 filter installed on amd64 architectures
338void seccomp_filter_32(void) { 71void seccomp_filter_32(void) {
339 // hardcoded syscall values 72 if (arg_debug)
340 struct sock_filter filter[] = { 73 printf("Build secondary 32-bit filter\n");
341 VALIDATE_ARCHITECTURE_32,
342 EXAMINE_SYSCALL,
343 BLACKLIST(21), // mount
344 BLACKLIST(52), // umount2
345// todo: implement --allow-debuggers
346 BLACKLIST(26), // ptrace
347 BLACKLIST(283), // kexec_load
348 BLACKLIST(341), // name_to_handle_at
349 BLACKLIST(342), // open_by_handle_at
350 BLACKLIST(127), // create_module
351 BLACKLIST(128), // init_module
352 BLACKLIST(350), // finit_module
353 BLACKLIST(129), // delete_module
354 BLACKLIST(110), // iopl
355 BLACKLIST(101), // ioperm
356 BLACKLIST(289), // ioprio_set
357 BLACKLIST(87), // swapon
358 BLACKLIST(115), // swapoff
359 BLACKLIST(103), // syslog
360 BLACKLIST(347), // process_vm_readv
361 BLACKLIST(348), // process_vm_writev
362 BLACKLIST(135), // sysfs
363 BLACKLIST(149), // _sysctl
364 BLACKLIST(124), // adjtimex
365 BLACKLIST(343), // clock_adjtime
366 BLACKLIST(253), // lookup_dcookie
367 BLACKLIST(336), // perf_event_open
368 BLACKLIST(338), // fanotify_init
369 BLACKLIST(349), // kcmp
370 BLACKLIST(286), // add_key
371 BLACKLIST(287), // request_key
372 BLACKLIST(288), // keyctl
373 BLACKLIST(86), // uselib
374 BLACKLIST(51), // acct
375 BLACKLIST(123), // modify_ldt
376 BLACKLIST(217), // pivot_root
377 BLACKLIST(245), // io_setup
378 BLACKLIST(246), // io_destroy
379 BLACKLIST(247), // io_getevents
380 BLACKLIST(248), // io_submit
381 BLACKLIST(249), // io_cancel
382 BLACKLIST(257), // remap_file_pages
383 BLACKLIST(274), // mbind
384 BLACKLIST(275), // get_mempolicy
385 BLACKLIST(276), // set_mempolicy
386 BLACKLIST(294), // migrate_pages
387 BLACKLIST(317), // move_pages
388 BLACKLIST(316), // vmsplice
389 BLACKLIST(61), // chroot
390 BLACKLIST(88), // reboot
391 BLACKLIST(169), // nfsservctl
392 BLACKLIST(130), // get_kernel_syms
393
394 RETURN_ALLOW
395 };
396 74
397 struct sock_fprog prog = { 75 // build the seccomp filter as a regular user
398 .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), 76 int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4,
399 .filter = filter, 77 PATH_FSECCOMP, "secondary", "32", RUN_SECCOMP_I386);
400 }; 78 if (rv)
79 exit(rv);
401 80
402 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 81 if (seccomp_load(RUN_SECCOMP_I386) == 0) {
403 ; 82 if (arg_debug)
404 } 83 printf("Dual i386/amd64 seccomp filter configured\n");
405 else if (arg_debug) {
406 printf("Dual i386/amd64 seccomp filter configured\n");
407 } 84 }
408} 85}
409 86
410// amd64 filter installed on i386 architectures 87// amd64 filter installed on i386 architectures
411void seccomp_filter_64(void) { 88void seccomp_filter_64(void) {
412 // hardcoded syscall values 89 if (arg_debug)
413 struct sock_filter filter[] = { 90 printf("Build secondary 64-bit filter\n");
414 VALIDATE_ARCHITECTURE_64,
415 EXAMINE_SYSCALL,
416 BLACKLIST(165), // mount
417 BLACKLIST(166), // umount2
418// todo: implement --allow-debuggers
419 BLACKLIST(101), // ptrace
420 BLACKLIST(246), // kexec_load
421 BLACKLIST(304), // open_by_handle_at
422 BLACKLIST(303), // name_to_handle_at
423 BLACKLIST(174), // create_module
424 BLACKLIST(175), // init_module
425 BLACKLIST(313), // finit_module
426 BLACKLIST(176), // delete_module
427 BLACKLIST(172), // iopl
428 BLACKLIST(173), // ioperm
429 BLACKLIST(251), // ioprio_set
430 BLACKLIST(167), // swapon
431 BLACKLIST(168), // swapoff
432 BLACKLIST(103), // syslog
433 BLACKLIST(310), // process_vm_readv
434 BLACKLIST(311), // process_vm_writev
435 BLACKLIST(139), // sysfs
436 BLACKLIST(156), // _sysctl
437 BLACKLIST(159), // adjtimex
438 BLACKLIST(305), // clock_adjtime
439 BLACKLIST(212), // lookup_dcookie
440 BLACKLIST(298), // perf_event_open
441 BLACKLIST(300), // fanotify_init
442 BLACKLIST(312), // kcmp
443 BLACKLIST(248), // add_key
444 BLACKLIST(249), // request_key
445 BLACKLIST(250), // keyctl
446 BLACKLIST(134), // uselib
447 BLACKLIST(163), // acct
448 BLACKLIST(154), // modify_ldt
449 BLACKLIST(155), // pivot_root
450 BLACKLIST(206), // io_setup
451 BLACKLIST(207), // io_destroy
452 BLACKLIST(208), // io_getevents
453 BLACKLIST(209), // io_submit
454 BLACKLIST(210), // io_cancel
455 BLACKLIST(216), // remap_file_pages
456 BLACKLIST(237), // mbind
457 BLACKLIST(239), // get_mempolicy
458 BLACKLIST(238), // set_mempolicy
459 BLACKLIST(256), // migrate_pages
460 BLACKLIST(279), // move_pages
461 BLACKLIST(278), // vmsplice
462 BLACKLIST(161), // chroot
463 BLACKLIST(184), // tuxcall
464 BLACKLIST(169), // reboot
465 BLACKLIST(180), // nfsservctl
466 BLACKLIST(177), // get_kernel_syms
467
468 RETURN_ALLOW
469 };
470 91
471 struct sock_fprog prog = { 92 // build the seccomp filter as a regular user
472 .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), 93 int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4,
473 .filter = filter, 94 PATH_FSECCOMP, "secondary", "64", RUN_SECCOMP_AMD64);
474 }; 95 if (rv)
96 exit(rv);
475 97
476 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 98 if (seccomp_load(RUN_SECCOMP_AMD64) == 0) {
477 ; 99 if (arg_debug)
478 } 100 printf("Dual i386/amd64 seccomp filter configured\n");
479 else if (arg_debug) {
480 printf("Dual i386/amd64 seccomp filter configured\n");
481 } 101 }
482} 102}
483 103
484 104
485// drop filter for seccomp option 105// drop filter for seccomp option
486int seccomp_filter_drop(int enforce_seccomp) { 106int seccomp_filter_drop(int enforce_seccomp) {
487 filter_init();
488
489 // default seccomp 107 // default seccomp
490 if (cfg.seccomp_list_drop == NULL) { 108 if (cfg.seccomp_list_drop == NULL && cfg.seccomp_list == NULL) {
491#if defined(__x86_64__) 109#if defined(__x86_64__)
492 seccomp_filter_32(); 110 seccomp_filter_32();
493#endif 111#endif
494#if defined(__i386__) 112#if defined(__i386__)
495 seccomp_filter_64(); 113 seccomp_filter_64();
496#endif 114#endif
497 115 if (arg_debug)
498#ifdef SYS_mount 116 printf("Build default seccomp filter\n");
499 filter_add_blacklist(SYS_mount, 0); 117 // build the seccomp filter as a regular user
500#endif 118 int rv;
501#ifdef SYS_umount2 119 if (arg_allow_debuggers)
502 filter_add_blacklist(SYS_umount2, 0); 120 rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4,
503#endif 121 PATH_FSECCOMP, "default", RUN_SECCOMP_CFG, "allow-debuggers");
504 122 else
505 if (!arg_allow_debuggers) { 123 rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3,
506#ifdef SYS_ptrace 124 PATH_FSECCOMP, "default", RUN_SECCOMP_CFG);
507 filter_add_blacklist(SYS_ptrace, 0); 125 if (rv)
508#endif 126 exit(rv);
509 }
510
511#ifdef SYS_kexec_load
512 filter_add_blacklist(SYS_kexec_load, 0);
513#endif
514#ifdef SYS_kexec_file_load
515 filter_add_blacklist(SYS_kexec_file_load, 0);
516#endif
517#ifdef SYS_open_by_handle_at
518 filter_add_blacklist(SYS_open_by_handle_at, 0);
519#endif
520#ifdef SYS_name_to_handle_at
521 filter_add_blacklist(SYS_name_to_handle_at, 0);
522#endif
523#ifdef SYS_init_module
524 filter_add_blacklist(SYS_init_module, 0);
525#endif
526#ifdef SYS_finit_module // introduced in 2013
527 filter_add_blacklist(SYS_finit_module, 0);
528#endif
529#ifdef SYS_create_module
530 filter_add_blacklist(SYS_create_module, 0);
531#endif
532#ifdef SYS_delete_module
533 filter_add_blacklist(SYS_delete_module, 0);
534#endif
535#ifdef SYS_iopl
536 filter_add_blacklist(SYS_iopl, 0);
537#endif
538#ifdef SYS_ioperm
539 filter_add_blacklist(SYS_ioperm, 0);
540#endif
541#ifdef SYS_ioprio_set
542 filter_add_blacklist(SYS_ioprio_set, 0);
543#endif
544#ifdef SYS_ni_syscall // new io permissions call on arm devices
545 filter_add_blacklist(SYS_ni_syscall, 0);
546#endif
547#ifdef SYS_swapon
548 filter_add_blacklist(SYS_swapon, 0);
549#endif
550#ifdef SYS_swapoff
551 filter_add_blacklist(SYS_swapoff, 0);
552#endif
553#ifdef SYS_syslog
554 filter_add_blacklist(SYS_syslog, 0);
555#endif
556 if (!arg_allow_debuggers) {
557#ifdef SYS_process_vm_readv
558 filter_add_blacklist(SYS_process_vm_readv, 0);
559#endif
560 }
561
562#ifdef SYS_process_vm_writev
563 filter_add_blacklist(SYS_process_vm_writev, 0);
564#endif
565
566// mknod removed in 0.9.29 - it brakes Zotero extension
567//#ifdef SYS_mknod
568// filter_add_blacklist(SYS_mknod, 0);
569//#endif
570
571 // new syscalls in 0.9,23
572#ifdef SYS_sysfs
573 filter_add_blacklist(SYS_sysfs, 0);
574#endif
575#ifdef SYS__sysctl
576 filter_add_blacklist(SYS__sysctl, 0);
577#endif
578#ifdef SYS_adjtimex
579 filter_add_blacklist(SYS_adjtimex, 0);
580#endif
581#ifdef SYS_clock_adjtime
582 filter_add_blacklist(SYS_clock_adjtime, 0);
583#endif
584#ifdef SYS_lookup_dcookie
585 filter_add_blacklist(SYS_lookup_dcookie, 0);
586#endif
587#ifdef SYS_perf_event_open
588 filter_add_blacklist(SYS_perf_event_open, 0);
589#endif
590#ifdef SYS_fanotify_init
591 filter_add_blacklist(SYS_fanotify_init, 0);
592#endif
593#ifdef SYS_kcmp
594 filter_add_blacklist(SYS_kcmp, 0);
595#endif
596
597// 0.9.32
598#ifdef SYS_add_key
599 filter_add_blacklist(SYS_add_key, 0);
600#endif
601#ifdef SYS_request_key
602 filter_add_blacklist(SYS_request_key, 0);
603#endif
604#ifdef SYS_keyctl
605 filter_add_blacklist(SYS_keyctl, 0);
606#endif
607#ifdef SYS_uselib
608 filter_add_blacklist(SYS_uselib, 0);
609#endif
610#ifdef SYS_acct
611 filter_add_blacklist(SYS_acct, 0);
612#endif
613#ifdef SYS_modify_ldt
614 filter_add_blacklist(SYS_modify_ldt, 0);
615#endif
616 //#ifdef SYS_unshare
617 // filter_add_blacklist(SYS_unshare, 0);
618 //#endif
619#ifdef SYS_pivot_root
620 filter_add_blacklist(SYS_pivot_root, 0);
621#endif
622 //#ifdef SYS_quotactl
623 // filter_add_blacklist(SYS_quotactl, 0);
624 //#endif
625#ifdef SYS_io_setup
626 filter_add_blacklist(SYS_io_setup, 0);
627#endif
628#ifdef SYS_io_destroy
629 filter_add_blacklist(SYS_io_destroy, 0);
630#endif
631#ifdef SYS_io_getevents
632 filter_add_blacklist(SYS_io_getevents, 0);
633#endif
634#ifdef SYS_io_submit
635 filter_add_blacklist(SYS_io_submit, 0);
636#endif
637#ifdef SYS_io_cancel
638 filter_add_blacklist(SYS_io_cancel, 0);
639#endif
640#ifdef SYS_remap_file_pages
641 filter_add_blacklist(SYS_remap_file_pages, 0);
642#endif
643#ifdef SYS_mbind
644 filter_add_blacklist(SYS_mbind, 0);
645#endif
646#ifdef SYS_get_mempolicy
647 filter_add_blacklist(SYS_get_mempolicy, 0);
648#endif
649#ifdef SYS_set_mempolicy
650 filter_add_blacklist(SYS_set_mempolicy, 0);
651#endif
652#ifdef SYS_migrate_pages
653 filter_add_blacklist(SYS_migrate_pages, 0);
654#endif
655#ifdef SYS_move_pages
656 filter_add_blacklist(SYS_move_pages, 0);
657#endif
658#ifdef SYS_vmsplice
659 filter_add_blacklist(SYS_vmsplice, 0);
660#endif
661#ifdef SYS_chroot
662 filter_add_blacklist(SYS_chroot, 0);
663#endif
664 //#ifdef SYS_set_robust_list
665 // filter_add_blacklist(SYS_set_robust_list, 0);
666 //#endif
667 //#ifdef SYS_get_robust_list
668 // filter_add_blacklist(SYS_get_robust_list, 0);
669 //#endif
670
671 // CHECK_SECCOMP(seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(clone), 1,
672 // SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER)));
673
674// 0.9.39
675#ifdef SYS_tuxcall
676 filter_add_blacklist(SYS_tuxcall, 0);
677#endif
678#ifdef SYS_reboot
679 filter_add_blacklist(SYS_reboot, 0);
680#endif
681#ifdef SYS_nfsservctl
682 filter_add_blacklist(SYS_nfsservctl, 0);
683#endif
684#ifdef SYS_get_kernel_syms
685 filter_add_blacklist(SYS_get_kernel_syms, 0);
686#endif
687
688 } 127 }
689 128
690 // default seccomp filter with additional drop list 129 // default seccomp filter with additional drop list
691 if (cfg.seccomp_list && cfg.seccomp_list_drop == NULL) { 130 else if (cfg.seccomp_list && cfg.seccomp_list_drop == NULL) {
692 if (syscall_check_list(cfg.seccomp_list, filter_add_blacklist, 0)) { 131#if defined(__x86_64__)
693 fprintf(stderr, "Error: cannot load seccomp filter\n"); 132 seccomp_filter_32();
133#endif
134#if defined(__i386__)
135 seccomp_filter_64();
136#endif
137 if (arg_debug)
138 printf("Build default+drop seccomp filter\n");
139 if (strlen(cfg.seccomp_list) == 0) {
140 fprintf(stderr, "Error: empty syscall lists are not allowed\n");
694 exit(1); 141 exit(1);
695 } 142 }
143
144 // build the seccomp filter as a regular user
145 int rv;
146 if (arg_allow_debuggers)
147 rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 6,
148 PATH_FSECCOMP, "default", "drop", RUN_SECCOMP_CFG, cfg.seccomp_list, "allow-debuggers");
149 else
150 rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5,
151 PATH_FSECCOMP, "default", "drop", RUN_SECCOMP_CFG, cfg.seccomp_list);
152 if (rv)
153 exit(rv);
696 } 154 }
697 // drop list 155
156 // drop list without defaults - secondary filters are not installed
698 else if (cfg.seccomp_list == NULL && cfg.seccomp_list_drop) { 157 else if (cfg.seccomp_list == NULL && cfg.seccomp_list_drop) {
699 if (syscall_check_list(cfg.seccomp_list_drop, filter_add_blacklist, 0)) { 158 if (arg_debug)
700 fprintf(stderr, "Error: cannot load seccomp filter\n"); 159 printf("Build drop seccomp filter\n");
160 if (strlen(cfg.seccomp_list_drop) == 0) {
161 fprintf(stderr, "Error: empty syscall lists are not allowed\n");
701 exit(1); 162 exit(1);
702 } 163 }
703 }
704
705
706 filter_end_blacklist();
707 if (arg_debug)
708 filter_debug();
709
710 // save seccomp filter in /run/firejail/mnt/seccomp
711 // in order to use it in --join operations
712 write_seccomp_file();
713
714
715 struct sock_fprog prog = {
716 .len = sfilter_index,
717 .filter = sfilter,
718 };
719 164
720 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 165 // build the seccomp filter as a regular user
721 if (enforce_seccomp) { 166 int rv;
722 fprintf(stderr, "Error: a seccomp-enabled Linux kernel is required, exiting...\n"); 167 if (arg_allow_debuggers)
723 exit(1); 168 rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5,
724 } 169 PATH_FSECCOMP, "drop", RUN_SECCOMP_CFG, cfg.seccomp_list_drop, "allow-debuggers");
725 else 170 else
726 fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); 171 rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4,
172 PATH_FSECCOMP, "drop", RUN_SECCOMP_CFG, cfg.seccomp_list_drop);
727 173
728 return 1; 174 if (rv)
175 exit(rv);
176 }
177 else {
178 assert(0);
729 } 179 }
730 180
731 return 0; 181 // load the filter
182 if (seccomp_load(RUN_SECCOMP_CFG) == 0) {
183 if (arg_debug)
184 printf("seccomp filter configured\n");
185 }
186 else if (enforce_seccomp) {
187 fprintf(stderr, "Error: a seccomp-enabled Linux kernel is required, exiting...\n");
188 exit(1);
189 }
190
191 if (arg_debug)
192 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3,
193 PATH_FSECCOMP, "print", RUN_SECCOMP_CFG);
194
195 return seccomp_load(RUN_SECCOMP_CFG);
732} 196}
733 197
734// keep filter for seccomp option 198// keep filter for seccomp option
735int seccomp_filter_keep(void) { 199int seccomp_filter_keep(void) {
736 filter_init(); 200 if (arg_debug)
737 201 printf("Build drop seccomp filter\n");
738 // these 4 syscalls are used by firejail after the seccomp filter is initialized 202 if (strlen(cfg.seccomp_list_keep) == 0) {
739 filter_add_whitelist(SYS_setuid, 0); 203 fprintf(stderr, "Error: empty syscall lists are not allowed\n");
740 filter_add_whitelist(SYS_setgid, 0); 204 exit(1);
741 filter_add_whitelist(SYS_setgroups, 0);
742 filter_add_whitelist(SYS_dup, 0);
743
744 // apply keep list
745 if (cfg.seccomp_list_keep) {
746 if (syscall_check_list(cfg.seccomp_list_keep, filter_add_whitelist, 0)) {
747 fprintf(stderr, "Error: cannot load seccomp filter\n");
748 exit(1);
749 }
750 } 205 }
751 206
752 filter_end_whitelist(); 207 // build the seccomp filter as a regular user
208 int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4,
209 PATH_FSECCOMP, "keep", RUN_SECCOMP_CFG, cfg.seccomp_list_keep);
210 if (rv)
211 exit(rv);
753 if (arg_debug) 212 if (arg_debug)
754 filter_debug(); 213 printf("seccomp filter configured\n");
755
756 // save seccomp filter in /run/firejail/mnt/seccomp
757 // in order to use it in --join operations
758 write_seccomp_file();
759
760 214
761 struct sock_fprog prog = { 215
762 .len = sfilter_index, 216 return seccomp_load(RUN_SECCOMP_CFG);
763 .filter = sfilter,
764 };
765
766 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
767 fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
768 return 1;
769 }
770 else if (arg_debug) {
771 printf("seccomp enabled\n");
772 }
773
774 return 0;
775} 217}
776 218
777// errno filter for seccomp option 219// errno filter for seccomp option
778int seccomp_filter_errno(void) { 220int seccomp_filter_errno(void) {
221#if 0 //todo: disabled temporarely, bring it back
779 int i; 222 int i;
780 int higest_errno = errno_highest_nr(); 223 int higest_errno = errno_highest_nr();
781 filter_init(); 224 filter_init();
@@ -798,42 +241,11 @@ int seccomp_filter_errno(void) {
798 // save seccomp filter in /run/firejail/mnt/seccomp 241 // save seccomp filter in /run/firejail/mnt/seccomp
799 // in order to use it in --join operations 242 // in order to use it in --join operations
800 write_seccomp_file(); 243 write_seccomp_file();
801 244 return seccomp_load(RUN_SECCOMP_CFG);
802 struct sock_fprog prog = { 245#else
803 .len = sfilter_index, 246printf("*** --seccomp.<errno> is temporarily disabled, it will be brought back soon ***\n");
804 .filter = sfilter,
805 };
806
807 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
808 fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
809 return 1;
810 }
811 else if (arg_debug) {
812 printf("seccomp enabled\n");
813 }
814
815 return 0; 247 return 0;
816} 248#endif
817
818
819
820void seccomp_set(void) {
821 // read seccomp filter from /runp/firejail/mnt/seccomp
822 read_seccomp_file(RUN_SECCOMP_CFG);
823
824 // apply filter
825 struct sock_fprog prog = {
826 .len = sfilter_index,
827 .filter = sfilter,
828 };
829
830 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
831 fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
832 return;
833 }
834 else if (arg_debug) {
835 printf("seccomp enabled\n");
836 }
837} 249}
838 250
839void seccomp_print_filter_name(const char *name) { 251void seccomp_print_filter_name(const char *name) {
@@ -890,10 +302,11 @@ void seccomp_print_filter(pid_t pid) {
890 exit(1); 302 exit(1);
891 } 303 }
892 304
893 // read and print the filter 305 // read and print the filter - run this as root, the user doesn't have access
894 read_seccomp_file(fname); 306 int rv = sbox_run(SBOX_ROOT | SBOX_SECCOMP, 3,
895 drop_privs(1); 307 PATH_FSECCOMP, "print", fname);
896 filter_debug(); 308 if (rv)
309 exit(rv);
897 free(fname); 310 free(fname);
898 311
899 exit(0); 312 exit(0);