static void filter_add_blacklist(int syscall) { assert(sfilter); assert(sfilter_alloc_size); assert(sfilter_index); // if (arg_debug) // printf("Blacklisting syscall %d %s\n", syscall, syscall_find_nr(syscall)); if ((sfilter_index + 2) > sfilter_alloc_size) filter_realloc(); struct sock_filter filter[] = { BLACKLIST(syscall) }; #if 0 { int i; unsigned char *ptr = (unsigned char *) &filter[0]; for (i = 0; i < sizeof(filter); i++, ptr++) printf("%x, ", (*ptr) & 0xff); printf("\n"); } #endif memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); sfilter_index += sizeof(filter) / sizeof(struct sock_filter); }
void filter_add_blacklist(int fd, int syscall, int arg) { (void) arg; struct sock_filter filter[] = { BLACKLIST(syscall) }; write_to_file(fd, filter, sizeof(filter)); }
static struct sock_filter filter[] = { VALIDATE_ARCHITECTURE, EXAMINE_SYSCALL, #if defined(__x86_64__) #define X32_SYSCALL_BIT 0x40000000 // handle X32 ABI BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), RETURN_ERRNO(EPERM), #endif // syscall list #ifdef SYS_mount BLACKLIST(SYS_mount), // mount/unmount filesystems #endif #ifdef SYS_umount2 BLACKLIST(SYS_umount2), #endif #ifdef SYS_ptrace BLACKLIST(SYS_ptrace), // trace processes #endif #ifdef SYS_kexec_file_load BLACKLIST(SYS_kexec_file_load), #endif #ifdef SYS_kexec_load BLACKLIST(SYS_kexec_load), // loading a different kernel #endif #ifdef SYS_name_to_handle_at BLACKLIST(SYS_name_to_handle_at),
// i386 filter installed on amd64 architectures void seccomp_filter_32(void) { // hardcoded syscall values struct sock_filter filter[] = { VALIDATE_ARCHITECTURE_32, EXAMINE_SYSCALL, BLACKLIST(21), // mount BLACKLIST(52), // umount2 BLACKLIST(26), // ptrace BLACKLIST(283), // kexec_load BLACKLIST(342), // open_by_handle_at BLACKLIST(128), // init_module BLACKLIST(350), // finit_module BLACKLIST(129), // delete_module BLACKLIST(110), // iopl BLACKLIST(101), // ioperm BLACKLIST(87), // swapon BLACKLIST(115), // swapoff BLACKLIST(103), // syslog BLACKLIST(347), // process_vm_readv BLACKLIST(348), // process_vm_writev BLACKLIST(135), // sysfs BLACKLIST(149), // _sysctl BLACKLIST(124), // adjtimex BLACKLIST(343), // clock_adjtime BLACKLIST(253), // lookup_dcookie BLACKLIST(336), // perf_event_open BLACKLIST(338), // fanotify_init BLACKLIST(349), // kcmp BLACKLIST(286), // add_key BLACKLIST(287), // request_key BLACKLIST(288), // keyctl BLACKLIST(86), // uselib BLACKLIST(51), // acct BLACKLIST(123), // modify_ldt BLACKLIST(217), // pivot_root BLACKLIST(245), // io_setup BLACKLIST(246), // io_destroy BLACKLIST(247), // io_getevents BLACKLIST(248), // io_submit BLACKLIST(249), // io_cancel BLACKLIST(257), // remap_file_pages BLACKLIST(274), // mbind BLACKLIST(275), // get_mempolicy BLACKLIST(276), // set_mempolicy BLACKLIST(294), // migrate_pages BLACKLIST(317), // move_pages BLACKLIST(316), // vmsplice BLACKLIST(61), // chroot BLACKLIST(88), // reboot BLACKLIST(169), // nfsservctl BLACKLIST(130), // get_kernel_syms RETURN_ALLOW }; struct sock_fprog prog = { .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), .filter = filter, }; if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { ; } else if (arg_debug) { printf("Dual i386/amd64 seccomp filter configured\n"); } } // amd64 filter installed on i386 architectures void seccomp_filter_64(void) { // hardcoded syscall values struct sock_filter filter[] = { VALIDATE_ARCHITECTURE_64, EXAMINE_SYSCALL, BLACKLIST(165), // mount BLACKLIST(166), // umount2 BLACKLIST(101), // ptrace BLACKLIST(246), // kexec_load BLACKLIST(304), // open_by_handle_at BLACKLIST(175), // init_module BLACKLIST(313), // finit_module BLACKLIST(176), // delete_module BLACKLIST(172), // iopl BLACKLIST(173), // ioperm BLACKLIST(167), // swapon BLACKLIST(168), // swapoff BLACKLIST(103), // syslog BLACKLIST(310), // process_vm_readv BLACKLIST(311), // process_vm_writev BLACKLIST(139), // sysfs BLACKLIST(156), // _sysctl BLACKLIST(159), // adjtimex BLACKLIST(305), // clock_adjtime BLACKLIST(212), // lookup_dcookie BLACKLIST(298), // perf_event_open BLACKLIST(300), // fanotify_init BLACKLIST(312), // kcmp BLACKLIST(248), // add_key BLACKLIST(249), // request_key BLACKLIST(250), // keyctl BLACKLIST(134), // uselib BLACKLIST(163), // acct BLACKLIST(154), // modify_ldt BLACKLIST(155), // pivot_root BLACKLIST(206), // io_setup BLACKLIST(207), // io_destroy BLACKLIST(208), // io_getevents BLACKLIST(209), // io_submit BLACKLIST(210), // io_cancel BLACKLIST(216), // remap_file_pages BLACKLIST(237), // mbind BLACKLIST(239), // get_mempolicy BLACKLIST(238), // set_mempolicy BLACKLIST(256), // migrate_pages BLACKLIST(279), // move_pages BLACKLIST(278), // vmsplice BLACKLIST(161), // chroot BLACKLIST(184), // tuxcall BLACKLIST(169), // reboot BLACKLIST(180), // nfsservctl BLACKLIST(177), // get_kernel_syms RETURN_ALLOW }; struct sock_fprog prog = { .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), .filter = filter, }; if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { ; } else if (arg_debug) { printf("Dual i386/amd64 seccomp filter configured\n"); } } // drop filter for seccomp option int seccomp_filter_drop(int enforce_seccomp) { filter_init(); // default seccomp if (cfg.seccomp_list_drop == NULL) { #if defined(__x86_64__) seccomp_filter_32(); #endif #if defined(__i386__) seccomp_filter_64(); #endif #ifdef SYS_mount filter_add_blacklist(SYS_mount, 0); #endif #ifdef SYS_umount2 filter_add_blacklist(SYS_umount2, 0); #endif #ifdef SYS_ptrace filter_add_blacklist(SYS_ptrace, 0); #endif #ifdef SYS_kexec_load filter_add_blacklist(SYS_kexec_load, 0); #endif #ifdef SYS_kexec_file_load filter_add_blacklist(SYS_kexec_file_load, 0); #endif #ifdef SYS_open_by_handle_at filter_add_blacklist(SYS_open_by_handle_at, 0); #endif #ifdef SYS_init_module filter_add_blacklist(SYS_init_module, 0); #endif #ifdef SYS_finit_module // introduced in 2013 filter_add_blacklist(SYS_finit_module, 0); #endif #ifdef SYS_delete_module filter_add_blacklist(SYS_delete_module, 0); #endif #ifdef SYS_iopl filter_add_blacklist(SYS_iopl, 0); #endif #ifdef SYS_ioperm filter_add_blacklist(SYS_ioperm, 0); #endif #ifdef SYS_ni_syscall // new io permissions call on arm devices filter_add_blacklist(SYS_ni_syscall, 0); #endif #ifdef SYS_swapon filter_add_blacklist(SYS_swapon, 0); #endif #ifdef SYS_swapoff filter_add_blacklist(SYS_swapoff, 0); #endif #ifdef SYS_syslog filter_add_blacklist(SYS_syslog, 0); #endif #ifdef SYS_process_vm_readv filter_add_blacklist(SYS_process_vm_readv, 0); #endif #ifdef SYS_process_vm_writev filter_add_blacklist(SYS_process_vm_writev, 0); #endif // mknod removed in 0.9.29 - it brakes Zotero extension //#ifdef SYS_mknod // filter_add_blacklist(SYS_mknod, 0); //#endif // new syscalls in 0.9,23 #ifdef SYS_sysfs filter_add_blacklist(SYS_sysfs, 0); #endif #ifdef SYS__sysctl filter_add_blacklist(SYS__sysctl, 0); #endif #ifdef SYS_adjtimex filter_add_blacklist(SYS_adjtimex, 0); #endif #ifdef SYS_clock_adjtime filter_add_blacklist(SYS_clock_adjtime, 0); #endif #ifdef SYS_lookup_dcookie filter_add_blacklist(SYS_lookup_dcookie, 0); #endif #ifdef SYS_perf_event_open filter_add_blacklist(SYS_perf_event_open, 0); #endif #ifdef SYS_fanotify_init filter_add_blacklist(SYS_fanotify_init, 0); #endif #ifdef SYS_kcmp filter_add_blacklist(SYS_kcmp, 0); #endif // 0.9.32 #ifdef SYS_add_key filter_add_blacklist(SYS_add_key, 0); #endif #ifdef SYS_request_key filter_add_blacklist(SYS_request_key, 0); #endif #ifdef SYS_keyctl filter_add_blacklist(SYS_keyctl, 0); #endif #ifdef SYS_uselib filter_add_blacklist(SYS_uselib, 0); #endif #ifdef SYS_acct filter_add_blacklist(SYS_acct, 0); #endif #ifdef SYS_modify_ldt filter_add_blacklist(SYS_modify_ldt, 0); #endif //#ifdef SYS_unshare // filter_add_blacklist(SYS_unshare, 0); //#endif #ifdef SYS_pivot_root filter_add_blacklist(SYS_pivot_root, 0); #endif //#ifdef SYS_quotactl // filter_add_blacklist(SYS_quotactl, 0); //#endif #ifdef SYS_io_setup filter_add_blacklist(SYS_io_setup, 0); #endif #ifdef SYS_io_destroy filter_add_blacklist(SYS_io_destroy, 0); #endif #ifdef SYS_io_getevents filter_add_blacklist(SYS_io_getevents, 0); #endif #ifdef SYS_io_submit filter_add_blacklist(SYS_io_submit, 0); #endif #ifdef SYS_io_cancel filter_add_blacklist(SYS_io_cancel, 0); #endif #ifdef SYS_remap_file_pages filter_add_blacklist(SYS_remap_file_pages, 0); #endif #ifdef SYS_mbind filter_add_blacklist(SYS_mbind, 0); #endif #ifdef SYS_get_mempolicy filter_add_blacklist(SYS_get_mempolicy, 0); #endif #ifdef SYS_set_mempolicy filter_add_blacklist(SYS_set_mempolicy, 0); #endif #ifdef SYS_migrate_pages filter_add_blacklist(SYS_migrate_pages, 0); #endif #ifdef SYS_move_pages filter_add_blacklist(SYS_move_pages, 0); #endif #ifdef SYS_vmsplice filter_add_blacklist(SYS_vmsplice, 0); #endif #ifdef SYS_chroot filter_add_blacklist(SYS_chroot, 0); #endif //#ifdef SYS_set_robust_list // filter_add_blacklist(SYS_set_robust_list, 0); //#endif //#ifdef SYS_get_robust_list // filter_add_blacklist(SYS_get_robust_list, 0); //#endif // CHECK_SECCOMP(seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(clone), 1, // SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER))); // 0.9.39 #ifdef SYS_tuxcall filter_add_blacklist(SYS_tuxcall, 0); #endif #ifdef SYS_reboot filter_add_blacklist(SYS_reboot, 0); #endif #ifdef SYS_nfsservctl filter_add_blacklist(SYS_nfsservctl, 0); #endif #ifdef SYS_get_kernel_syms filter_add_blacklist(SYS_get_kernel_syms, 0); #endif } // default seccomp filter with additional drop list if (cfg.seccomp_list && cfg.seccomp_list_drop == NULL) { if (syscall_check_list(cfg.seccomp_list, filter_add_blacklist, 0)) { fprintf(stderr, "Error: cannot load seccomp filter\n"); exit(1); } } // drop list else if (cfg.seccomp_list == NULL && cfg.seccomp_list_drop) { if (syscall_check_list(cfg.seccomp_list_drop, filter_add_blacklist, 0)) { fprintf(stderr, "Error: cannot load seccomp filter\n"); exit(1); } } filter_end_blacklist(); if (arg_debug) filter_debug(); // save seccomp filter in /tmp/firejail/mnt/seccomp // in order to use it in --join operations write_seccomp_file(); struct sock_fprog prog = { .len = sfilter_index, .filter = sfilter, }; if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { if (enforce_seccomp) { fprintf(stderr, "Error: a seccomp-enabled Linux kernel is required, exiting...\n"); exit(1); } else fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); return 1; } return 0; } // keep filter for seccomp option int seccomp_filter_keep(void) { filter_init(); // these 4 syscalls are used by firejail after the seccomp filter is initialized filter_add_whitelist(SYS_setuid, 0); filter_add_whitelist(SYS_setgid, 0); filter_add_whitelist(SYS_setgroups, 0); filter_add_whitelist(SYS_dup, 0); // apply keep list if (cfg.seccomp_list_keep) { if (syscall_check_list(cfg.seccomp_list_keep, filter_add_whitelist, 0)) { fprintf(stderr, "Error: cannot load seccomp filter\n"); exit(1); } } filter_end_whitelist(); if (arg_debug) filter_debug(); // save seccomp filter in /tmp/firejail/mnt/seccomp // in order to use it in --join operations write_seccomp_file(); struct sock_fprog prog = { .len = sfilter_index, .filter = sfilter, }; if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); return 1; } else if (arg_debug) { printf("seccomp enabled\n"); } return 0; }
void seccomp_secondary_64(const char *fname) { // hardcoded syscall values struct sock_filter filter[] = { VALIDATE_ARCHITECTURE_64, EXAMINE_SYSCALL, BLACKLIST(165), // mount BLACKLIST(166), // umount2 // todo: implement --allow-debuggers BLACKLIST(101), // ptrace BLACKLIST(246), // kexec_load BLACKLIST(304), // open_by_handle_at BLACKLIST(303), // name_to_handle_at BLACKLIST(174), // create_module BLACKLIST(175), // init_module BLACKLIST(313), // finit_module BLACKLIST(176), // delete_module BLACKLIST(172), // iopl BLACKLIST(173), // ioperm BLACKLIST(251), // ioprio_set BLACKLIST(167), // swapon BLACKLIST(168), // swapoff BLACKLIST(103), // syslog BLACKLIST(310), // process_vm_readv BLACKLIST(311), // process_vm_writev BLACKLIST(139), // sysfs BLACKLIST(156), // _sysctl BLACKLIST(159), // adjtimex BLACKLIST(305), // clock_adjtime BLACKLIST(212), // lookup_dcookie BLACKLIST(298), // perf_event_open BLACKLIST(300), // fanotify_init BLACKLIST(312), // kcmp BLACKLIST(248), // add_key BLACKLIST(249), // request_key BLACKLIST(250), // keyctl BLACKLIST(134), // uselib BLACKLIST(163), // acct BLACKLIST(154), // modify_ldt BLACKLIST(155), // pivot_root BLACKLIST(206), // io_setup BLACKLIST(207), // io_destroy BLACKLIST(208), // io_getevents BLACKLIST(209), // io_submit BLACKLIST(210), // io_cancel BLACKLIST(216), // remap_file_pages BLACKLIST(237), // mbind BLACKLIST(239), // get_mempolicy BLACKLIST(238), // set_mempolicy BLACKLIST(256), // migrate_pages BLACKLIST(279), // move_pages BLACKLIST(278), // vmsplice BLACKLIST(161), // chroot BLACKLIST(184), // tuxcall BLACKLIST(169), // reboot BLACKLIST(180), // nfsservctl BLACKLIST(177), // get_kernel_syms RETURN_ALLOW }; // save filter to file int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (dst < 0) { fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); exit(1); } int size = (int) sizeof(filter); int written = 0; while (written < size) { int rv = write(dst, (unsigned char *) filter + written, size - written); if (rv == -1) { fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); exit(1); } written += rv; } close(dst); }