summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac22
-rw-r--r--zhm/Makefile.in3
-rw-r--r--zhm/zhm.c113
3 files changed, 136 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac
index dd0dc5a..cb0d568 100644
--- a/configure.ac
+++ b/configure.ac
@@ -264,7 +264,27 @@ if test "x$with_ares" != "xno"; then
AC_MSG_ERROR(libcares not found)))
fi
AC_SUBST(ARES_LIBS)
-
+
+AC_ARG_WITH(seccomp,
+ [AS_HELP_STRING([--without-seccomp], [Disable seccomp])
+AS_HELP_STRING([--with-seccomp=PREFIX], [Specify location of libseccomp])],
+ [seccomp="$withval"], [seccomp=maybe])
+AS_IF([test "x$seccomp" != "xno"], [
+ AS_IF([test "x$seccomp" != "xyes" && test "x$seccomp" != "xmaybe"], [
+ CPPFLAGS="$CPPFLAGS -I$seccomp/include"
+ LDFLAGS="$LDFLAGS -I$seccomp/lib"
+ ])
+ AC_CHECK_LIB(seccomp, seccomp_init, [
+ SECCOMP_LIBS="-lseccomp"
+ AC_DEFINE(HAVE_SECCOMP, 1,
+ [Define to compile with libseccomp support.])
+ ], [
+ AS_IF([test "x$seccomp" != "xmaybe"],
+ AC_MSG_ERROR([libseccomp not found]))
+ ])
+])
+AC_SUBST(SECCOMP_LIBS)
+
AC_PROG_GCC_TRADITIONAL
AC_FUNC_VPRINTF
AC_FUNC_GETPGRP
diff --git a/zhm/Makefile.in b/zhm/Makefile.in
index 77bf2c0..3284bd3 100644
--- a/zhm/Makefile.in
+++ b/zhm/Makefile.in
@@ -33,13 +33,14 @@ CFLAGS=@CFLAGS@
ALL_CFLAGS=${CFLAGS} -I${top_srcdir}/h -I${BUILDTOP}/h ${CPPFLAGS}
LDFLAGS=@LDFLAGS@
HESIOD_LIBS=@HESIOD_LIBS@
+SECCOMP_LIBS=@SECCOMP_LIBS@
OBJS= timer.o queue.o zhm.o zhm_client.o zhm_server.o
all: zhm zhm.8
zhm: ${OBJS} ${LIBZEPHYR}
- ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBZEPHYR} ${HESIOD_LIBS} -lcom_err
+ ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBZEPHYR} ${HESIOD_LIBS} -lcom_err ${SECCOMP_LIBS}
zhm.8: ${srcdir}/zhm.8.in Makefile
${editman} ${srcdir}/$@.in > $@.tmp
diff --git a/zhm/zhm.c b/zhm/zhm.c
index ec4696b..8386cec 100644
--- a/zhm/zhm.c
+++ b/zhm/zhm.c
@@ -6,6 +6,7 @@
* $Id$
*
* Copyright (c) 1987,1991 by the Massachusetts Institute of Technology.
+ * Copyright 2019 Google LLC.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
@@ -13,6 +14,10 @@
#include "zhm.h"
#include <zephyr_version.h>
+#ifdef HAVE_SECCOMP
+#include <seccomp.h>
+#endif
+
static const char rcsid_hm_c[] = "$Id$";
#ifdef HAVE_HESIOD
@@ -49,6 +54,9 @@ static void init_hm(void);
#ifndef DEBUG
static void detach(void);
#endif
+#ifdef HAVE_SECCOMP
+static int set_seccomp_enforcing(void);
+#endif
static void send_stats(ZNotice_t *, struct sockaddr_in *);
static char *strsave(const char *);
@@ -164,6 +172,14 @@ main(int argc,
DPR2("zephyr server port: %u\n", ntohs(serv_sin.sin_port));
DPR2("zephyr client port: %u\n", ntohs(cli_port));
+#ifdef HAVE_SECCOMP
+ if (set_seccomp_enforcing()) {
+ printf("Unable to enable seccomp; exiting.\n");
+ exit(ZERR_INTERNAL);
+ }
+ DPR("Seccomp enabled.\n");
+#endif
+
/* Main loop */
for (;;) {
/* Wait for incoming packets or queue timeouts. */
@@ -519,6 +535,103 @@ stats_malloc(size_t size)
return p;
}
+#ifdef HAVE_SECCOMP
+static int
+set_seccomp_enforcing(void)
+{
+ scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
+ if (ctx == NULL) {
+ DPR("seccomp_init failed.");
+ return 1;
+ }
+ int r = 0;
+
+#define ALLOW_SYSCALL(syscall) \
+ do { \
+ if ((r = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(syscall), \
+ 0)) < 0) { \
+ Zperr(-r); \
+ goto out; \
+ } \
+ } while (0)
+
+ /* The main ZHM loop fundamentally consists of a select(2), a ZReceivePacket
+ * (a recvfrom(2)), and a ZSendPacket (a sendto(2)). */
+ ALLOW_SYSCALL(select);
+ ALLOW_SYSCALL(recvfrom);
+ ALLOW_SYSCALL(sendto);
+
+ /* If stuff breaks, we need to log with syslog(3). */
+ ALLOW_SYSCALL(openat);
+ ALLOW_SYSCALL(fstat);
+ ALLOW_SYSCALL(read);
+ ALLOW_SYSCALL(lseek);
+ ALLOW_SYSCALL(close);
+ ALLOW_SYSCALL(getpid);
+ ALLOW_SYSCALL(socket);
+ ALLOW_SYSCALL(connect);
+ ALLOW_SYSCALL(sendto);
+
+ /* We might also use com_err, which manipulates the terminal during its
+ * writes. */
+ ALLOW_SYSCALL(write);
+ ALLOW_SYSCALL(ioctl);
+
+ /* Exiting the process is okay. */
+ ALLOW_SYSCALL(exit_group);
+ ALLOW_SYSCALL(exit);
+
+ /* We might exit in response to a signal. */
+ ALLOW_SYSCALL(rt_sigreturn);
+#ifdef __NR_sigreturn
+ ALLOW_SYSCALL(sigreturn);
+#endif
+
+ /* When it's time to exit, we need to remove the PID file. */
+ ALLOW_SYSCALL(unlink);
+
+#ifdef DEBUG
+ /* Logging stuff to stderr (with DPR and DPR2) is okay. write(2) has already
+ * been allowed above, so don't add it again. */
+ /* ALLOW_SYSCALL(write); */
+#endif
+
+#ifdef HAVE_HESIOD
+ /* If a Zephyr server goes offline; we need to query Hesiod for a new
+ * server. Some of these syscalls have already been allowed above, so don't
+ * add them again. */
+ ALLOW_SYSCALL(brk);
+ ALLOW_SYSCALL(getuid);
+ ALLOW_SYSCALL(geteuid);
+ ALLOW_SYSCALL(getgid);
+ ALLOW_SYSCALL(getegid);
+ /* ALLOW_SYSCALL(openat); */
+ /* ALLOW_SYSCALL(fstat); */
+ ALLOW_SYSCALL(mmap);
+ /* ALLOW_SYSCALL(close); */
+ /* ALLOW_SYSCALL(getpid); */
+ ALLOW_SYSCALL(stat);
+ /* ALLOW_SYSCALL(read); */
+ /* ALLOW_SYSCALL(socket); */
+ /* ALLOW_SYSCALL(connect); */
+ ALLOW_SYSCALL(poll);
+ /* ALLOW_SYSCALL(sendto); */
+ /* ALLOW_SYSCALL(recvfrom); */
+#endif
+
+#undef ALLOW_SYSCALL
+
+ if ((r = seccomp_load(ctx)) < 0) {
+ Zperr(-r);
+ goto out;
+ }
+
+out:
+ seccomp_release(ctx);
+ return r;
+}
+#endif
+
static void
send_stats(ZNotice_t *notice,
struct sockaddr_in *sin)