From: Roy Marples Date: Sat, 19 Sep 2020 19:53:23 +0000 (+0100) Subject: privsep: Add the SECCOMP BPF sandbox for Linux X-Git-Tag: v9.3.0~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a926ee6d8f4eb2f04e01d72664893e3cb95fceca;p=thirdparty%2Fdhcpcd.git privsep: Add the SECCOMP BPF sandbox for Linux Now we have capsicum, pledge and the POSIX resource limited sandboxes this was quite easy really. --- diff --git a/src/privsep-linux.c b/src/privsep-linux.c index 887d7f3f..20579769 100644 --- a/src/privsep-linux.c +++ b/src/privsep-linux.c @@ -27,13 +27,22 @@ */ #include +#include +#include + +#include +#include +#include +#include #include #include +#include #include #include #include +#include "common.h" #include "if.h" #include "logerr.h" #include "privsep.h" @@ -87,3 +96,169 @@ ps_root_sendnetlink(struct dhcpcd_ctx *ctx, int protocol, struct msghdr *msg) return -1; return ps_root_readerror(ctx, NULL, 0); } + +#if (BYTE_ORDER == LITTLE_ENDIAN) +# define SECCOMP_ARG_LO 0 +# define SECCOMP_ARG_HI sizeof(uint32_t) +#elif (BYTE_ORDER == BIG_ENDIAN) +# define SECCOMP_ARG_LO sizeof(uint32_t) +# define SECCOMP_ARG_HI 0 +#else +# error "Uknown endian" +#endif + +#define SECCOMP_ALLOW(_nr) \ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (_nr), 0, 1), \ + BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) + +#define SECCOMP_ALLOW_ARG(_nr, _arg, _val) \ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (_nr), 0, 6), \ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \ + offsetof(struct seccomp_data, args[(_arg)]) + SECCOMP_ARG_LO), \ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, \ + ((_val) & 0xffffffff), 0, 3), \ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \ + offsetof(struct seccomp_data, args[(_arg)]) + SECCOMP_ARG_HI), \ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, \ + (((uint32_t)((uint64_t)(_val) >> 32)) & 0xffffffff), 0, 1), \ + BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW), \ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \ + offsetof(struct seccomp_data, nr)) + +#define SECCOMP_FILTER_FAIL SECCOMP_RET_KILL + +#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__) +# ifndef EM_ARM +# define EM_ARM 40 +# endif +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM +#elif defined(__aarch64__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_AARCH64 +#elif defined(__mips__) +# if defined(__MIPSEL__) +# if defined(__LP64__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPSEL64 +# else +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPSEL +# endif +# elif defined(__LP64__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPS64 +# else +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPS +# endif +#elif defined(__powerpc64__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PPC64 +#elif defined(__powerpc__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PPC +#elif defined(__s390x__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_S390X +#elif defined(__s390__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_S390 +#elif defined(__sparc__) +# if defined(__arch64__) +# define AUDIT_ARCH_SPARC64 +# else +# define AUDIT_ARCH_SPARC +# endif +#else +# error "Platform does not support seccomp filter yet" +#endif + +static struct sock_filter ps_seccomp_filter[] = { + /* Check syscall arch */ + 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), + /* Allow syscalls */ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, + offsetof(struct seccomp_data, nr)), +#ifdef __NR_brk + SECCOMP_ALLOW(__NR_brk), +#endif +#ifdef __NR_clock_gettime + SECCOMP_ALLOW(__NR_clock_gettime), +#endif +#if defined(__x86_64__) && defined(__ILP32__) && defined(__X32_SYSCALL_BIT) + SECCOMP_ALLOW(__NR_clock_gettime & ~__X32_SYSCALL_BIT), +#endif +#ifdef __NR_clock_gettime64 + SECCOMP_ALLOW(__NR_clock_gettime64), +#endif +#ifdef __NR_close + SECCOMP_ALLOW(__NR_close), +#endif +#ifdef __NR_getpid + SECCOMP_ALLOW(__NR_getpid), +#endif +#ifdef __NR_ioctl + SECCOMP_ALLOW_ARG(__NR_ioctl, 1, SIOCGIFFLAGS), + SECCOMP_ALLOW_ARG(__NR_ioctl, 1, SIOCGIFHWADDR), + SECCOMP_ALLOW_ARG(__NR_ioctl, 1, SIOCGIFINDEX), + SECCOMP_ALLOW_ARG(__NR_ioctl, 1, SIOCGIFMTU), + SECCOMP_ALLOW_ARG(__NR_ioctl, 1, SIOCGIFVLAN), + /* SECCOMP BPF is newer than nl80211 so we don't need SIOCGIWESSID + * which lives in the impossible to include linux/wireless.h header */ +#endif +#ifdef __NR_ppoll + SECCOMP_ALLOW(__NR_ppoll), +#endif +#ifdef __NR_ppoll_time64 + SECCOMP_ALLOW(__NR_ppoll_time64), +#endif +#ifdef __NR_read + SECCOMP_ALLOW(__NR_read), +#endif +#ifdef __NR_readv + SECCOMP_ALLOW(__NR_readv), +#endif +#ifdef __NR_recvfrom + SECCOMP_ALLOW(__NR_recvfrom), +#endif +#ifdef __NR_recvmsg + SECCOMP_ALLOW(__NR_recvmsg), +#endif +#ifdef __NR_rt_sigreturn + SECCOMP_ALLOW(__NR_rt_sigreturn), +#endif +#ifdef __NR_sendmsg + SECCOMP_ALLOW(__NR_sendmsg), +#endif +#ifdef __NR_sendto + SECCOMP_ALLOW(__NR_sendto), +#endif +#ifdef __NR_shutdown + SECCOMP_ALLOW(__NR_shutdown), +#endif +#ifdef __NR_write + SECCOMP_ALLOW(__NR_write), +#endif +#ifdef __NR_writev + SECCOMP_ALLOW(__NR_writev), +#endif +#ifdef __NR_uname + SECCOMP_ALLOW(__NR_uname), +#endif + /* Deny everything else */ + BPF_STMT(BPF_RET + BPF_K, SECCOMP_FILTER_FAIL), +}; + +static struct sock_fprog ps_seccomp_prog = { + .len = (unsigned short)__arraycount(ps_seccomp_filter), + .filter = ps_seccomp_filter, +}; + +int +ps_seccomp_enter(void) +{ + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) + return errno == EINVAL ? 0 : -1; + if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &ps_seccomp_prog) == -1) + return errno == EINVAL ? 0 : -1; + return 0; +} diff --git a/src/privsep.c b/src/privsep.c index 1841fb36..2cc61a88 100644 --- a/src/privsep.c +++ b/src/privsep.c @@ -507,6 +507,12 @@ ps_entersandbox(const char *_pledge) #else UNUSED(_pledge); #endif +#ifdef HAVE_SECCOMP + if (ps_seccomp_enter() == -1) { + logerr("%s: ps_seccomp_enter", __func__); + return -1; + } +#endif return 0; } diff --git a/src/privsep.h b/src/privsep.h index 8d73af0e..d8c3dc8a 100644 --- a/src/privsep.h +++ b/src/privsep.h @@ -96,6 +96,13 @@ #define PRIVSEP_RIGHTS #endif +#ifdef __linux__ +# include +# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) +# define HAVE_SECCOMP +# endif +#endif + #include "config.h" #include "arp.h" #include "dhcp.h" @@ -194,6 +201,10 @@ int ps_rights_limit_fd(int); int ps_rights_limit_fdpair(int []); #endif +#ifdef HAVE_SECCOMP +int ps_seccomp_enter(void); +#endif + pid_t ps_dostart(struct dhcpcd_ctx * ctx, pid_t *priv_pid, int *priv_fd, void (*recv_msg)(void *), void (*recv_unpriv_msg),