]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
privsep: Add the SECCOMP BPF sandbox for Linux
authorRoy Marples <roy@marples.name>
Sat, 19 Sep 2020 19:53:23 +0000 (20:53 +0100)
committerRoy Marples <roy@marples.name>
Sat, 19 Sep 2020 19:53:23 +0000 (20:53 +0100)
Now we have capsicum, pledge and the POSIX resource limited sandboxes
this was quite easy really.

src/privsep-linux.c
src/privsep.c
src/privsep.h

index 887d7f3f504d485047d1fce41709629f9b21b837..20579769b3f1cb966bc1e38ecdab602a88baf14a 100644 (file)
  */
 
 #include <sys/ioctl.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+
+#include <linux/audit.h>
+#include <linux/filter.h>
+#include <linux/seccomp.h>
+#include <linux/sockios.h>
 
 #include <errno.h>
 #include <fcntl.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
+#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;
+}
index 1841fb36b65c79c328bc88825a77bd343f6b243a..2cc61a88633b10e4bdb2a042cd38150d877d9186 100644 (file)
@@ -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;
 }
index 8d73af0e8a2bb5a953537a85d95936225da8b470..d8c3dc8adcbf3cee997b11fe6bfdf9137c83ea0b 100644 (file)
 #define PRIVSEP_RIGHTS
 #endif
 
+#ifdef __linux__
+# include <linux/version.h>
+# 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),