commit:     d6fcdb53ed7341f25db859516fa0383fca95eb1d
Author:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
AuthorDate: Tue Aug 18 14:50:45 2015 +0000
Commit:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
CommitDate: Thu Aug 20 14:38:40 2015 +0000
URL:        https://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=d6fcdb53

security: use seccomp to lock ourselves down

This has a minor speed hit (a few milliseconds), but otherwise provides
a decent balance.

 Makefile     |   7 +++
 configure.ac |   7 +++
 security.c   | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 161 insertions(+)

diff --git a/Makefile b/Makefile
index ac5e9cc..3abfee7 100644
--- a/Makefile
+++ b/Makefile
@@ -49,6 +49,13 @@ CPPFLAGS-pspax.c += $(LIBCAPS_CFLAGS) -DWANT_SYSCAP
 LIBS-pspax       += $(LIBCAPS_LIBS)
 endif
 
+ifeq ($(USE_SECCOMP),yes)
+LIBSECCOMP_CFLAGS := $(shell $(PKG_CONFIG) --cflags libseccomp)
+LIBSECCOMP_LIBS   := $(shell $(PKG_CONFIG) --libs libseccomp)
+override CPPFLAGS += $(LIBSECCOMP_CFLAGS) -DWANT_SECCOMP
+LIBS              += $(LIBSECCOMP_LIBS)
+endif
+
 ifdef PV
 override CPPFLAGS  += -DVERSION=\"$(PV)\"
 else

diff --git a/configure.ac b/configure.ac
index c3591ff..327d9b8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -26,6 +26,13 @@ AS_IF([test "x$with_caps" = "xyes"], [
 AC_ARG_WITH([python], [AS_HELP_STRING([--with-python], [use lddtree.py])])
 AM_CONDITIONAL([USE_PYTHON], [test "x$with_python" = "xyes"])
 
+AC_ARG_WITH([seccomp], [AS_HELP_STRING([--with-seccomp], [build with 
seccomp])])
+AS_IF([test "x$with_seccomp" = "xyes"], [
+       PKG_CHECK_MODULES(LIBSECCOMP, libseccomp)
+       CPPFLAGS="$CPPFLAGS $LIBSECCOMP_CFLAGS -DWANT_SECCOMP"
+       LIBS="$LIBS $LIBSECCOMP_LIBS"
+])
+
 AX_CFLAGS_WARN_ALL
 AC_DEFUN([PT_CHECK_CFLAG],[AX_CHECK_COMPILER_FLAGS([$1],[CFLAGS="$CFLAGS 
$1"])])
 m4_foreach_w([flag], [

diff --git a/security.c b/security.c
index 3012212..333524a 100644
--- a/security.c
+++ b/security.c
@@ -16,6 +16,151 @@
 # define ALLOW_PIDNS 1
 #endif
 
+#ifdef WANT_SECCOMP
+# include <seccomp.h>
+
+/* Simple helper to add all of the syscalls in an array. */
+static int pax_seccomp_rules_add(scmp_filter_ctx ctx, int syscalls[], size_t 
num)
+{
+       static uint8_t prio;
+       size_t i;
+       for (i = 0; i < num; ++i) {
+               if (syscalls[i] < 0)
+                       continue;
+
+               if (seccomp_syscall_priority(ctx, syscalls[i], prio++) < 0) {
+                       warnp("seccomp_syscall_priority failed");
+                       return -1;
+               }
+               if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls[i], 0) < 0) {
+                       warnp("seccomp_rule_add failed");
+                       return -1;
+               }
+       }
+       return 0;
+}
+#define pax_seccomp_rules_add(ctx, syscalls) pax_seccomp_rules_add(ctx, 
syscalls, ARRAY_SIZE(syscalls))
+
+static void pax_seccomp_init(bool allow_forking)
+{
+       /* Order determines priority (first == lowest prio).  */
+       int base_syscalls[] = {
+               /* We write the most w/scanelf.  */
+               SCMP_SYS(write),
+
+               /* Then the stat family of functions.  */
+               SCMP_SYS(newfstatat),
+#ifdef __NR_fstat
+               SCMP_SYS(fstat),
+#endif
+               SCMP_SYS(fstat64),
+#ifdef __NR_fstatat
+               SCMP_SYS(fstatat),
+#endif
+               SCMP_SYS(fstatat64),
+               SCMP_SYS(lstat),
+               SCMP_SYS(lstat64),
+               SCMP_SYS(stat),
+               SCMP_SYS(stat64),
+
+               /* Then the fd close func.  */
+               SCMP_SYS(close),
+
+               /* Then fd open family of functions.  */
+               SCMP_SYS(open),
+#ifdef __NR_openat
+               SCMP_SYS(openat),
+#endif
+
+               /* Then the memory mapping functions.  */
+               SCMP_SYS(mmap),
+               SCMP_SYS(mmap2),
+               SCMP_SYS(munmap),
+
+               /* Then the directory reading functions.  */
+               SCMP_SYS(getdents),
+#ifdef __NR_getdents64
+               SCMP_SYS(getdents64),
+#endif
+
+               /* Then the file reading functions.  */
+#ifdef __NR_pread
+               SCMP_SYS(pread),
+#endif
+#ifdef __NR_pread64
+               SCMP_SYS(pread64),
+#endif
+               SCMP_SYS(read),
+
+               /* Then the fd manipulation functions.  */
+#ifdef __NR_fcntl
+               SCMP_SYS(fcntl),
+#endif
+               SCMP_SYS(fcntl64),
+
+               /* After this point, just sort the list alphabetically.  */
+               SCMP_SYS(access),
+               SCMP_SYS(brk),
+               SCMP_SYS(capget),
+               SCMP_SYS(chdir),
+               SCMP_SYS(exit),
+               SCMP_SYS(exit_group),
+               SCMP_SYS(faccessat),
+               SCMP_SYS(fchdir),
+               SCMP_SYS(getpid),
+               SCMP_SYS(gettid),
+               SCMP_SYS(ioctl),
+#ifdef __NR_lseek
+               SCMP_SYS(lseek),
+#endif
+               SCMP_SYS(_llseek),
+               SCMP_SYS(mprotect),
+
+               /* Syscalls listed because of sandbox.  */
+               SCMP_SYS(readlink),
+       };
+       int fork_syscalls[] = {
+               SCMP_SYS(clone),
+               SCMP_SYS(execve),
+               SCMP_SYS(fork),
+               SCMP_SYS(rt_sigaction),
+               SCMP_SYS(rt_sigprocmask),
+               SCMP_SYS(unshare),
+               SCMP_SYS(vfork),
+               SCMP_SYS(wait4),
+               SCMP_SYS(waitid),
+               SCMP_SYS(waitpid),
+       };
+       scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_TRAP);
+       if (!ctx) {
+               warnp("seccomp_init failed");
+               return;
+       }
+
+       if (pax_seccomp_rules_add(ctx, base_syscalls) < 0)
+               goto done;
+
+       if (allow_forking)
+               if (pax_seccomp_rules_add(ctx, fork_syscalls) < 0)
+                       goto done;
+
+       /* We already called prctl. */
+       seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0);
+
+#ifndef __SANITIZE_ADDRESS__
+       /* ASAN does some weird stuff. */
+       if (seccomp_load(ctx) < 0)
+               warnp("seccomp_load failed");
+#endif
+
+ done:
+       seccomp_release(ctx);
+}
+
+#else
+# define pax_seccomp_init(allow_forking)
+#endif
+
 static int ns_unshare(int flags)
 {
        int flag, ret = 0;
@@ -93,6 +238,8 @@ void security_init(bool allow_forking)
                        if (vfork() == 0)
                                _exit(0);
        }
+
+       pax_seccomp_init(allow_forking);
 }
 
 #endif

Reply via email to