From 5917d031376d8f5d8add26ea4c871dc3ce149be4 Mon Sep 17 00:00:00 2001 From: Michael Santos Date: Thu, 2 Feb 2017 10:13:33 -0500 Subject: [PATCH] sandbox: Linux seccomp syscall filter Add a BPF seccomp syscall filter on Linux. Not enabled by default. To compile: XMPPIPE_SANDBOX=XMPPIPE_SANDBOX_SECCOMP make The sandbox is derived from OpenSSH's seccomp sandbox by Will Drewry and Kees Cook's tutorial on seccomp: http://outflux.net/teach-seccomp/ --- src/xmppipe_sandbox_seccomp.c | 169 ++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 src/xmppipe_sandbox_seccomp.c diff --git a/src/xmppipe_sandbox_seccomp.c b/src/xmppipe_sandbox_seccomp.c new file mode 100644 index 0000000..d25af00 --- /dev/null +++ b/src/xmppipe_sandbox_seccomp.c @@ -0,0 +1,169 @@ +/* Copyright (c) 2017, Michael Santos + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef XMPPIPE_SANDBOX_SECCOMP +#include +#include +#include +#include +#include +#include +#include + +#include "xmppipe.h" + +/* macros from openssh-7.2/sandbox-seccomp-filter.c */ + +/* Linux seccomp_filter sandbox */ +#define SECCOMP_FILTER_FAIL SECCOMP_RET_KILL + +/* Use a signal handler to emit violations when debugging */ +#ifdef SANDBOX_SECCOMP_FILTER_DEBUG +# undef SECCOMP_FILTER_FAIL +# define SECCOMP_FILTER_FAIL SECCOMP_RET_TRAP +#endif /* SANDBOX_SECCOMP_FILTER_DEBUG */ + +/* Simple helpers to avoid manual errors (but larger BPF programs). */ +#define SC_DENY(_nr, _errno) \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(_errno)) +#define SC_ALLOW(_nr) \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) +#define SC_ALLOW_ARG(_nr, _arg_nr, _arg_val) \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 4), \ + /* load first syscall argument */ \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ + offsetof(struct seccomp_data, args[(_arg_nr)])), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_arg_val), 0, 1), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), \ + /* reload syscall number; all rules expect it in accumulator */ \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ + offsetof(struct seccomp_data, nr)) + +/* + * http://outflux.net/teach-seccomp/ + * https://github.com/gebi/teach-seccomp + * + */ +#define syscall_nr (offsetof(struct seccomp_data, nr)) +#define arch_nr (offsetof(struct seccomp_data, arch)) + +#if defined(__i386__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_I386 +#elif defined(__x86_64__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_X86_64 +#elif defined(__arm__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM +#elif defined(__aarch64__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_AARCH64 +#else +# warning "seccomp: unsupported platform" +# define SECCOMP_AUDIT_ARCH 0 +#endif + + int +xmppipe_sandbox_init(xmppipe_state_t *state) +{ + struct sock_filter filter[] = { + /* Ensure the syscall arch convention is as expected. */ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, + offsetof(struct seccomp_data, arch)), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_AUDIT_ARCH, 1, 0), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL), + /* Load the syscall number for checking. */ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, + offsetof(struct seccomp_data, nr)), + + /* Syscalls to non-fatally deny */ +#ifdef __NR_open + SC_DENY(open, EACCES), +#endif + + /* Syscalls to allow */ +#ifdef __NR_brk + SC_ALLOW(brk), +#endif +#ifdef __NR_clock_gettime + SC_ALLOW(clock_gettime), +#endif +#ifdef __NR_exit_group + SC_ALLOW(exit_group), +#endif +#ifdef __NR_fcntl + SC_ALLOW(fcntl), +#endif +#ifdef __NR_fcntl64 + SC_ALLOW(fcntl64), +#endif +#ifdef __NR_fstat + SC_ALLOW(fstat), +#endif +#ifdef __NR_fstat64 + SC_ALLOW(fstat64), +#endif + +#ifdef __NR_getppid + SC_ALLOW(getppid), +#endif +#ifdef __NR_gettid + SC_ALLOW(gettid), +#endif +#ifdef __NR_gettimeofday + SC_ALLOW(gettimeofday), +#endif +#ifdef __NR_getuid32 + SC_ALLOW(getuid32), +#endif +#ifdef __NR_ioctl + SC_ALLOW(ioctl), +#endif + +#ifdef __NR_poll + SC_ALLOW(poll), +#endif +#ifdef __NR_read + SC_ALLOW(read), +#endif +#ifdef __NR__newselect + SC_ALLOW(_newselect), +#endif +#ifdef __NR_select + SC_ALLOW(select), +#endif +#ifdef __NR_stat64 + SC_ALLOW(stat64), +#endif +#ifdef __NR_write + SC_ALLOW(write), +#endif + + /* Default deny */ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL) + }; + + struct sock_fprog prog = { + .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), + .filter = filter, + }; + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) + return -1; + + if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) + return -1; + + return 0; +} +#endif