From f4f9d02afd569fefcc754074e22d3a69231aea0c Mon Sep 17 00:00:00 2001
From: "Nicholas J. Kain" <nicholas@kain.us>
Date: Fri, 20 Jul 2012 07:05:56 -0400
Subject: [PATCH] Enforce seccomp syscall restrictions when kernel support
 exists.

---
 ifchd/ifchd.c        | 54 +++++++++++++++++++++++++++--
 ncmlib/seccomp-bpf.h | 81 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 132 insertions(+), 3 deletions(-)
 create mode 100644 ncmlib/seccomp-bpf.h

diff --git a/ifchd/ifchd.c b/ifchd/ifchd.c
index 1a70eba..e37b287 100644
--- a/ifchd/ifchd.c
+++ b/ifchd/ifchd.c
@@ -60,6 +60,7 @@
 #include "cap.h"
 #include "io.h"
 #include "linux.h"
+#include "seccomp-bpf.h"
 
 enum states {
     STATE_NOTHING,
@@ -150,6 +151,49 @@ static void epoll_del(int fd)
         suicide("epoll_del failed %s", strerror(errno));
 }
 
+static int enforce_seccomp(void)
+{
+    struct sock_filter filter[] = {
+        VALIDATE_ARCHITECTURE,
+        EXAMINE_SYSCALL,
+        ALLOW_SYSCALL(read),
+        ALLOW_SYSCALL(write),
+        ALLOW_SYSCALL(sendto), // used for glibc syslog routines
+        ALLOW_SYSCALL(epoll_wait),
+        ALLOW_SYSCALL(epoll_ctl),
+        ALLOW_SYSCALL(close),
+        ALLOW_SYSCALL(socket),
+        ALLOW_SYSCALL(getsockopt),
+        ALLOW_SYSCALL(accept),
+        ALLOW_SYSCALL(listen),
+        ALLOW_SYSCALL(ioctl),
+        ALLOW_SYSCALL(fsync),
+        ALLOW_SYSCALL(lseek),
+        ALLOW_SYSCALL(truncate),
+        ALLOW_SYSCALL(fcntl),
+        ALLOW_SYSCALL(unlink),
+        ALLOW_SYSCALL(bind),
+        ALLOW_SYSCALL(chmod),
+
+        ALLOW_SYSCALL(rt_sigreturn),
+#ifdef __NR_sigreturn
+        ALLOW_SYSCALL(sigreturn),
+#endif
+        ALLOW_SYSCALL(exit_group),
+        ALLOW_SYSCALL(exit),
+        KILL_PROCESS,
+    };
+    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))
+        return -1;
+    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog))
+        return -1;
+    return 0;
+}
+
 /* Abstracts away the details of accept()ing a socket connection. */
 /* Writes out each element in a strlist as an argument to a keyword in
  * a file. */
@@ -709,9 +753,6 @@ static void dispatch_work(void)
 
     lsock = get_listen();
 
-    epollfd = epoll_create1(0);
-    if (epollfd == -1)
-        suicide("epoll_create1 failed");
     epoll_add(lsock);
     epoll_add(signalFd);
 
@@ -951,6 +992,13 @@ int main(int argc, char** argv) {
     memset(resolv_conf_d, '\0', sizeof(resolv_conf_d));
     memset(pidfile, '\0', sizeof(pidfile));
 
+    epollfd = epoll_create1(0);
+    if (epollfd == -1)
+        suicide("epoll_create1 failed");
+
+    if (enforce_seccomp())
+        log_line("seccomp filter cannot be installed");
+
     dispatch_work();
 
     /* Explicitly freed so memory debugger output has less static. */
diff --git a/ncmlib/seccomp-bpf.h b/ncmlib/seccomp-bpf.h
new file mode 100644
index 0000000..b123787
--- /dev/null
+++ b/ncmlib/seccomp-bpf.h
@@ -0,0 +1,81 @@
+/*
+ * seccomp example for x86 (32-bit and 64-bit) with BPF macros
+ *
+ * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
+ * Authors:
+ *  Will Drewry <wad@chromium.org>
+ *  Kees Cook <keescook@chromium.org>
+ *
+ * The code may be used by anyone for any purpose, and can serve as a
+ * starting point for developing applications using mode 2 seccomp.
+ */
+#ifndef _SECCOMP_BPF_H_
+#define _SECCOMP_BPF_H_
+
+#define _GNU_SOURCE 1
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/prctl.h>
+#ifndef PR_SET_NO_NEW_PRIVS
+# define PR_SET_NO_NEW_PRIVS 38
+#endif
+
+#include <linux/unistd.h>
+#include <linux/audit.h>
+#include <linux/filter.h>
+#ifdef HAVE_LINUX_SECCOMP_H
+# include <linux/seccomp.h>
+#endif
+#ifndef SECCOMP_MODE_FILTER
+# define SECCOMP_MODE_FILTER	2 /* uses user-supplied filter. */
+# define SECCOMP_RET_KILL	0x00000000U /* kill the task immediately */
+# define SECCOMP_RET_TRAP	0x00030000U /* disallow and force a SIGSYS */
+# define SECCOMP_RET_ALLOW	0x7fff0000U /* allow */
+struct seccomp_data {
+    int nr;
+    __u32 arch;
+    __u64 instruction_pointer;
+    __u64 args[6];
+};
+#endif
+#ifndef SYS_SECCOMP
+# define SYS_SECCOMP 1
+#endif
+
+#define syscall_nr (offsetof(struct seccomp_data, nr))
+#define arch_nr (offsetof(struct seccomp_data, arch))
+
+#if defined(__i386__)
+# define REG_SYSCALL	REG_EAX
+# define ARCH_NR	AUDIT_ARCH_I386
+#elif defined(__x86_64__)
+# define REG_SYSCALL	REG_RAX
+# define ARCH_NR	AUDIT_ARCH_X86_64
+#else
+# warning "Platform does not support seccomp filter yet"
+# define REG_SYSCALL	0
+# define ARCH_NR	0
+#endif
+
+#define VALIDATE_ARCHITECTURE \
+	BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr), \
+	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \
+	BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
+
+#define EXAMINE_SYSCALL \
+	BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr)
+
+#define ALLOW_SYSCALL(name) \
+	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##name, 0, 1), \
+	BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
+
+#define KILL_PROCESS \
+	BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
+
+#endif /* _SECCOMP_BPF_H_ */