From: Roy Marples Date: Thu, 15 Oct 2020 16:59:33 +0000 (+0100) Subject: privsep: Allow more syscalls through SECCOMP and add a debugger X-Git-Tag: v9.3.2~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2a5ca0e317b4a1044c4774f8508a279ea1711933;p=thirdparty%2Fdhcpcd.git privsep: Allow more syscalls through SECCOMP and add a debugger This fixes PowerPC at least. The debugger should not be enabled by default as the attacker could keep the processes running. However, it is need to work out which syscall is failing due to the way SECCOMP works. --- diff --git a/src/privsep-linux.c b/src/privsep-linux.c index 5d35ae2c..01f4975c 100644 --- a/src/privsep-linux.c +++ b/src/privsep-linux.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,14 @@ #include "logerr.h" #include "privsep.h" +/* + * Set this to debug SECCOMP. + * Then run dhcpcd with strace -f and strace will even translate + * the failing syscall into the __NR_name define we need to use below. + * DO NOT ENABLE THIS FOR PRODUCTION BUILDS! + */ +//#define SECCOMP_FILTER_DEBUG + static ssize_t ps_root_dosendnetlink(int protocol, struct msghdr *msg) { @@ -125,7 +134,11 @@ ps_root_sendnetlink(struct dhcpcd_ctx *ctx, int protocol, struct msghdr *msg) BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \ offsetof(struct seccomp_data, nr)) +#ifdef SECCOMP_FILTER_DEBUG +#define SECCOMP_FILTER_FAIL SECCOMP_RET_TRAP +#else #define SECCOMP_FILTER_FAIL SECCOMP_RET_KILL +#endif /* I personally find this quite nutty. * Why can a system header not define a default for this? */ @@ -247,6 +260,9 @@ static struct sock_filter ps_seccomp_filter[] = { #ifdef __NR_munmap SECCOMP_ALLOW(__NR_munmap), #endif +#ifdef __NR_nanosleep + SECCOMP_ALLOW(__NR_nanosleep), /* XXX should use ppoll instead */ +#endif #ifdef __NR_ppoll SECCOMP_ALLOW(__NR_ppoll), #endif @@ -259,6 +275,9 @@ static struct sock_filter ps_seccomp_filter[] = { #ifdef __NR_readv SECCOMP_ALLOW(__NR_readv), #endif +#ifdef __NR_recv + SECCOMP_ALLOW(__NR_recv), +#endif #ifdef __NR_recvfrom SECCOMP_ALLOW(__NR_recvfrom), #endif @@ -268,6 +287,9 @@ static struct sock_filter ps_seccomp_filter[] = { #ifdef __NR_rt_sigreturn SECCOMP_ALLOW(__NR_rt_sigreturn), #endif +#ifdef __NR_send + SECCOMP_ALLOW(__NR_send), +#endif #ifdef __NR_sendmsg SECCOMP_ALLOW(__NR_sendmsg), #endif @@ -277,9 +299,15 @@ static struct sock_filter ps_seccomp_filter[] = { #ifdef __NR_shutdown SECCOMP_ALLOW(__NR_shutdown), #endif +#ifdef __NR_time + SECCOMP_ALLOW(__NR_time), +#endif #ifdef __NR_wait4 SECCOMP_ALLOW(__NR_wait4), #endif +#ifdef __NR_waitpid + SECCOMP_ALLOW(__NR_waitpid), +#endif #ifdef __NR_write SECCOMP_ALLOW(__NR_write), #endif @@ -299,10 +327,44 @@ static struct sock_fprog ps_seccomp_prog = { .filter = ps_seccomp_filter, }; +#ifdef SECCOMP_FILTER_DEBUG +static void +ps_seccomp_violation(__unused int signum, siginfo_t *si, __unused void *context) +{ + + logerrx("%s: unexpected syscall %d (arch=0x%x)", + __func__, si->si_syscall, si->si_arch); + _exit(EXIT_FAILURE); +} + +static int +ps_seccomp_debug(void) +{ + struct sigaction sa = { + .sa_flags = SA_SIGINFO, + .sa_sigaction = &ps_seccomp_violation, + }; + sigset_t mask; + + /* Install a signal handler to catch any issues with our filter. */ + sigemptyset(&mask); + sigaddset(&mask, SIGSYS); + if (sigaction(SIGSYS, &sa, NULL) == -1 || + sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) + return -1; + + return 0; +} +#endif + int ps_seccomp_enter(void) { +#ifdef SECCOMP_FILTER_DEBUG + ps_seccomp_debug(); +#endif + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1 || prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &ps_seccomp_prog) == -1) {