Subject: | isc-dhcpd sandboxing patch |
Date: | Fri, 10 Jan 2014 23:14:07 -0800 |
To: | dhcp-bugs@isc.org |
From: | Loganaden Velvindron <logan@elandsys.com> |
Dear Jeremy and ISC team,
I'm currently running with isc-dhcpd sandboxed on Production Ubuntu servers.
The patch restricts dhcpd to a small number of whitelisted C functions using
seccomp. OpenSSH and systemd ship with a similar sandbox on Linux.
This prevents exploits that use execve() and such.
If there is interest in such a patch, I'm willing to improve it futher
based on the feedback I get from ISC.
diff --git a/dhcp-4.3.0a1/configure.ac b/dhcp-4.3.0a1/configure.ac
index 3b7f12e..b4e87fe 100644
--- a/dhcp-4.3.0a1/configure.ac
+++ b/dhcp-4.3.0a1/configure.ac
@@ -145,6 +145,17 @@ if test "$enable_early_chroot" = "yes" ; then
[Define to any value to chroot() prior to loading config.])
fi
+# LIBSECCOMP is off by default -- needs testing with all the features
+AC_ARG_ENABLE(libseccomp,
+ AS_HELP_STRING([--enable-libseccomp],[enable support for libseccomp sandboxing (default is no)]))
+if test "$enable_libseccomp" = "yes" ; then
+ AC_SEARCH_LIBS(seccomp_init, [seccomp])
+ if test "$ac_cv_search_seccomp_init" = "-lseccomp" ; then
+ AC_DEFINE([LIBSECCOMP], [1],
+ [Define to any value to include libseccomp sandboxing.])
+ fi
+fi
+
AC_ARG_ENABLE(ipv4_pktinfo,
AS_HELP_STRING([--enable-ipv4-pktinfo],[enable use of pktinfo on IPv4 sockets (default is no)]))
diff --git a/dhcp-4.3.0a1/server/dhcpd.c b/dhcp-4.3.0a1/server/dhcpd.c
index ebf00fd..be21f37 100644
--- a/dhcp-4.3.0a1/server/dhcpd.c
+++ b/dhcp-4.3.0a1/server/dhcpd.c
@@ -58,6 +58,12 @@ static const char url [] =
# undef group
#endif /* PARANOIA */
+#if defined (LIBSECCOMP)
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <seccomp.h>
+#endif /* LIBSECCOMP */
+
#ifndef UNIT_TEST
static void usage(void);
#endif
@@ -746,6 +752,79 @@ main(int argc, char **argv) {
}
}
+#if defined (LIBSECCOMP)
+ scmp_filter_ctx ctx;
+ if ((ctx = seccomp_init(SCMP_ACT_KILL)) < 0)
+ log_fatal("%s:libseccomp activation failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpid), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(gettimeofday), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clock_gettime), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+#ifdef __NR_time /* not defined on EABI ARM */
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(time), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+#endif
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(poll), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+#ifdef __NR__newselect
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(_newselect), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+#else
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(select), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+#endif
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(madvise), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+#ifdef __NR_mmap2 /* EABI ARM only has mmap2() */
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+#endif
+#ifdef __NR_mmap
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+#endif
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+#ifdef __NR_rt_sigprocmask
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+#else
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sigprocmask), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+#endif
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketcall), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fsync), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sigreturn), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsid), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chdir), 0) < 0)
+ log_fatal("%s:libseccomp rule failed", __func__);
+
+
+ if (seccomp_load(ctx) < 0)
+ log_fatal("%s:libseccomp unable to load filter", __func__);
+#endif /* LIBSECCOMP */
+
/* If we were requested to log to stdout on the command line,
keep doing so; otherwise, stop. */
if (log_perror == -1)
@@ -789,6 +868,7 @@ main(int argc, char **argv) {
/* Log that we are about to start working */
log_info("Server starting service.");
+
/*
* Receive packets and dispatch them...
* dispatch() will never return.