diff options
Diffstat (limited to 'src/firejail/seccomp.c')
-rw-r--r-- | src/firejail/seccomp.c | 144 |
1 files changed, 110 insertions, 34 deletions
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index 47988dbf4..4f6b7b326 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c | |||
@@ -109,6 +109,10 @@ struct seccomp_data { | |||
109 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ | 109 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ |
110 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) | 110 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) |
111 | 111 | ||
112 | #define ERRNO(syscall_nr, nr) \ | ||
113 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ | ||
114 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO | nr) | ||
115 | |||
112 | #define RETURN_ALLOW \ | 116 | #define RETURN_ALLOW \ |
113 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) | 117 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) |
114 | 118 | ||
@@ -157,6 +161,11 @@ void filter_debug(void) { | |||
157 | printf(" BLACKLIST %d %s\n", *nr, syscall_find_nr(*nr)); | 161 | printf(" BLACKLIST %d %s\n", *nr, syscall_find_nr(*nr)); |
158 | i += 2; | 162 | i += 2; |
159 | } | 163 | } |
164 | else if (*ptr == 0x15 && *(ptr +14) == 0x5 && *(ptr + 15) == 0) { | ||
165 | int err = *(ptr + 13) << 8 | *(ptr + 12); | ||
166 | printf(" ERRNO %d %s %d %s\n", *nr, syscall_find_nr(*nr), err, errno_find_nr(err)); | ||
167 | i += 2; | ||
168 | } | ||
160 | else if (*ptr == 0x06 && *(ptr +6) == 0 && *(ptr + 7) == 0 ) { | 169 | else if (*ptr == 0x06 && *(ptr +6) == 0 && *(ptr + 7) == 0 ) { |
161 | printf(" KILL_PROCESS\n"); | 170 | printf(" KILL_PROCESS\n"); |
162 | i++; | 171 | i++; |
@@ -216,7 +225,7 @@ static void filter_realloc(void) { | |||
216 | sfilter_alloc_size += SECSIZE; | 225 | sfilter_alloc_size += SECSIZE; |
217 | } | 226 | } |
218 | 227 | ||
219 | static void filter_add_whitelist(int syscall) { | 228 | static void filter_add_whitelist(int syscall, int arg) { |
220 | assert(sfilter); | 229 | assert(sfilter); |
221 | assert(sfilter_alloc_size); | 230 | assert(sfilter_alloc_size); |
222 | assert(sfilter_index); | 231 | assert(sfilter_index); |
@@ -242,7 +251,7 @@ static void filter_add_whitelist(int syscall) { | |||
242 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); | 251 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); |
243 | } | 252 | } |
244 | 253 | ||
245 | static void filter_add_blacklist(int syscall) { | 254 | static void filter_add_blacklist(int syscall, int arg) { |
246 | assert(sfilter); | 255 | assert(sfilter); |
247 | assert(sfilter_alloc_size); | 256 | assert(sfilter_alloc_size); |
248 | assert(sfilter_index); | 257 | assert(sfilter_index); |
@@ -268,6 +277,32 @@ static void filter_add_blacklist(int syscall) { | |||
268 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); | 277 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); |
269 | } | 278 | } |
270 | 279 | ||
280 | static void filter_add_errno(int syscall, int arg) { | ||
281 | assert(sfilter); | ||
282 | assert(sfilter_alloc_size); | ||
283 | assert(sfilter_index); | ||
284 | // if (arg_debug) | ||
285 | // printf("Errno syscall %d %d %s\n", syscall, arg, syscall_find_nr(syscall)); | ||
286 | |||
287 | if ((sfilter_index + 2) > sfilter_alloc_size) | ||
288 | filter_realloc(); | ||
289 | |||
290 | struct sock_filter filter[] = { | ||
291 | ERRNO(syscall, arg) | ||
292 | }; | ||
293 | #if 0 | ||
294 | { | ||
295 | int i; | ||
296 | unsigned char *ptr = (unsigned char *) &filter[0]; | ||
297 | for (i = 0; i < sizeof(filter); i++, ptr++) | ||
298 | printf("%x, ", (*ptr) & 0xff); | ||
299 | printf("\n"); | ||
300 | } | ||
301 | #endif | ||
302 | memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); | ||
303 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); | ||
304 | } | ||
305 | |||
271 | static void filter_end_blacklist(void) { | 306 | static void filter_end_blacklist(void) { |
272 | assert(sfilter); | 307 | assert(sfilter); |
273 | assert(sfilter_alloc_size); | 308 | assert(sfilter_alloc_size); |
@@ -405,96 +440,96 @@ int seccomp_filter_drop(void) { | |||
405 | // default seccomp | 440 | // default seccomp |
406 | if (arg_seccomp_list_drop == NULL) { | 441 | if (arg_seccomp_list_drop == NULL) { |
407 | #ifdef SYS_mount | 442 | #ifdef SYS_mount |
408 | filter_add_blacklist(SYS_mount); | 443 | filter_add_blacklist(SYS_mount, 0); |
409 | #endif | 444 | #endif |
410 | #ifdef SYS_umount2 | 445 | #ifdef SYS_umount2 |
411 | filter_add_blacklist(SYS_umount2); | 446 | filter_add_blacklist(SYS_umount2, 0); |
412 | #endif | 447 | #endif |
413 | #ifdef SYS_ptrace | 448 | #ifdef SYS_ptrace |
414 | filter_add_blacklist(SYS_ptrace); | 449 | filter_add_blacklist(SYS_ptrace, 0); |
415 | #endif | 450 | #endif |
416 | #ifdef SYS_kexec_load | 451 | #ifdef SYS_kexec_load |
417 | filter_add_blacklist(SYS_kexec_load); | 452 | filter_add_blacklist(SYS_kexec_load, 0); |
418 | #endif | 453 | #endif |
419 | #ifdef SYS_open_by_handle_at | 454 | #ifdef SYS_open_by_handle_at |
420 | filter_add_blacklist(SYS_open_by_handle_at); | 455 | filter_add_blacklist(SYS_open_by_handle_at, 0); |
421 | #endif | 456 | #endif |
422 | #ifdef SYS_init_module | 457 | #ifdef SYS_init_module |
423 | filter_add_blacklist(SYS_init_module); | 458 | filter_add_blacklist(SYS_init_module, 0); |
424 | #endif | 459 | #endif |
425 | #ifdef SYS_finit_module // introduced in 2013 | 460 | #ifdef SYS_finit_module // introduced in 2013 |
426 | filter_add_blacklist(SYS_finit_module); | 461 | filter_add_blacklist(SYS_finit_module, 0); |
427 | #endif | 462 | #endif |
428 | #ifdef SYS_delete_module | 463 | #ifdef SYS_delete_module |
429 | filter_add_blacklist(SYS_delete_module); | 464 | filter_add_blacklist(SYS_delete_module, 0); |
430 | #endif | 465 | #endif |
431 | #ifdef SYS_iopl | 466 | #ifdef SYS_iopl |
432 | filter_add_blacklist(SYS_iopl); | 467 | filter_add_blacklist(SYS_iopl, 0); |
433 | #endif | 468 | #endif |
434 | #ifdef SYS_ioperm | 469 | #ifdef SYS_ioperm |
435 | filter_add_blacklist(SYS_ioperm); | 470 | filter_add_blacklist(SYS_ioperm, 0); |
436 | #endif | 471 | #endif |
437 | #ifdef SYS_ni_syscall // new io permisions call on arm devices | 472 | #ifdef SYS_ni_syscall // new io permisions call on arm devices |
438 | filter_add_blacklist(SYS_ni_syscall); | 473 | filter_add_blacklist(SYS_ni_syscall, 0); |
439 | #endif | 474 | #endif |
440 | #ifdef SYS_swapon | 475 | #ifdef SYS_swapon |
441 | filter_add_blacklist(SYS_swapon); | 476 | filter_add_blacklist(SYS_swapon, 0); |
442 | #endif | 477 | #endif |
443 | #ifdef SYS_swapoff | 478 | #ifdef SYS_swapoff |
444 | filter_add_blacklist(SYS_swapoff); | 479 | filter_add_blacklist(SYS_swapoff, 0); |
445 | #endif | 480 | #endif |
446 | #ifdef SYS_syslog | 481 | #ifdef SYS_syslog |
447 | filter_add_blacklist(SYS_syslog); | 482 | filter_add_blacklist(SYS_syslog, 0); |
448 | #endif | 483 | #endif |
449 | #ifdef SYS_process_vm_readv | 484 | #ifdef SYS_process_vm_readv |
450 | filter_add_blacklist(SYS_process_vm_readv); | 485 | filter_add_blacklist(SYS_process_vm_readv, 0); |
451 | #endif | 486 | #endif |
452 | #ifdef SYS_process_vm_writev | 487 | #ifdef SYS_process_vm_writev |
453 | filter_add_blacklist(SYS_process_vm_writev); | 488 | filter_add_blacklist(SYS_process_vm_writev, 0); |
454 | #endif | 489 | #endif |
455 | 490 | ||
456 | // mknod removed in 0.9.29 | 491 | // mknod removed in 0.9.29 |
457 | //#ifdef SYS_mknod | 492 | //#ifdef SYS_mknod |
458 | // filter_add_blacklist(SYS_mknod); | 493 | // filter_add_blacklist(SYS_mknod, 0); |
459 | //#endif | 494 | //#endif |
460 | 495 | ||
461 | // new syscalls in 0.9,23 | 496 | // new syscalls in 0.9,23 |
462 | #ifdef SYS_sysfs | 497 | #ifdef SYS_sysfs |
463 | filter_add_blacklist(SYS_sysfs); | 498 | filter_add_blacklist(SYS_sysfs, 0); |
464 | #endif | 499 | #endif |
465 | #ifdef SYS__sysctl | 500 | #ifdef SYS__sysctl |
466 | filter_add_blacklist(SYS__sysctl); | 501 | filter_add_blacklist(SYS__sysctl, 0); |
467 | #endif | 502 | #endif |
468 | #ifdef SYS_adjtimex | 503 | #ifdef SYS_adjtimex |
469 | filter_add_blacklist(SYS_adjtimex); | 504 | filter_add_blacklist(SYS_adjtimex, 0); |
470 | #endif | 505 | #endif |
471 | #ifdef SYS_clock_adjtime | 506 | #ifdef SYS_clock_adjtime |
472 | filter_add_blacklist(SYS_clock_adjtime); | 507 | filter_add_blacklist(SYS_clock_adjtime, 0); |
473 | #endif | 508 | #endif |
474 | #ifdef SYS_lookup_dcookie | 509 | #ifdef SYS_lookup_dcookie |
475 | filter_add_blacklist(SYS_lookup_dcookie); | 510 | filter_add_blacklist(SYS_lookup_dcookie, 0); |
476 | #endif | 511 | #endif |
477 | #ifdef SYS_perf_event_open | 512 | #ifdef SYS_perf_event_open |
478 | filter_add_blacklist(SYS_perf_event_open); | 513 | filter_add_blacklist(SYS_perf_event_open, 0); |
479 | #endif | 514 | #endif |
480 | #ifdef SYS_fanotify_init | 515 | #ifdef SYS_fanotify_init |
481 | filter_add_blacklist(SYS_fanotify_init); | 516 | filter_add_blacklist(SYS_fanotify_init, 0); |
482 | #endif | 517 | #endif |
483 | #ifdef SYS_kcmp | 518 | #ifdef SYS_kcmp |
484 | filter_add_blacklist(SYS_kcmp); | 519 | filter_add_blacklist(SYS_kcmp, 0); |
485 | #endif | 520 | #endif |
486 | } | 521 | } |
487 | 522 | ||
488 | // default seccomp filter with additional drop list | 523 | // default seccomp filter with additional drop list |
489 | if (arg_seccomp_list && arg_seccomp_list_drop == NULL) { | 524 | if (arg_seccomp_list && arg_seccomp_list_drop == NULL) { |
490 | if (syscall_check_list(arg_seccomp_list, filter_add_blacklist)) { | 525 | if (syscall_check_list(arg_seccomp_list, filter_add_blacklist, 0)) { |
491 | fprintf(stderr, "Error: cannot load seccomp filter\n"); | 526 | fprintf(stderr, "Error: cannot load seccomp filter\n"); |
492 | exit(1); | 527 | exit(1); |
493 | } | 528 | } |
494 | } | 529 | } |
495 | // drop list | 530 | // drop list |
496 | else if (arg_seccomp_list == NULL && arg_seccomp_list_drop) { | 531 | else if (arg_seccomp_list == NULL && arg_seccomp_list_drop) { |
497 | if (syscall_check_list(arg_seccomp_list_drop, filter_add_blacklist)) { | 532 | if (syscall_check_list(arg_seccomp_list_drop, filter_add_blacklist, 0)) { |
498 | fprintf(stderr, "Error: cannot load seccomp filter\n"); | 533 | fprintf(stderr, "Error: cannot load seccomp filter\n"); |
499 | exit(1); | 534 | exit(1); |
500 | } | 535 | } |
@@ -531,14 +566,14 @@ int seccomp_filter_keep(void) { | |||
531 | filter_init(); | 566 | filter_init(); |
532 | 567 | ||
533 | // these 4 syscalls are used by firejail after the seccomp filter is initialized | 568 | // these 4 syscalls are used by firejail after the seccomp filter is initialized |
534 | filter_add_whitelist(SYS_setuid); | 569 | filter_add_whitelist(SYS_setuid, 0); |
535 | filter_add_whitelist(SYS_setgid); | 570 | filter_add_whitelist(SYS_setgid, 0); |
536 | filter_add_whitelist(SYS_setgroups); | 571 | filter_add_whitelist(SYS_setgroups, 0); |
537 | filter_add_whitelist(SYS_dup); | 572 | filter_add_whitelist(SYS_dup, 0); |
538 | 573 | ||
539 | // apply keep list | 574 | // apply keep list |
540 | if (arg_seccomp_list_keep) { | 575 | if (arg_seccomp_list_keep) { |
541 | if (syscall_check_list(arg_seccomp_list_keep, filter_add_whitelist)) { | 576 | if (syscall_check_list(arg_seccomp_list_keep, filter_add_whitelist, 0)) { |
542 | fprintf(stderr, "Error: cannot load seccomp filter\n"); | 577 | fprintf(stderr, "Error: cannot load seccomp filter\n"); |
543 | exit(1); | 578 | exit(1); |
544 | } | 579 | } |
@@ -569,6 +604,47 @@ int seccomp_filter_keep(void) { | |||
569 | return 0; | 604 | return 0; |
570 | } | 605 | } |
571 | 606 | ||
607 | // errno filter for seccomp option | ||
608 | int seccomp_filter_errno(void) { | ||
609 | int i; | ||
610 | int higest_errno = errno_highest_nr(); | ||
611 | filter_init(); | ||
612 | |||
613 | // apply errno list | ||
614 | |||
615 | for (i = 0; i < higest_errno; i++) { | ||
616 | if (arg_seccomp_list_errno[i]) { | ||
617 | if (syscall_check_list(arg_seccomp_list_errno[i], filter_add_errno, i)) { | ||
618 | fprintf(stderr, "Error: cannot load seccomp filter\n"); | ||
619 | exit(1); | ||
620 | } | ||
621 | } | ||
622 | } | ||
623 | |||
624 | filter_end_blacklist(); | ||
625 | if (arg_debug) | ||
626 | filter_debug(); | ||
627 | |||
628 | // save seccomp filter in /tmp/firejail/mnt/seccomp | ||
629 | // in order to use it in --join operations | ||
630 | write_seccomp_file(); | ||
631 | |||
632 | struct sock_fprog prog = { | ||
633 | .len = sfilter_index, | ||
634 | .filter = sfilter, | ||
635 | }; | ||
636 | |||
637 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | ||
638 | fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); | ||
639 | return 1; | ||
640 | } | ||
641 | else if (arg_debug) { | ||
642 | printf("seccomp enabled\n"); | ||
643 | } | ||
644 | |||
645 | return 0; | ||
646 | } | ||
647 | |||
572 | 648 | ||
573 | 649 | ||
574 | void seccomp_set(void) { | 650 | void seccomp_set(void) { |