diff mbox

[PATCHv3,5/5] seccomp: adding debug mode

Message ID 1352749698-1219-5-git-send-email-otubo@linux.vnet.ibm.com
State New
Headers show

Commit Message

Eduardo Otubo Nov. 12, 2012, 7:48 p.m. UTC
This patch is meant for developer debug purposes only.  It adds
support that displays the offending system call number if QEMU
is being killed by seccomp.  The offending system call may need
to be added to the appropriate system call white list in
qemu-seccomp.c to prevent seccomp from killing QEMU.

When the seccomp filter is configured with SCMP_ACT_TRAP, the
kernel sends a SIGSYS every time an illegal syscall is called.
The role of the debug mode is to handle the SIGSYS, determine
the illegal syscall, and print the syscall number to stderr.

v3: New in v3.

Signed-off-by: Eduardo Otubo <otubo@linux.vnet.ibm.com>
Signed-off-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
---
 Makefile.objs        |    3 ++
 configure            |   16 +++++++++
 qemu-seccomp-debug.c |   93 ++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-seccomp-debug.h |   40 ++++++++++++++++++++++
 qemu-seccomp.c       |    4 +--
 qemu-seccomp.h       |   13 +++++++
 qemu-thread-posix.c  |    3 ++
 vl.c                 |   10 ++++++
 8 files changed, 180 insertions(+), 2 deletions(-)
 create mode 100644 qemu-seccomp-debug.c
 create mode 100644 qemu-seccomp-debug.h
diff mbox

Patch

diff --git a/Makefile.objs b/Makefile.objs
index 682b1e6..4ece4d8 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -104,6 +104,9 @@  common-obj-$(CONFIG_SLIRP) += slirp/
 ######################################################################
 # libseccomp
 common-obj-y += qemu-seccomp.o
+ifeq ($(CONFIG_SECCOMP_DEBUG),y)
+common-obj-y += qemu-seccomp-debug.o
+endif
 
 ######################################################################
 # libuser
diff --git a/configure b/configure
index d28f8d5..e2417fe 100755
--- a/configure
+++ b/configure
@@ -222,6 +222,7 @@  want_tools="yes"
 libiscsi=""
 coroutine=""
 seccomp="yes"
+seccomp_debug="no"
 glusterfs=""
 
 # parse CC options first
@@ -867,6 +868,10 @@  for opt do
   ;;
   --disable-seccomp) seccomp="no"
   ;;
+  --enable-seccomp-debug) seccomp_debug="yes"
+  ;;
+  --disable-seccomp-debug) seccomp_debug="no"
+  ;;
   --disable-glusterfs) glusterfs="no"
   ;;
   --enable-glusterfs) glusterfs="yes"
@@ -876,6 +881,10 @@  for opt do
   esac
 done
 
+if test "$seccomp" = "no"; then
+    seccomp_debug="no";
+fi
+
 case "$cpu" in
     sparc)
            LDFLAGS="-m32 $LDFLAGS"
@@ -1115,6 +1124,8 @@  echo "  --disable-guest-agent    disable building of the QEMU Guest Agent"
 echo "  --enable-guest-agent     enable building of the QEMU Guest Agent"
 echo "  --disable-seccomp        disable seccomp support"
 echo "  --enable-seccomp         enables seccomp support"
+echo "  --disable-seccomp-debug  disable seccomp debug support"
+echo "  --enable-seccomp-debug   enables seccomp debug support"
 echo "  --with-coroutine=BACKEND coroutine backend. Supported options:"
 echo "                           gthread, ucontext, sigaltstack, windows"
 echo "  --enable-glusterfs       enable GlusterFS backend"
@@ -3230,6 +3241,7 @@  echo "OpenGL support    $opengl"
 echo "libiscsi support  $libiscsi"
 echo "build guest agent $guest_agent"
 echo "seccomp support   $seccomp"
+echo "seccomp debug     $seccomp_debug"
 echo "coroutine backend $coroutine_backend"
 echo "GlusterFS support $glusterfs"
 
@@ -3534,6 +3546,10 @@  if test "$seccomp" = "yes"; then
   echo "CONFIG_SECCOMP=y" >> $config_host_mak
 fi
 
+if test "$seccomp_debug" = "yes"; then
+  echo "CONFIG_SECCOMP_DEBUG=y" >> $config_host_mak
+fi
+
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
   echo "CONFIG_BSD=y" >> $config_host_mak
diff --git a/qemu-seccomp-debug.c b/qemu-seccomp-debug.c
new file mode 100644
index 0000000..4b64e8c
--- /dev/null
+++ b/qemu-seccomp-debug.c
@@ -0,0 +1,93 @@ 
+/*
+ * QEMU seccomp mode 2 support with libseccomp
+ * Debug system calls helper functions
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Eduardo Otubo    <eotubo@br.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu-seccomp-debug.h"
+#include <asm-generic/unistd.h>
+
+#define safe_warn(data, len) write(STDERR_FILENO, (const void *) data, len)
+
+static int count_digits(int number)
+{
+    int digits = 0;
+    while (number) {
+        number /= 10;
+        digits++;
+    }
+
+    return digits;
+}
+
+static char *sput_i(int integer, char *string)
+{
+    if (integer / 10 != 0) {
+        string = sput_i(integer / 10, string);
+    }
+    *string++ = (char) ('0' + integer % 10);
+    return string;
+}
+
+static void int_to_asc(int integer, char *string)
+{
+    *sput_i(integer, string) = '\n';
+}
+
+static void syscall_debug(int nr, siginfo_t *info, void *void_context)
+{
+    ucontext_t *ctx = (ucontext_t *) (void_context);
+    char errormsg[] = "seccomp: illegal syscall trapped: ";
+    char syscall_char[count_digits(__NR_syscalls) + 1];
+    int syscall_num = 0;
+    int i;
+
+    for (i = 0; i < count_digits(__NR_syscalls) + 1; i++) {
+        syscall_char[i] = ' ';
+    }
+    if (info->si_code != SYS_SECCOMP) {
+        return;
+    }
+    if (!ctx) {
+        return;
+    }
+    syscall_num = ctx->uc_mcontext.gregs[REG_SYSCALL];
+    int_to_asc(syscall_num, syscall_char);
+    if ((safe_warn(errormsg, sizeof(errormsg)-1) < 0) ||
+        (safe_warn(syscall_char, sizeof(syscall_char)) < 0)) {
+        return;
+    }
+    return;
+}
+
+int seccomp_install_syscall_debug(void)
+{
+    struct sigaction act;
+    sigset_t mask;
+
+    memset(&act, 0, sizeof(act));
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGSYS);
+
+    act.sa_sigaction = &syscall_debug;
+    act.sa_flags = SA_SIGINFO;
+    if (sigaction(SIGSYS, &act, NULL) < 0) {
+        perror("seccomp: sigaction returned with errors\n");
+        return -1;
+    }
+    if (pthread_sigmask(SIG_UNBLOCK, &mask, NULL)) {
+        perror("seccomp: pthread_sigmask returned with errors\n");
+        return -1;
+    }
+    return 0;
+}
diff --git a/qemu-seccomp-debug.h b/qemu-seccomp-debug.h
new file mode 100644
index 0000000..c41538e
--- /dev/null
+++ b/qemu-seccomp-debug.h
@@ -0,0 +1,40 @@ 
+/*
+ * QEMU seccomp mode 2 support with libseccomp
+ * Trap system calls helper functions
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Eduardo Otubo    <eotubo@br.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+#ifndef QEMU_SECCOMP_TRAP_H
+#define QEMU_SECCOMP_TRAP_H
+
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#if defined(__i386__)
+#define REG_SYSCALL REG_EAX
+#include <asm/unistd_32.h>
+#elif defined(__x86_64__)
+#define REG_SYSCALL REG_RAX
+#include <asm/unistd_64.h>
+#else
+#error Unsupported platform
+#endif
+
+#ifndef SYS_SECCOMP
+#define SYS_SECCOMP 1
+#endif
+
+int seccomp_install_syscall_debug(void);
+
+#endif
diff --git a/qemu-seccomp.c b/qemu-seccomp.c
index d5a3b0f..d2177f8 100644
--- a/qemu-seccomp.c
+++ b/qemu-seccomp.c
@@ -454,7 +454,7 @@  static int process_list(scmp_filter_ctx *ctx,
     unsigned int i = 0;
 
     for (i = 0; i < list_size; i++) {
-        rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, list[i].num, 0);
+        rc = seccomp_rule_add(ctx, SECCOMP_ALLOW, list[i].num, 0);
         if (rc < 0) {
             return rc;
         }
@@ -474,7 +474,7 @@  int seccomp_install_filter(int state)
 #ifdef CONFIG_SECCOMP
     scmp_filter_ctx ctx = NULL;
 
-    ctx = seccomp_init(SCMP_ACT_KILL);
+    ctx = seccomp_init(SECCOMP_DENY);
     if (ctx == NULL) {
         rc = -1;
         goto seccomp_return;
diff --git a/qemu-seccomp.h b/qemu-seccomp.h
index 029c111..3fd6ad3 100644
--- a/qemu-seccomp.h
+++ b/qemu-seccomp.h
@@ -15,10 +15,23 @@ 
 #ifndef QEMU_SECCOMP_H
 #define QEMU_SECCOMP_H
 
+#include <stdint.h>
 #ifdef CONFIG_SECCOMP
 #include <seccomp.h>
 #endif
 
+#define SECCOMP_ALLOW SCMP_ACT_ALLOW
+
+#ifdef CONFIG_SECCOMP
+#ifdef CONFIG_SECCOMP_DEBUG
+#define SECCOMP_DENY SCMP_ACT_TRAP
+#else
+#define SECCOMP_DENY SCMP_ACT_KILL
+#endif
+#else
+#define SECCOMP_DENY 0
+#endif
+
 enum seccomp_states {
     SECCOMP_OFF,
     SECCOMP_ON,
diff --git a/qemu-thread-posix.c b/qemu-thread-posix.c
index 4ef9c7b..3c67732 100644
--- a/qemu-thread-posix.c
+++ b/qemu-thread-posix.c
@@ -288,6 +288,9 @@  void qemu_thread_create(QemuThread *thread,
 
     /* Leave signal handling to the iothread.  */
     sigfillset(&set);
+#ifdef CONFIG_SECCOMP_DEBUG
+    sigdelset(&set, SIGSYS);
+#endif
     pthread_sigmask(SIG_SETMASK, &set, &oldset);
     err = pthread_create(&thread->thread, &attr, start_routine, arg);
     if (err)
diff --git a/vl.c b/vl.c
index 80b1fff..8f970e4 100644
--- a/vl.c
+++ b/vl.c
@@ -65,6 +65,9 @@ 
 #endif
 
 #include "qemu-seccomp.h"
+#ifdef CONFIG_SECCOMP_DEBUG
+#include "qemu-seccomp-debug.h"
+#endif
 
 #ifdef __sun__
 #include <sys/stat.h>
@@ -3483,6 +3486,13 @@  int main(int argc, char **argv, char **envp)
     }
 
     if (seccomp_get_state() == SECCOMP_ON) {
+#ifdef CONFIG_SECCOMP_DEBUG
+        if (seccomp_install_syscall_debug() < 0) {
+            fprintf(stderr,
+                    "failed to install seccomp syscall debug support\n");
+            exit(1);
+        }
+#endif
         if (seccomp_install_filter(SECCOMP_INIT) < 0) {
             fprintf(stderr, "failed to install seccomp syscall "
                             "initialization filter\n");