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*48c779cdSXin LI FILE_RCSID("@(#)$File: seccomp.c,v 1.8 2019/02/24 18:12:04 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 */ 3658a0f0d0SEitan Adler #include <sys/socket.h> 3758a0f0d0SEitan Adler #include <fcntl.h> 3858a0f0d0SEitan Adler #include <stdlib.h> 3958a0f0d0SEitan Adler #include <errno.h> 4058a0f0d0SEitan Adler 4158a0f0d0SEitan Adler #define DENY_RULE(call) \ 4258a0f0d0SEitan Adler do \ 4358a0f0d0SEitan Adler if (seccomp_rule_add (ctx, SCMP_ACT_KILL, SCMP_SYS(call), 0) == -1) \ 4458a0f0d0SEitan Adler goto out; \ 4558a0f0d0SEitan Adler while (/*CONSTCOND*/0) 4658a0f0d0SEitan Adler #define ALLOW_RULE(call) \ 4758a0f0d0SEitan Adler do \ 4858a0f0d0SEitan Adler if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(call), 0) == -1) \ 4958a0f0d0SEitan Adler goto out; \ 5058a0f0d0SEitan Adler while (/*CONSTCOND*/0) 5158a0f0d0SEitan Adler 5258a0f0d0SEitan Adler static scmp_filter_ctx ctx; 5358a0f0d0SEitan Adler 5458a0f0d0SEitan Adler 5558a0f0d0SEitan Adler int 5658a0f0d0SEitan Adler enable_sandbox_basic(void) 5758a0f0d0SEitan Adler { 5858a0f0d0SEitan Adler 5958a0f0d0SEitan Adler if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) 6058a0f0d0SEitan Adler return -1; 6158a0f0d0SEitan Adler 6258a0f0d0SEitan Adler if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) 6358a0f0d0SEitan Adler return -1; 6458a0f0d0SEitan Adler 6558a0f0d0SEitan Adler // initialize the filter 6658a0f0d0SEitan Adler ctx = seccomp_init(SCMP_ACT_ALLOW); 6758a0f0d0SEitan Adler if (ctx == NULL) 6858a0f0d0SEitan Adler return 1; 6958a0f0d0SEitan Adler 7058a0f0d0SEitan Adler DENY_RULE(_sysctl); 7158a0f0d0SEitan Adler DENY_RULE(acct); 7258a0f0d0SEitan Adler DENY_RULE(add_key); 7358a0f0d0SEitan Adler DENY_RULE(adjtimex); 7458a0f0d0SEitan Adler DENY_RULE(chroot); 7558a0f0d0SEitan Adler DENY_RULE(clock_adjtime); 7658a0f0d0SEitan Adler DENY_RULE(create_module); 7758a0f0d0SEitan Adler DENY_RULE(delete_module); 7858a0f0d0SEitan Adler DENY_RULE(fanotify_init); 7958a0f0d0SEitan Adler DENY_RULE(finit_module); 8058a0f0d0SEitan Adler DENY_RULE(get_kernel_syms); 8158a0f0d0SEitan Adler DENY_RULE(get_mempolicy); 8258a0f0d0SEitan Adler DENY_RULE(init_module); 8358a0f0d0SEitan Adler DENY_RULE(io_cancel); 8458a0f0d0SEitan Adler DENY_RULE(io_destroy); 8558a0f0d0SEitan Adler DENY_RULE(io_getevents); 8658a0f0d0SEitan Adler DENY_RULE(io_setup); 8758a0f0d0SEitan Adler DENY_RULE(io_submit); 8858a0f0d0SEitan Adler DENY_RULE(ioperm); 8958a0f0d0SEitan Adler DENY_RULE(iopl); 9058a0f0d0SEitan Adler DENY_RULE(ioprio_set); 9158a0f0d0SEitan Adler DENY_RULE(kcmp); 9258a0f0d0SEitan Adler #ifdef __NR_kexec_file_load 9358a0f0d0SEitan Adler DENY_RULE(kexec_file_load); 9458a0f0d0SEitan Adler #endif 9558a0f0d0SEitan Adler DENY_RULE(kexec_load); 9658a0f0d0SEitan Adler DENY_RULE(keyctl); 9758a0f0d0SEitan Adler DENY_RULE(lookup_dcookie); 9858a0f0d0SEitan Adler DENY_RULE(mbind); 9958a0f0d0SEitan Adler DENY_RULE(nfsservctl); 10058a0f0d0SEitan Adler DENY_RULE(migrate_pages); 10158a0f0d0SEitan Adler DENY_RULE(modify_ldt); 10258a0f0d0SEitan Adler DENY_RULE(mount); 10358a0f0d0SEitan Adler DENY_RULE(move_pages); 10458a0f0d0SEitan Adler DENY_RULE(name_to_handle_at); 10558a0f0d0SEitan Adler DENY_RULE(open_by_handle_at); 10658a0f0d0SEitan Adler DENY_RULE(perf_event_open); 10758a0f0d0SEitan Adler DENY_RULE(pivot_root); 10858a0f0d0SEitan Adler DENY_RULE(process_vm_readv); 10958a0f0d0SEitan Adler DENY_RULE(process_vm_writev); 11058a0f0d0SEitan Adler DENY_RULE(ptrace); 11158a0f0d0SEitan Adler DENY_RULE(reboot); 11258a0f0d0SEitan Adler DENY_RULE(remap_file_pages); 11358a0f0d0SEitan Adler DENY_RULE(request_key); 11458a0f0d0SEitan Adler DENY_RULE(set_mempolicy); 11558a0f0d0SEitan Adler DENY_RULE(swapoff); 11658a0f0d0SEitan Adler DENY_RULE(swapon); 11758a0f0d0SEitan Adler DENY_RULE(sysfs); 11858a0f0d0SEitan Adler DENY_RULE(syslog); 11958a0f0d0SEitan Adler DENY_RULE(tuxcall); 12058a0f0d0SEitan Adler DENY_RULE(umount2); 12158a0f0d0SEitan Adler DENY_RULE(uselib); 12258a0f0d0SEitan Adler DENY_RULE(vmsplice); 12358a0f0d0SEitan Adler 12458a0f0d0SEitan Adler // blocking dangerous syscalls that file should not need 12558a0f0d0SEitan Adler DENY_RULE (execve); 12658a0f0d0SEitan Adler DENY_RULE (socket); 12758a0f0d0SEitan Adler // ... 12858a0f0d0SEitan Adler 12958a0f0d0SEitan Adler 13058a0f0d0SEitan Adler // applying filter... 13158a0f0d0SEitan Adler if (seccomp_load (ctx) == -1) 13258a0f0d0SEitan Adler goto out; 13358a0f0d0SEitan Adler // free ctx after the filter has been loaded into the kernel 13458a0f0d0SEitan Adler seccomp_release(ctx); 13558a0f0d0SEitan Adler return 0; 13658a0f0d0SEitan Adler 13758a0f0d0SEitan Adler out: 13858a0f0d0SEitan Adler seccomp_release(ctx); 13958a0f0d0SEitan Adler return -1; 14058a0f0d0SEitan Adler } 14158a0f0d0SEitan Adler 14258a0f0d0SEitan Adler 14358a0f0d0SEitan Adler int 14458a0f0d0SEitan Adler enable_sandbox_full(void) 14558a0f0d0SEitan Adler { 14658a0f0d0SEitan Adler 14758a0f0d0SEitan Adler // prevent child processes from getting more priv e.g. via setuid, 14858a0f0d0SEitan Adler // capabilities, ... 14958a0f0d0SEitan Adler if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) 15058a0f0d0SEitan Adler return -1; 15158a0f0d0SEitan Adler 15258a0f0d0SEitan Adler if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) 15358a0f0d0SEitan Adler return -1; 15458a0f0d0SEitan Adler 15558a0f0d0SEitan Adler // initialize the filter 15658a0f0d0SEitan Adler ctx = seccomp_init(SCMP_ACT_KILL); 15758a0f0d0SEitan Adler if (ctx == NULL) 15858a0f0d0SEitan Adler return -1; 15958a0f0d0SEitan Adler 16058a0f0d0SEitan Adler ALLOW_RULE(access); 16158a0f0d0SEitan Adler ALLOW_RULE(brk); 16258a0f0d0SEitan Adler ALLOW_RULE(close); 16358a0f0d0SEitan Adler ALLOW_RULE(dup2); 16458a0f0d0SEitan Adler ALLOW_RULE(exit); 16558a0f0d0SEitan Adler ALLOW_RULE(exit_group); 16658a0f0d0SEitan Adler ALLOW_RULE(fcntl); 1672dc4dbb9SEitan Adler ALLOW_RULE(fcntl64); 16858a0f0d0SEitan Adler ALLOW_RULE(fstat); 1692dc4dbb9SEitan Adler ALLOW_RULE(fstat64); 17058a0f0d0SEitan Adler ALLOW_RULE(getdents); 1712dc4dbb9SEitan Adler #ifdef __NR_getdents64 1722dc4dbb9SEitan Adler ALLOW_RULE(getdents64); 1732dc4dbb9SEitan Adler #endif 17458a0f0d0SEitan Adler ALLOW_RULE(ioctl); 17558a0f0d0SEitan Adler ALLOW_RULE(lseek); 1762dc4dbb9SEitan Adler ALLOW_RULE(_llseek); 17758a0f0d0SEitan Adler ALLOW_RULE(lstat); 1782dc4dbb9SEitan Adler ALLOW_RULE(lstat64); 179*48c779cdSXin LI ALLOW_RULE(madvise); 18058a0f0d0SEitan Adler ALLOW_RULE(mmap); 1812dc4dbb9SEitan Adler ALLOW_RULE(mmap2); 18258a0f0d0SEitan Adler ALLOW_RULE(mprotect); 18358a0f0d0SEitan Adler ALLOW_RULE(mremap); 18458a0f0d0SEitan Adler ALLOW_RULE(munmap); 1852dc4dbb9SEitan Adler #ifdef __NR_newfstatat 1862dc4dbb9SEitan Adler ALLOW_RULE(newfstatat); 1872dc4dbb9SEitan Adler #endif 18858a0f0d0SEitan Adler ALLOW_RULE(open); 18958a0f0d0SEitan Adler ALLOW_RULE(openat); 19058a0f0d0SEitan Adler ALLOW_RULE(pread64); 19158a0f0d0SEitan Adler ALLOW_RULE(read); 19258a0f0d0SEitan Adler ALLOW_RULE(readlink); 19358a0f0d0SEitan Adler ALLOW_RULE(rt_sigaction); 19458a0f0d0SEitan Adler ALLOW_RULE(rt_sigprocmask); 19558a0f0d0SEitan Adler ALLOW_RULE(rt_sigreturn); 19658a0f0d0SEitan Adler ALLOW_RULE(select); 19758a0f0d0SEitan Adler ALLOW_RULE(stat); 1982dc4dbb9SEitan Adler ALLOW_RULE(stat64); 19958a0f0d0SEitan Adler ALLOW_RULE(sysinfo); 20058a0f0d0SEitan Adler ALLOW_RULE(unlink); 20158a0f0d0SEitan Adler ALLOW_RULE(write); 20258a0f0d0SEitan Adler 20358a0f0d0SEitan Adler 20458a0f0d0SEitan Adler #if 0 20558a0f0d0SEitan Adler // needed by valgrind 20658a0f0d0SEitan Adler ALLOW_RULE(gettid); 20758a0f0d0SEitan Adler ALLOW_RULE(getpid); 20858a0f0d0SEitan Adler ALLOW_RULE(rt_sigtimedwait); 20958a0f0d0SEitan Adler #endif 21058a0f0d0SEitan Adler 21158a0f0d0SEitan Adler #if 0 21258a0f0d0SEitan Adler /* special restrictions for socket, only allow AF_UNIX/AF_LOCAL */ 21358a0f0d0SEitan Adler if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1, 21458a0f0d0SEitan Adler SCMP_CMP(0, SCMP_CMP_EQ, AF_UNIX)) == -1) 21558a0f0d0SEitan Adler goto out; 21658a0f0d0SEitan Adler 21758a0f0d0SEitan Adler if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1, 21858a0f0d0SEitan Adler SCMP_CMP(0, SCMP_CMP_EQ, AF_LOCAL)) == -1) 21958a0f0d0SEitan Adler goto out; 22058a0f0d0SEitan Adler 22158a0f0d0SEitan Adler 22258a0f0d0SEitan Adler /* special restrictions for open, prevent opening files for writing */ 22358a0f0d0SEitan Adler if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1, 22458a0f0d0SEitan Adler SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR, 0)) == -1) 22558a0f0d0SEitan Adler goto out; 22658a0f0d0SEitan Adler 22758a0f0d0SEitan Adler if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1, 22858a0f0d0SEitan Adler SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)) == -1) 22958a0f0d0SEitan Adler goto out; 23058a0f0d0SEitan Adler 23158a0f0d0SEitan Adler if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1, 23258a0f0d0SEitan Adler SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)) == -1) 23358a0f0d0SEitan Adler goto out; 23458a0f0d0SEitan Adler 23558a0f0d0SEitan Adler 23658a0f0d0SEitan Adler /* allow stderr */ 23758a0f0d0SEitan Adler if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, 23858a0f0d0SEitan Adler SCMP_CMP(0, SCMP_CMP_EQ, 2)) == -1) 23958a0f0d0SEitan Adler goto out; 24058a0f0d0SEitan Adler #endif 24158a0f0d0SEitan Adler 24258a0f0d0SEitan Adler // applying filter... 24358a0f0d0SEitan Adler if (seccomp_load(ctx) == -1) 24458a0f0d0SEitan Adler goto out; 24558a0f0d0SEitan Adler // free ctx after the filter has been loaded into the kernel 24658a0f0d0SEitan Adler seccomp_release(ctx); 24758a0f0d0SEitan Adler return 0; 24858a0f0d0SEitan Adler 24958a0f0d0SEitan Adler out: 25058a0f0d0SEitan Adler // something went wrong 25158a0f0d0SEitan Adler seccomp_release(ctx); 25258a0f0d0SEitan Adler return -1; 25358a0f0d0SEitan Adler } 25458a0f0d0SEitan Adler #endif 255