[v9_10] enable libseccomp system call filtering
authorEvan Hunt <each@isc.org>
Thu, 19 Jun 2014 22:48:28 +0000 (15:48 -0700)
committerEvan Hunt <each@isc.org>
Thu, 19 Jun 2014 22:48:28 +0000 (15:48 -0700)
3851. [func] Allow libseccomp based system-call filtering
on Linux; use "configure --enable-seccomp" to
turn it on.  Thanks to Loganaden Velvindron for
the contribution. [RT #35347]

CHANGES
bin/named/include/named/seccomp.h [new file with mode: 0644]
bin/named/main.c
config.h.in
configure
configure.in

diff --git a/CHANGES b/CHANGES
index 58ec0e9..54720c5 100644 (file)
--- a/CHANGES
+++ b/CHANGES
 3853.  [cleanup]       Refactor dns_rdataslab_fromrdataset to separate out
                        the handling of a rdataset with no records. [RT #35968]
 
+3851.  [func]          Allow libseccomp based system-call filtering
+                       on Linux; use "configure --enable-seccomp" to
+                       turn it on.  Thanks to Loganaden Velvindron for
+                       the contribution. [RT #35347]
+
 3850.  [bug]           Disabling forwarding could trigger a REQUIRE assertion.
                        [RT #35979]
 
diff --git a/bin/named/include/named/seccomp.h b/bin/named/include/named/seccomp.h
new file mode 100644 (file)
index 0000000..ebc9471
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef NAMED_SECCOMP_H
+#define NAMED_SECCOMP_H 1
+
+/*! \file */
+
+#ifdef HAVE_LIBSECCOMP
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <seccomp.h>
+#include <isc/platform.h>
+
+/*%
+ * For each architecture, the scmp_syscalls and
+ * scmp_syscall_names arrays MUST be kept in sync.
+ */
+#ifdef __x86_64__
+int scmp_syscalls[] = {
+       SCMP_SYS(access),
+       SCMP_SYS(open),
+       SCMP_SYS(clock_gettime),
+       SCMP_SYS(time),
+       SCMP_SYS(read),
+       SCMP_SYS(write),
+       SCMP_SYS(close),
+       SCMP_SYS(brk),
+       SCMP_SYS(poll),
+       SCMP_SYS(select),
+       SCMP_SYS(madvise),
+       SCMP_SYS(mmap),
+       SCMP_SYS(munmap),
+       SCMP_SYS(exit_group),
+       SCMP_SYS(rt_sigprocmask),
+       SCMP_SYS(rt_sigaction),
+       SCMP_SYS(fsync),
+       SCMP_SYS(rt_sigreturn),
+       SCMP_SYS(setsid),
+       SCMP_SYS(chdir),
+       SCMP_SYS(futex),
+       SCMP_SYS(stat),
+       SCMP_SYS(rt_sigsuspend),
+       SCMP_SYS(fstat),
+       SCMP_SYS(epoll_ctl),
+       SCMP_SYS(gettimeofday),
+       SCMP_SYS(unlink),
+       SCMP_SYS(socket),
+       SCMP_SYS(sendto),
+#ifndef ISC_PLATFORM_USETHREADS
+       SCMP_SYS(bind),
+       SCMP_SYS(accept),
+       SCMP_SYS(connect),
+       SCMP_SYS(listen),
+       SCMP_SYS(fcntl),
+       SCMP_SYS(sendmsg),
+       SCMP_SYS(recvmsg),
+       SCMP_SYS(uname),
+       SCMP_SYS(setrlimit),
+       SCMP_SYS(getrlimit),
+       SCMP_SYS(setsockopt),
+       SCMP_SYS(getsockopt),
+       SCMP_SYS(getsockname),
+       SCMP_SYS(lstat),
+       SCMP_SYS(lseek),
+       SCMP_SYS(getgid),
+       SCMP_SYS(getegid),
+       SCMP_SYS(getuid),
+       SCMP_SYS(geteuid),
+       SCMP_SYS(setresgid),
+       SCMP_SYS(setresuid),
+       SCMP_SYS(setgid),
+       SCMP_SYS(setuid),
+       SCMP_SYS(prctl),
+       SCMP_SYS(epoll_wait),
+       SCMP_SYS(openat),
+       SCMP_SYS(getdents),
+       SCMP_SYS(rename),
+       SCMP_SYS(utimes),
+       SCMP_SYS(dup),
+#endif
+};
+const char *scmp_syscall_names[] = {
+       "access",
+       "open",
+       "clock_gettime",
+       "time",
+       "read",
+       "write",
+       "close",
+       "brk",
+       "poll",
+       "select",
+       "madvise",
+       "mmap",
+       "munmap",
+       "exit_group",
+       "rt_sigprocmask",
+       "rt_sigaction",
+       "fsync",
+       "rt_sigreturn",
+       "setsid",
+       "chdir",
+       "futex",
+       "stat",
+       "rt_sigsuspend",
+       "fstat",
+       "epoll_ctl",
+       "gettimeofday",
+       "unlink",
+       "socket",
+       "sendto",
+#ifndef ISC_PLATFORM_USETHREADS
+       "bind",
+       "accept",
+       "connect",
+       "listen",
+       "fcntl",
+       "sendmsg",
+       "recvmsg",
+       "uname",
+       "setrlimit",
+       "getrlimit",
+       "setsockopt",
+       "getsockopt",
+       "getsockname",
+       "lstat",
+       "lseek",
+       "getgid",
+       "getegid",
+       "getuid",
+       "geteuid",
+       "setresgid",
+       "setresuid",
+       "setgid",
+       "setuid",
+       "prctl",
+       "epoll_wait",
+       "openat",
+       "getdents",
+       "rename",
+       "utimes",
+       "dup",
+#endif
+};
+#endif /* __x86_64__ */
+#ifdef __i386__
+int scmp_syscalls[] = {
+       SCMP_SYS(access),
+       SCMP_SYS(open),
+       SCMP_SYS(clock_gettime),
+       SCMP_SYS(time),
+       SCMP_SYS(read),
+       SCMP_SYS(write),
+       SCMP_SYS(close),
+       SCMP_SYS(brk),
+       SCMP_SYS(poll),
+       SCMP_SYS(_newselect),
+       SCMP_SYS(select),
+       SCMP_SYS(madvise),
+       SCMP_SYS(mmap2),
+       SCMP_SYS(mmap),
+       SCMP_SYS(munmap),
+       SCMP_SYS(exit_group),
+       SCMP_SYS(rt_sigprocmask),
+       SCMP_SYS(sigprocmask),
+       SCMP_SYS(rt_sigaction),
+       SCMP_SYS(socketcall),
+       SCMP_SYS(fsync),
+       SCMP_SYS(sigreturn),
+       SCMP_SYS(setsid),
+       SCMP_SYS(chdir),
+       SCMP_SYS(futex),
+       SCMP_SYS(stat64),
+       SCMP_SYS(rt_sigsuspend),
+       SCMP_SYS(fstat64),
+       SCMP_SYS(epoll_ctl),
+       SCMP_SYS(gettimeofday),
+       SCMP_SYS(unlink),
+#ifndef ISC_PLATFORM_USETHREADS
+       SCMP_SYS(fcntl64),
+#endif
+};
+const char *scmp_syscall_names[] = {
+       "access",
+       "open",
+       "clock_gettime",
+       "time",
+       "read",
+       "write",
+       "close",
+       "brk",
+       "poll",
+       "_newselect",
+       "select",
+       "madvise",
+       "mmap2",
+       "mmap",
+       "munmap",
+       "exit_group",
+       "rt_sigprocmask",
+       "sigprocmask",
+       "rt_sigaction",
+       "socketcall",
+       "fsync",
+       "sigreturn",
+       "setsid",
+       "chdir",
+       "futex",
+       "stat64",
+       "rt_sigsuspend",
+       "fstat64",
+       "epoll_ctl",
+       "gettimeofday",
+       "unlink",
+#ifndef ISC_PLATFORM_USETHREADS
+        "fcntl64",
+#endif
+};
+#endif /* __i386__ */
+#endif /* HAVE_LIBSECCOMP */
+
+#endif /* NAMED_SECCOMP_H */
index b2104ad..8ee9bd8 100644 (file)
@@ -70,6 +70,7 @@
 #include <named/server.h>
 #include <named/lwresd.h>
 #include <named/main.h>
+#include <named/seccomp.h>
 #ifdef HAVE_LIBSCF
 #include <named/ns_smf_globals.h>
 #endif
@@ -770,6 +771,60 @@ dump_symboltable(void) {
        }
 }
 
+#ifdef HAVE_LIBSECCOMP
+static void
+setup_seccomp() {
+       scmp_filter_ctx ctx;
+       unsigned int i;
+       int ret;
+
+       /* Make sure the lists are in sync */
+       INSIST((sizeof(scmp_syscalls) / sizeof(int)) ==
+              (sizeof(scmp_syscall_names) / sizeof(const char *)));
+
+       ctx = seccomp_init(SCMP_ACT_KILL);
+       if (ctx == NULL) {
+               isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                             NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
+                             "libseccomp activation failed");
+               return;
+       }
+
+       for (i = 0 ; i < sizeof(scmp_syscalls)/sizeof(*(scmp_syscalls)); i++) {
+               ret = seccomp_rule_add(ctx, SCMP_ACT_ALLOW,
+                                      scmp_syscalls[i], 0);
+               if (ret < 0)
+                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                                     NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
+                                     "libseccomp rule failed: %s",
+                                     scmp_syscall_names[i]);
+
+               else
+                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                                     NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(9),
+                                     "added libseccomp rule: %s",
+                                     scmp_syscall_names[i]);
+       }
+
+       ret = seccomp_load(ctx);
+       if (ret < 0) {
+               isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                             NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
+                             "libseccomp unable to load filter");
+       } else {
+               isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                             NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+                             "libseccomp sandboxing active");
+       }
+
+       /*
+        * Release filter in ctx. Filters already loaded are not
+        * affected.
+        */
+       seccomp_release(ctx);
+}
+#endif /* HAVE_LIBSECCOMP */
+
 static void
 setup(void) {
        isc_result_t result;
@@ -983,6 +1038,10 @@ setup(void) {
 #endif
 
        ns_server_create(ns_g_mctx, &ns_g_server);
+
+#ifdef HAVE_LIBSECCOMP
+       setup_seccomp();
+#endif /* HAVE_LIBSECCOMP */
 }
 
 static void
index 09d77b4..1561ae5 100644 (file)
@@ -281,6 +281,9 @@ int sigwait(const unsigned int *set, int *sig);
 /* Define to 1 if you have the `scf' library (-lscf). */
 #undef HAVE_LIBSCF
 
+/* Define to use libseccomp system call filtering. */
+#undef HAVE_LIBSECCOMP
+
 /* Define to 1 if you have the `socket' library (-lsocket). */
 #undef HAVE_LIBSOCKET
 
index f094c6e..aebaf35 100755 (executable)
--- a/configure
+++ b/configure
@@ -973,6 +973,7 @@ with_sysroot
 enable_libtool_lock
 enable_libbind
 enable_developer
+enable_seccomp
 with_python
 enable_kqueue
 enable_epoll
@@ -1662,6 +1663,8 @@ Optional Features:
   --disable-libtool-lock  avoid locking (might break parallel builds)
   --enable-libbind       deprecated
   --enable-developer      enable developer build settings
+  --enable-seccomp        enable support for libseccomp sysstem call filtering
+                          [default=no]
   --enable-kqueue         use BSD kqueue when available [default=yes]
   --enable-epoll          use Linux epoll when available [default=auto]
   --enable-devpoll        use /dev/poll when available [default=yes]
@@ -11414,6 +11417,144 @@ yes)
        test "${enable_sit+set}" = set || enable_sit=yes
        ;;
 esac
+
+#libseccomp sandboxing
+# Check whether --enable-seccomp was given.
+if test "${enable_seccomp+set}" = set; then :
+  enableval=$enable_seccomp;
+fi
+
+case "$enable_seccomp" in
+       yes)
+       case $host_os in
+       linux*)
+               ;;
+       *)
+               { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: seccomp is not supported on non-linux platforms; disabling it" >&5
+$as_echo "$as_me: WARNING: seccomp is not supported on non-linux platforms; disabling it" >&2;}
+               enable_seccomp=no
+               ;;
+       esac
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing seccomp_init" >&5
+$as_echo_n "checking for library containing seccomp_init... " >&6; }
+if ${ac_cv_search_seccomp_init+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char seccomp_init ();
+int
+main ()
+{
+return seccomp_init ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' seccomp; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_seccomp_init=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_seccomp_init+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_seccomp_init+:} false; then :
+
+else
+  ac_cv_search_seccomp_init=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_seccomp_init" >&5
+$as_echo "$ac_cv_search_seccomp_init" >&6; }
+ac_res=$ac_cv_search_seccomp_init
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+       if test "$ac_cv_search_seccomp_init" = "-lseccomp" ; then
+               if test "$cross_compiling" = yes; then :
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run test program while cross compiling
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+               #include <stdio.h>
+               #include <stdlib.h>
+               #include <errno.h>
+               #include <sys/prctl.h>
+               #include <linux/seccomp.h>
+
+               int main(void)
+               {
+                       int ret;
+
+                       ret = prctl(PR_GET_SECCOMP, 0, 0, 0, 0);
+                       if (ret < 0) {
+                               switch (errno) {
+                               case ENOSYS:
+                                       return 1;
+                               case EINVAL:
+                                       return 1;
+                               default:
+                                       return 1;
+                               }
+                       }
+                       ret =
+                       prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0);
+                       if (ret < 0) {
+                               switch (errno) {
+                               case EINVAL:
+                                       return 1;
+                               case EFAULT:
+                                       return 0;
+                               default:
+                                       return 1;
+                       }
+               }
+       return 1;
+       }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+$as_echo "#define HAVE_LIBSECCOMP 1" >>confdefs.h
+
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+       fi
+               ;;
+       *)
+               ;;
+esac
+
 #
 # Make very sure that these are the first files processed by
 # config.status, since we use the processed output as the input for
@@ -23918,6 +24059,8 @@ test "$enable_fixed" = "yes" && \
     echo "    Allow 'fixed' rrset-order (--enable-fixed-rrset)"
 test "$enable_filter" = "yes" && \
     echo "    AAAA filtering (--enable-filter-aaaa)"
+test "$enable_seccomp" = yes && \
+    echo "    Use libseccomp system call filtering (--enable-seccomp)"
 test "$want_backtrace" = "yes" && \
     echo "    Print backtrace on crash (--enable-backtrace)"
 test "$want_symtable" = "minimal" && \
@@ -23971,6 +24114,8 @@ test "X$CRYPTO" = "X" -o "$OPENSSL_GOST" = "yes" -o "$PKCS11_GOST" = "yes" || \
 test "X$CRYPTO" = "X" -o "$OPENSSL_ECDSA" = "yes" -o "$PKCS11_ECDSA" = "yes" || \
     echo "    ECDSA algorithm support (--with-ecdsa)"
 
+test "$enable_seccomp" = yes || \
+    echo "    Use libseccomp system call filtering (--enable-seccomp)"
 test "$want_backtrace" = "yes" || \
     echo "    Print backtrace on crash (--enable-backtrace)"
 test "$use_libtool" = "yes" || echo "    Use GNU libtool (--with-libtool)"
index fb95d11..fbd3395 100644 (file)
@@ -89,6 +89,69 @@ yes)
        test "${enable_sit+set}" = set || enable_sit=yes
        ;;
 esac
+
+#libseccomp sandboxing
+AC_ARG_ENABLE(seccomp,
+       AS_HELP_STRING([--enable-seccomp],[enable support for libseccomp sysstem call filtering [default=no]]))
+case "$enable_seccomp" in
+       yes)
+       case $host_os in
+       linux*)
+               ;;
+       *)
+               AC_MSG_WARN([seccomp is not supported on non-linux platforms; disabling it])
+               enable_seccomp=no
+               ;;
+       esac
+       AC_SEARCH_LIBS(seccomp_init, [seccomp])
+       if test "$ac_cv_search_seccomp_init" = "-lseccomp" ; then
+               AC_TRY_RUN([
+               #include <stdio.h>
+               #include <stdlib.h>
+               #include <errno.h>
+               #include <sys/prctl.h>
+               #include <linux/seccomp.h>
+
+               int main(void)
+               {
+                       int ret;
+
+                       ret = prctl(PR_GET_SECCOMP, 0, 0, 0, 0);
+                       if (ret < 0) {
+                               switch (errno) {
+                               case ENOSYS:
+                                       return 1;
+                               case EINVAL:
+                                       return 1;
+                               default:
+                                       return 1;
+                               }
+                       }
+                       ret = 
+                       prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0);
+                       if (ret < 0) {
+                               switch (errno) {
+                               case EINVAL:
+                                       return 1;
+                               case EFAULT:
+                                       return 0;
+                               default:
+                                       return 1;
+                       }
+               }
+       return 1;
+       }
+       ]
+       , AC_DEFINE([HAVE_LIBSECCOMP], 1, 
+       [Define to use libseccomp system call filtering.])   
+       , []
+       )
+       fi
+               ;;
+       *)
+               ;;
+esac
+
 #
 # Make very sure that these are the first files processed by
 # config.status, since we use the processed output as the input for
@@ -4562,6 +4625,8 @@ test "$enable_fixed" = "yes" && \
     echo "    Allow 'fixed' rrset-order (--enable-fixed-rrset)"
 test "$enable_filter" = "yes" && \
     echo "    AAAA filtering (--enable-filter-aaaa)"
+test "$enable_seccomp" = yes && \
+    echo "    Use libseccomp system call filtering (--enable-seccomp)"
 test "$want_backtrace" = "yes" && \
     echo "    Print backtrace on crash (--enable-backtrace)"
 test "$want_symtable" = "minimal" && \
@@ -4615,6 +4680,8 @@ test "X$CRYPTO" = "X" -o "$OPENSSL_GOST" = "yes" -o "$PKCS11_GOST" = "yes" || \
 test "X$CRYPTO" = "X" -o "$OPENSSL_ECDSA" = "yes" -o "$PKCS11_ECDSA" = "yes" || \
     echo "    ECDSA algorithm support (--with-ecdsa)"
 
+test "$enable_seccomp" = yes || \
+    echo "    Use libseccomp system call filtering (--enable-seccomp)"
 test "$want_backtrace" = "yes" || \
     echo "    Print backtrace on crash (--enable-backtrace)"
 test "$use_libtool" = "yes" || echo "    Use GNU libtool (--with-libtool)"