158a0f0d0SEitan Adler /* 258a0f0d0SEitan Adler * Redistribution and use in source and binary forms, with or without 358a0f0d0SEitan Adler * modification, are permitted provided that the following conditions 458a0f0d0SEitan Adler * are met: 558a0f0d0SEitan Adler * 1. Redistributions of source code must retain the above copyright 658a0f0d0SEitan Adler * notice immediately at the beginning of the file, without modification, 758a0f0d0SEitan Adler * this list of conditions, and the following disclaimer. 858a0f0d0SEitan Adler * 2. Redistributions in binary form must reproduce the above copyright 958a0f0d0SEitan Adler * notice, this list of conditions and the following disclaimer in the 1058a0f0d0SEitan Adler * documentation and/or other materials provided with the distribution. 1158a0f0d0SEitan Adler * 1258a0f0d0SEitan Adler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1358a0f0d0SEitan Adler * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1458a0f0d0SEitan Adler * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1558a0f0d0SEitan Adler * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 1658a0f0d0SEitan Adler * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1758a0f0d0SEitan Adler * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1858a0f0d0SEitan Adler * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1958a0f0d0SEitan Adler * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2058a0f0d0SEitan Adler * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2158a0f0d0SEitan Adler * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2258a0f0d0SEitan Adler * SUCH DAMAGE. 2358a0f0d0SEitan Adler */ 2458a0f0d0SEitan Adler /* 2558a0f0d0SEitan Adler * libseccomp hooks. 2658a0f0d0SEitan Adler */ 2758a0f0d0SEitan Adler #include "file.h" 2858a0f0d0SEitan Adler 2958a0f0d0SEitan Adler #ifndef lint 30*d38c30c0SXin LI FILE_RCSID("@(#)$File: seccomp.c,v 1.11 2019/07/18 20:32:06 christos Exp $") 3158a0f0d0SEitan Adler #endif /* lint */ 3258a0f0d0SEitan Adler 3358a0f0d0SEitan Adler #if HAVE_LIBSECCOMP 3458a0f0d0SEitan Adler #include <seccomp.h> /* libseccomp */ 3558a0f0d0SEitan Adler #include <sys/prctl.h> /* prctl */ 36*d38c30c0SXin LI #include <sys/ioctl.h> 3758a0f0d0SEitan Adler #include <sys/socket.h> 3858a0f0d0SEitan Adler #include <fcntl.h> 3958a0f0d0SEitan Adler #include <stdlib.h> 4058a0f0d0SEitan Adler #include <errno.h> 4158a0f0d0SEitan Adler 4258a0f0d0SEitan Adler #define DENY_RULE(call) \ 4358a0f0d0SEitan Adler do \ 4458a0f0d0SEitan Adler if (seccomp_rule_add (ctx, SCMP_ACT_KILL, SCMP_SYS(call), 0) == -1) \ 4558a0f0d0SEitan Adler goto out; \ 4658a0f0d0SEitan Adler while (/*CONSTCOND*/0) 4758a0f0d0SEitan Adler #define ALLOW_RULE(call) \ 4858a0f0d0SEitan Adler do \ 4958a0f0d0SEitan Adler if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(call), 0) == -1) \ 5058a0f0d0SEitan Adler goto out; \ 5158a0f0d0SEitan Adler while (/*CONSTCOND*/0) 5258a0f0d0SEitan Adler 53*d38c30c0SXin LI #define ALLOW_IOCTL_RULE(param) \ 54*d38c30c0SXin LI do \ 55*d38c30c0SXin LI if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1, \ 56*d38c30c0SXin LI SCMP_CMP(1, SCMP_CMP_EQ, param)) == -1) \ 57*d38c30c0SXin LI goto out; \ 58*d38c30c0SXin LI while (/*CONSTCOND*/0) 5958a0f0d0SEitan Adler 60*d38c30c0SXin LI static scmp_filter_ctx ctx; 6158a0f0d0SEitan Adler 6258a0f0d0SEitan Adler int 6358a0f0d0SEitan Adler enable_sandbox_basic(void) 6458a0f0d0SEitan Adler { 6558a0f0d0SEitan Adler 6658a0f0d0SEitan Adler if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) 6758a0f0d0SEitan Adler return -1; 6858a0f0d0SEitan Adler 6958a0f0d0SEitan Adler if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) 7058a0f0d0SEitan Adler return -1; 7158a0f0d0SEitan Adler 7258a0f0d0SEitan Adler // initialize the filter 7358a0f0d0SEitan Adler ctx = seccomp_init(SCMP_ACT_ALLOW); 7458a0f0d0SEitan Adler if (ctx == NULL) 7558a0f0d0SEitan Adler return 1; 7658a0f0d0SEitan Adler 7758a0f0d0SEitan Adler DENY_RULE(_sysctl); 7858a0f0d0SEitan Adler DENY_RULE(acct); 7958a0f0d0SEitan Adler DENY_RULE(add_key); 8058a0f0d0SEitan Adler DENY_RULE(adjtimex); 8158a0f0d0SEitan Adler DENY_RULE(chroot); 8258a0f0d0SEitan Adler DENY_RULE(clock_adjtime); 8358a0f0d0SEitan Adler DENY_RULE(create_module); 8458a0f0d0SEitan Adler DENY_RULE(delete_module); 8558a0f0d0SEitan Adler DENY_RULE(fanotify_init); 8658a0f0d0SEitan Adler DENY_RULE(finit_module); 8758a0f0d0SEitan Adler DENY_RULE(get_kernel_syms); 8858a0f0d0SEitan Adler DENY_RULE(get_mempolicy); 8958a0f0d0SEitan Adler DENY_RULE(init_module); 9058a0f0d0SEitan Adler DENY_RULE(io_cancel); 9158a0f0d0SEitan Adler DENY_RULE(io_destroy); 9258a0f0d0SEitan Adler DENY_RULE(io_getevents); 9358a0f0d0SEitan Adler DENY_RULE(io_setup); 9458a0f0d0SEitan Adler DENY_RULE(io_submit); 9558a0f0d0SEitan Adler DENY_RULE(ioperm); 9658a0f0d0SEitan Adler DENY_RULE(iopl); 9758a0f0d0SEitan Adler DENY_RULE(ioprio_set); 9858a0f0d0SEitan Adler DENY_RULE(kcmp); 9958a0f0d0SEitan Adler #ifdef __NR_kexec_file_load 10058a0f0d0SEitan Adler DENY_RULE(kexec_file_load); 10158a0f0d0SEitan Adler #endif 10258a0f0d0SEitan Adler DENY_RULE(kexec_load); 10358a0f0d0SEitan Adler DENY_RULE(keyctl); 10458a0f0d0SEitan Adler DENY_RULE(lookup_dcookie); 10558a0f0d0SEitan Adler DENY_RULE(mbind); 10658a0f0d0SEitan Adler DENY_RULE(nfsservctl); 10758a0f0d0SEitan Adler DENY_RULE(migrate_pages); 10858a0f0d0SEitan Adler DENY_RULE(modify_ldt); 10958a0f0d0SEitan Adler DENY_RULE(mount); 11058a0f0d0SEitan Adler DENY_RULE(move_pages); 11158a0f0d0SEitan Adler DENY_RULE(name_to_handle_at); 11258a0f0d0SEitan Adler DENY_RULE(open_by_handle_at); 11358a0f0d0SEitan Adler DENY_RULE(perf_event_open); 11458a0f0d0SEitan Adler DENY_RULE(pivot_root); 11558a0f0d0SEitan Adler DENY_RULE(process_vm_readv); 11658a0f0d0SEitan Adler DENY_RULE(process_vm_writev); 11758a0f0d0SEitan Adler DENY_RULE(ptrace); 11858a0f0d0SEitan Adler DENY_RULE(reboot); 11958a0f0d0SEitan Adler DENY_RULE(remap_file_pages); 12058a0f0d0SEitan Adler DENY_RULE(request_key); 12158a0f0d0SEitan Adler DENY_RULE(set_mempolicy); 12258a0f0d0SEitan Adler DENY_RULE(swapoff); 12358a0f0d0SEitan Adler DENY_RULE(swapon); 12458a0f0d0SEitan Adler DENY_RULE(sysfs); 12558a0f0d0SEitan Adler DENY_RULE(syslog); 12658a0f0d0SEitan Adler DENY_RULE(tuxcall); 12758a0f0d0SEitan Adler DENY_RULE(umount2); 12858a0f0d0SEitan Adler DENY_RULE(uselib); 12958a0f0d0SEitan Adler DENY_RULE(vmsplice); 13058a0f0d0SEitan Adler 13158a0f0d0SEitan Adler // blocking dangerous syscalls that file should not need 13258a0f0d0SEitan Adler DENY_RULE (execve); 13358a0f0d0SEitan Adler DENY_RULE (socket); 13458a0f0d0SEitan Adler // ... 13558a0f0d0SEitan Adler 13658a0f0d0SEitan Adler 13758a0f0d0SEitan Adler // applying filter... 13858a0f0d0SEitan Adler if (seccomp_load (ctx) == -1) 13958a0f0d0SEitan Adler goto out; 14058a0f0d0SEitan Adler // free ctx after the filter has been loaded into the kernel 14158a0f0d0SEitan Adler seccomp_release(ctx); 14258a0f0d0SEitan Adler return 0; 14358a0f0d0SEitan Adler 14458a0f0d0SEitan Adler out: 14558a0f0d0SEitan Adler seccomp_release(ctx); 14658a0f0d0SEitan Adler return -1; 14758a0f0d0SEitan Adler } 14858a0f0d0SEitan Adler 14958a0f0d0SEitan Adler 15058a0f0d0SEitan Adler int 15158a0f0d0SEitan Adler enable_sandbox_full(void) 15258a0f0d0SEitan Adler { 15358a0f0d0SEitan Adler 15458a0f0d0SEitan Adler // prevent child processes from getting more priv e.g. via setuid, 15558a0f0d0SEitan Adler // capabilities, ... 15658a0f0d0SEitan Adler if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) 15758a0f0d0SEitan Adler return -1; 15858a0f0d0SEitan Adler 15958a0f0d0SEitan Adler if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) 16058a0f0d0SEitan Adler return -1; 16158a0f0d0SEitan Adler 16258a0f0d0SEitan Adler // initialize the filter 16358a0f0d0SEitan Adler ctx = seccomp_init(SCMP_ACT_KILL); 16458a0f0d0SEitan Adler if (ctx == NULL) 16558a0f0d0SEitan Adler return -1; 16658a0f0d0SEitan Adler 16758a0f0d0SEitan Adler ALLOW_RULE(access); 16858a0f0d0SEitan Adler ALLOW_RULE(brk); 16958a0f0d0SEitan Adler ALLOW_RULE(close); 17058a0f0d0SEitan Adler ALLOW_RULE(dup2); 17158a0f0d0SEitan Adler ALLOW_RULE(exit); 17258a0f0d0SEitan Adler ALLOW_RULE(exit_group); 17358a0f0d0SEitan Adler ALLOW_RULE(fcntl); 1742dc4dbb9SEitan Adler ALLOW_RULE(fcntl64); 17558a0f0d0SEitan Adler ALLOW_RULE(fstat); 1762dc4dbb9SEitan Adler ALLOW_RULE(fstat64); 177*d38c30c0SXin LI #ifdef XZLIBSUPPORT 178*d38c30c0SXin LI ALLOW_RULE(futex); 179*d38c30c0SXin LI #endif 18058a0f0d0SEitan Adler ALLOW_RULE(getdents); 1812dc4dbb9SEitan Adler #ifdef __NR_getdents64 1822dc4dbb9SEitan Adler ALLOW_RULE(getdents64); 1832dc4dbb9SEitan Adler #endif 184*d38c30c0SXin LI #ifdef FIONREAD 185*d38c30c0SXin LI // called in src/compress.c under sread 186*d38c30c0SXin LI ALLOW_IOCTL_RULE(FIONREAD); 187*d38c30c0SXin LI #endif 188*d38c30c0SXin LI #ifdef TIOCGWINSZ 189*d38c30c0SXin LI // musl libc may call ioctl TIOCGWINSZ when calling stdout 190*d38c30c0SXin LI ALLOW_IOCTL_RULE(TIOCGWINSZ); 191*d38c30c0SXin LI #endif 19258a0f0d0SEitan Adler ALLOW_RULE(lseek); 1932dc4dbb9SEitan Adler ALLOW_RULE(_llseek); 19458a0f0d0SEitan Adler ALLOW_RULE(lstat); 1952dc4dbb9SEitan Adler ALLOW_RULE(lstat64); 19648c779cdSXin LI ALLOW_RULE(madvise); 19758a0f0d0SEitan Adler ALLOW_RULE(mmap); 1982dc4dbb9SEitan Adler ALLOW_RULE(mmap2); 19958a0f0d0SEitan Adler ALLOW_RULE(mprotect); 20058a0f0d0SEitan Adler ALLOW_RULE(mremap); 20158a0f0d0SEitan Adler ALLOW_RULE(munmap); 2022dc4dbb9SEitan Adler #ifdef __NR_newfstatat 2032dc4dbb9SEitan Adler ALLOW_RULE(newfstatat); 2042dc4dbb9SEitan Adler #endif 20558a0f0d0SEitan Adler ALLOW_RULE(open); 20658a0f0d0SEitan Adler ALLOW_RULE(openat); 20758a0f0d0SEitan Adler ALLOW_RULE(pread64); 20858a0f0d0SEitan Adler ALLOW_RULE(read); 20958a0f0d0SEitan Adler ALLOW_RULE(readlink); 21058a0f0d0SEitan Adler ALLOW_RULE(rt_sigaction); 21158a0f0d0SEitan Adler ALLOW_RULE(rt_sigprocmask); 21258a0f0d0SEitan Adler ALLOW_RULE(rt_sigreturn); 21358a0f0d0SEitan Adler ALLOW_RULE(select); 21458a0f0d0SEitan Adler ALLOW_RULE(stat); 2152dc4dbb9SEitan Adler ALLOW_RULE(stat64); 21658a0f0d0SEitan Adler ALLOW_RULE(sysinfo); 217*d38c30c0SXin LI ALLOW_RULE(umask); // Used in file_pipe2file() 21858a0f0d0SEitan Adler ALLOW_RULE(unlink); 21958a0f0d0SEitan Adler ALLOW_RULE(write); 22058a0f0d0SEitan Adler 22158a0f0d0SEitan Adler 22258a0f0d0SEitan Adler #if 0 22358a0f0d0SEitan Adler // needed by valgrind 22458a0f0d0SEitan Adler ALLOW_RULE(gettid); 22558a0f0d0SEitan Adler ALLOW_RULE(getpid); 22658a0f0d0SEitan Adler ALLOW_RULE(rt_sigtimedwait); 22758a0f0d0SEitan Adler #endif 22858a0f0d0SEitan Adler 22958a0f0d0SEitan Adler #if 0 23058a0f0d0SEitan Adler /* special restrictions for socket, only allow AF_UNIX/AF_LOCAL */ 23158a0f0d0SEitan Adler if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1, 23258a0f0d0SEitan Adler SCMP_CMP(0, SCMP_CMP_EQ, AF_UNIX)) == -1) 23358a0f0d0SEitan Adler goto out; 23458a0f0d0SEitan Adler 23558a0f0d0SEitan Adler if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1, 23658a0f0d0SEitan Adler SCMP_CMP(0, SCMP_CMP_EQ, AF_LOCAL)) == -1) 23758a0f0d0SEitan Adler goto out; 23858a0f0d0SEitan Adler 23958a0f0d0SEitan Adler 24058a0f0d0SEitan Adler /* special restrictions for open, prevent opening files for writing */ 24158a0f0d0SEitan Adler if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1, 24258a0f0d0SEitan Adler SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR, 0)) == -1) 24358a0f0d0SEitan Adler goto out; 24458a0f0d0SEitan Adler 24558a0f0d0SEitan Adler if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1, 24658a0f0d0SEitan Adler SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)) == -1) 24758a0f0d0SEitan Adler goto out; 24858a0f0d0SEitan Adler 24958a0f0d0SEitan Adler if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1, 25058a0f0d0SEitan Adler SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)) == -1) 25158a0f0d0SEitan Adler goto out; 25258a0f0d0SEitan Adler 25358a0f0d0SEitan Adler 25458a0f0d0SEitan Adler /* allow stderr */ 25558a0f0d0SEitan Adler if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, 25658a0f0d0SEitan Adler SCMP_CMP(0, SCMP_CMP_EQ, 2)) == -1) 25758a0f0d0SEitan Adler goto out; 25858a0f0d0SEitan Adler #endif 25958a0f0d0SEitan Adler 26058a0f0d0SEitan Adler // applying filter... 26158a0f0d0SEitan Adler if (seccomp_load(ctx) == -1) 26258a0f0d0SEitan Adler goto out; 26358a0f0d0SEitan Adler // free ctx after the filter has been loaded into the kernel 26458a0f0d0SEitan Adler seccomp_release(ctx); 26558a0f0d0SEitan Adler return 0; 26658a0f0d0SEitan Adler 26758a0f0d0SEitan Adler out: 26858a0f0d0SEitan Adler // something went wrong 26958a0f0d0SEitan Adler seccomp_release(ctx); 27058a0f0d0SEitan Adler return -1; 27158a0f0d0SEitan Adler } 27258a0f0d0SEitan Adler #endif 273