kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit c1affbbd740a08b5b733057eba76f1d0aa57c783
parent 61b8a9e90d8d6eaa3c9ef9b8a1446820a138d87f
Author: Joris Vink <joris@coders.se>
Date:   Wed, 25 Sep 2019 23:41:43 +0200

simplify bpf rule generation, add deny macro.

Diffstat:
include/kore/seccomp.h | 18++++++++++--------
src/seccomp.c | 59+++++++++++++++++++++--------------------------------------
2 files changed, 31 insertions(+), 46 deletions(-)

diff --git a/include/kore/seccomp.h b/include/kore/seccomp.h @@ -26,15 +26,17 @@ /* * Allow a system call by comparing the accumulator value (which will contain * the system call value) with the value of SYS_##name. - * - * If the value is equal the true branch (first) is taken, otherwise the - * false branch (second) is taken. - * - * When the program is constructed the true branch jump destination is - * resolved automatically. */ -#define KORE_SYSCALL_ALLOW(_name) \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_##_name, 0, 0) +#define KORE_SYSCALL_ALLOW(_name) \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_##_name, 0, 1), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) + +/* + * Explicit deny of a system call with an errno code for the caller. + */ +#define KORE_SYSCALL_DENY_ERRNO(_name, _errno) \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_##_name, 0, 1), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(_errno)) /* The length of a filter. */ #define KORE_FILTER_LEN(x) (sizeof(x) / sizeof(x[0])) diff --git a/src/seccomp.c b/src/seccomp.c @@ -36,8 +36,14 @@ #define SECCOMP_KILL_POLICY SECCOMP_RET_KILL #endif -/* The bare minimum to be able to run kore. */ +/* + * The bare minimum to be able to run kore. These are added last and can + * be overwritten by a filter program that is added before hand. + */ static struct sock_filter filter_kore[] = { + /* Deny these, but with EACCESS instead of dying. */ + KORE_SYSCALL_DENY_ERRNO(ioctl, EACCES), + /* File related. */ KORE_SYSCALL_ALLOW(open), KORE_SYSCALL_ALLOW(read), @@ -49,6 +55,7 @@ static struct sock_filter filter_kore[] = { KORE_SYSCALL_ALLOW(lseek), KORE_SYSCALL_ALLOW(close), KORE_SYSCALL_ALLOW(access), + KORE_SYSCALL_ALLOW(writev), KORE_SYSCALL_ALLOW(getcwd), KORE_SYSCALL_ALLOW(openat), KORE_SYSCALL_ALLOW(unlink), @@ -74,14 +81,18 @@ static struct sock_filter filter_kore[] = { KORE_SYSCALL_ALLOW(epoll_ctl), KORE_SYSCALL_ALLOW(setsockopt), KORE_SYSCALL_ALLOW(epoll_wait), + KORE_SYSCALL_ALLOW(epoll_pwait), - /* "Other" without clear category. */ - KORE_SYSCALL_ALLOW(futex), + /* Signal related. */ KORE_SYSCALL_ALLOW(sigaltstack), KORE_SYSCALL_ALLOW(rt_sigreturn), KORE_SYSCALL_ALLOW(rt_sigaction), KORE_SYSCALL_ALLOW(clock_gettime), + /* "Other" without clear category. */ + KORE_SYSCALL_ALLOW(futex), + KORE_SYSCALL_ALLOW(rt_sigprocmask), + #if defined(__NR_getrandom) KORE_SYSCALL_ALLOW(getrandom), #endif @@ -101,14 +112,9 @@ static struct sock_filter filter_prologue[] = { }; /* bpf program epilogue. */ -#define FILTER_EPILOGUE_ALLOW_OFFSET 1 - static struct sock_filter filter_epilogue[] = { /* Return hit if no system calls matched our list. */ - BPF_STMT(BPF_RET+BPF_K, SECCOMP_KILL_POLICY), - - /* Final destination for syscalls that are accepted. */ - BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) + BPF_STMT(BPF_RET+BPF_K, SECCOMP_KILL_POLICY) }; #define filter_prologue_len KORE_FILTER_LEN(filter_prologue) @@ -161,8 +167,8 @@ kore_seccomp_enable(void) struct sock_fprog prog; struct kore_runtime_call *rcall; struct filter *filter; + size_t prog_len, off, i; int skip_worker_filter; - size_t prog_len, pos, jmp_off, i; #if defined(KORE_DEBUG) memset(&sa, 0, sizeof(sa)); @@ -195,50 +201,27 @@ kore_seccomp_enable(void) KORE_FILTER_LEN(filter_kore)); } - /* - * Construct the entire BPF program by adding all relevant parts - * together. While doing so remember where the jmp_off is going to be - * so we can resolve the true branch for all comparisons. - */ - /* Start with the prologue. */ prog_len = filter_prologue_len; - jmp_off = prog_len; /* Now account for all enabled filters. */ - TAILQ_FOREACH(filter, &filters, list) { + TAILQ_FOREACH(filter, &filters, list) prog_len += filter->instructions; - jmp_off += filter->instructions; - } /* Finally add the epilogue. */ prog_len += filter_epilogue_len; - /* Finalize the jump position. */ - jmp_off += FILTER_EPILOGUE_ALLOW_OFFSET; - - /* Initial filter position is immediately after prologue. */ - pos = filter_prologue_len + 1; - - /* Iterate over all filters and fixup the true branch. */ - TAILQ_FOREACH(filter, &filters, list) { - for (i = 0; i < filter->instructions; i++) { - filter->prog[i].jt = (u_int8_t)jmp_off - pos; - pos++; - } - } - /* Build the entire bpf program now. */ if ((sf = calloc(prog_len, sizeof(*sf))) == NULL) fatal("calloc"); - jmp_off = 0; + off = 0; for (i = 0; i < filter_prologue_len; i++) - sf[jmp_off++] = filter_prologue[i]; + sf[off++] = filter_prologue[i]; TAILQ_FOREACH(filter, &filters, list) { for (i = 0; i < filter->instructions; i++) - sf[jmp_off++] = filter->prog[i]; + sf[off++] = filter->prog[i]; if (!kore_quiet) { kore_log(LOG_INFO, @@ -247,7 +230,7 @@ kore_seccomp_enable(void) } for (i = 0; i < filter_epilogue_len; i++) - sf[jmp_off++] = filter_epilogue[i]; + sf[off++] = filter_epilogue[i]; /* Lock and load it. */ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)