From 607dd016c24b1b0eeea0462e2dc5e0694a018982 Mon Sep 17 00:00:00 2001
From: Larry Dewey <ldewey@suse.com>
Date: Tue, 23 Oct 2018 15:46:38 -0600
Subject: [PATCH] seccomp: secure all threads with seccomp manually.

Just before starting a child thread, a call to seccomp_start() has been
added to ensure that each thread is sandboxed properly, and that
seccomp is successfully applied to all threads when the user specifies
that sanboxing should be used either via /etc/libvirt/qemu.conf or via
the command line by passing `--seccomp on` to qemu.

[LD: BSC#1106222 CVE-2018-15746]
Signed-off-by: Larry Dewey <ldewey@suse.com>
---
 cpus.c                    | 16 ++++++++++++++++
 hw/ccid-card-emulated.c   | 12 ++++++++++++
 hw/dataplane/virtio-blk.c |  8 ++++++++
 include/sysemu/seccomp.h  |  2 +-
 migration.c               |  8 ++++++++
 qemu-img.c                |  9 +++++++++
 qemu-io.c                 |  9 +++++++++
 qemu-nbd.c                |  9 +++++++++
 qemu-seccomp.c            | 13 ++++++++++++-
 thread-pool.c             |  9 +++++++++
 ui/vnc-jobs.c             |  8 ++++++++
 vl.c                      | 22 +++++++++++-----------
 12 files changed, 112 insertions(+), 13 deletions(-)

diff --git a/cpus.c b/cpus.c
index c851177b12..61f8b12b3a 100644
--- a/cpus.c
+++ b/cpus.c
@@ -38,6 +38,10 @@
 #include "qemu/main-loop.h"
 #include "qemu/bitmap.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 #ifndef _WIN32
 #include "qemu/compatfd.h"
 #endif
@@ -748,6 +752,10 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
     CPUState *cpu = ENV_GET_CPU(env);
     int r;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     qemu_mutex_lock(&qemu_global_mutex);
     qemu_thread_get_self(cpu->thread);
     cpu->thread_id = qemu_get_thread_id();
@@ -790,6 +798,10 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
     sigset_t waitset;
     int r;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     qemu_mutex_lock_iothread();
     qemu_thread_get_self(cpu->thread);
     cpu->thread_id = qemu_get_thread_id();
@@ -832,6 +844,10 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
     CPUState *cpu = arg;
     CPUArchState *env;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     qemu_tcg_init_cpu_signals();
     qemu_thread_get_self(cpu->thread);
 
diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
index c8f8ba3792..02fd7dd911 100644
--- a/hw/ccid-card-emulated.c
+++ b/hw/ccid-card-emulated.c
@@ -36,6 +36,10 @@
 #include "monitor/monitor.h"
 #include "hw/ccid.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 #define DPRINTF(card, lvl, fmt, ...) \
 do {\
     if (lvl <= card->debug) {\
@@ -234,6 +238,10 @@ static void *handle_apdu_thread(void* arg)
     VReaderStatus reader_status;
     EmulEvent *event;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     while (1) {
         qemu_mutex_lock(&card->handle_apdu_mutex);
         qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex);
@@ -281,6 +289,10 @@ static void *event_thread(void *arg)
     VEvent *event = NULL;
     EmulatedState *card = arg;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     while (1) {
         const char *reader_name;
 
diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c
index 3f2da22669..7544a441d2 100644
--- a/hw/dataplane/virtio-blk.c
+++ b/hw/dataplane/virtio-blk.c
@@ -22,6 +22,10 @@
 #include "hw/virtio-blk.h"
 #include "hw/dataplane/virtio-blk.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 enum {
     SEG_MAX = 126,                  /* maximum number of I/O segments */
     VRING_MAX = SEG_MAX + 2,        /* maximum number of vring descriptors */
@@ -356,6 +360,10 @@ static void *data_plane_thread(void *opaque)
 {
     VirtIOBlockDataPlane *s = opaque;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     do {
         event_poll(&s->event_poll);
     } while (!s->stopping || s->num_reqs > 0);
diff --git a/include/sysemu/seccomp.h b/include/sysemu/seccomp.h
index 1189fa241d..28e67ed0c7 100644
--- a/include/sysemu/seccomp.h
+++ b/include/sysemu/seccomp.h
@@ -18,5 +18,5 @@
 #include <seccomp.h>
 #include "qemu/osdep.h"
 
-int seccomp_start(void);
+int seccomp_start(_Bool enabled);
 #endif
diff --git a/migration.c b/migration.c
index f048c84838..e575e52bd9 100644
--- a/migration.c
+++ b/migration.c
@@ -24,6 +24,10 @@
 #include "qemu/thread.h"
 #include "qmp-commands.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 //#define DEBUG_MIGRATION
 
 #ifdef DEBUG_MIGRATION
@@ -663,6 +667,10 @@ static void *buffered_file_thread(void *opaque)
     bool last_round = false;
     int ret;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     qemu_mutex_lock_iothread();
     DPRINTF("beginning savevm\n");
     ret = qemu_savevm_state_begin(s->file, &s->params);
diff --git a/qemu-img.c b/qemu-img.c
index 85d3740b9c..7bb700a0d3 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -28,11 +28,16 @@
 #include "qemu/option.h"
 #include "qemu/error-report.h"
 #include "qemu/osdep.h"
+#include "qemu/compiler.h"
 #include "sysemu/sysemu.h"
 #include "block/block_int.h"
 #include <getopt.h>
 #include <stdio.h>
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 #ifdef _WIN32
 #include <windows.h>
 #endif
@@ -46,6 +51,10 @@ typedef struct img_cmd_t {
 #define BDRV_O_FLAGS BDRV_O_CACHE_WB
 #define BDRV_DEFAULT_CACHE "writeback"
 
+#ifdef CONFIG_SECCOMP
+int seccomp_start(_Bool enabled) { return 0; }
+#endif
+
 static void format_print(void *opaque, const char *name)
 {
     printf(" %s", name);
diff --git a/qemu-io.c b/qemu-io.c
index 61880932b3..e355492159 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -16,10 +16,15 @@
 
 #include "qemu-common.h"
 #include "qemu/main-loop.h"
+#include "qemu/compiler.h"
 #include "block/block_int.h"
 #include "cmd.h"
 #include "trace/control.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 #define VERSION	"0.0.1"
 
 #define CMD_NOFILE_OK   0x01
@@ -29,6 +34,10 @@ static BlockDriverState *bs;
 
 static int misalign;
 
+#ifdef CONFIG_SECCOMP
+int seccomp_start(_Bool enabled){ return 0; }
+#endif
+
 /*
  * Parse the pattern argument to various sub-commands.
  *
diff --git a/qemu-nbd.c b/qemu-nbd.c
index cd94832447..5903f1e1d1 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -17,6 +17,7 @@
  */
 
 #include "qemu-common.h"
+#include "qemu/compiler.h"
 #include "block/block.h"
 #include "block/nbd.h"
 
@@ -33,6 +34,10 @@
 #include <libgen.h>
 #include <pthread.h>
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 #define SOCKET_PATH         "/var/lock/qemu-nbd-%s"
 #define QEMU_NBD_OPT_CACHE  1
 #define QEMU_NBD_OPT_AIO    2
@@ -46,6 +51,10 @@ static enum { RUNNING, TERMINATE, TERMINATING, TERMINATED } state;
 static int shared = 1;
 static int nb_fds;
 
+#ifdef CONFIG_SECCOMP
+int seccomp_start(_Bool enabled) { return 0; }
+#endif
+
 static void usage(const char *name)
 {
     (printf) (
diff --git a/qemu-seccomp.c b/qemu-seccomp.c
index 157af98656..c0932f8652 100644
--- a/qemu-seccomp.c
+++ b/qemu-seccomp.c
@@ -232,12 +232,23 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = {
     { SCMP_SYS(shmget), 241 }
 };
 
-int seccomp_start(void)
+int seccomp_start(_Bool enabled)
 {
+    static _Bool is_enabled = !!0;
     int rc = 0;
     unsigned int i = 0;
     scmp_filter_ctx ctx;
 
+    if (!is_enabled && !enabled)
+    {
+        return rc;
+    }
+
+    if (enabled)
+    {
+        is_enabled = !!1;
+    }
+
     ctx = seccomp_init(SCMP_ACT_KILL);
     if (ctx == NULL) {
         goto seccomp_return;
diff --git a/thread-pool.c b/thread-pool.c
index e3ca64d790..dc8311359c 100644
--- a/thread-pool.c
+++ b/thread-pool.c
@@ -18,12 +18,17 @@
 #include "qemu/queue.h"
 #include "qemu/thread.h"
 #include "qemu/osdep.h"
+#include "qemu/compiler.h"
 #include "block/coroutine.h"
 #include "trace.h"
 #include "block/block_int.h"
 #include "qemu/event_notifier.h"
 #include "block/thread-pool.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 static void do_spawn_thread(void);
 
 typedef struct ThreadPoolElement ThreadPoolElement;
@@ -74,6 +79,10 @@ static int pending_cancellations; /* whether we need a cond_broadcast */
 
 static void *worker_thread(void *unused)
 {
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     qemu_mutex_lock(&lock);
     pending_threads--;
     do_spawn_thread();
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index 2d3fce8155..12addb6077 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -30,6 +30,10 @@
 #include "vnc-jobs.h"
 #include "qemu/sockets.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 /*
  * Locking:
  *
@@ -313,6 +317,10 @@ static void *vnc_worker_thread(void *arg)
 {
     VncJobQueue *queue = arg;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     qemu_thread_get_self(&queue->thread);
 
     while (!vnc_worker_thread_loop(queue)) ;
diff --git a/vl.c b/vl.c
index 316210e6cc..9343cf9e99 100644
--- a/vl.c
+++ b/vl.c
@@ -970,7 +970,7 @@ static int parse_sandbox(QemuOpts *opts, void *opaque)
     /* FIXME: change this to true for 1.3 */
     if (qemu_opt_get_bool(opts, "enable", false)) {
 #ifdef CONFIG_SECCOMP
-        if (seccomp_start() < 0) {
+        if (seccomp_start(!!1) < 0) {
             qerror_report(ERROR_CLASS_GENERIC_ERROR,
                           "failed to install seccomp syscall filter in the kernel");
             return -1;
@@ -2947,6 +2947,12 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_nouserconfig:
                 userconfig = false;
                 break;
+            case QEMU_OPTION_sandbox:
+                opts = qemu_opts_parse(qemu_find_opts("sandbox"), optarg, 1);
+                if (!opts) {
+                    exit(1);
+                }
+                break;
             }
         }
     }
@@ -2959,6 +2965,10 @@ int main(int argc, char **argv, char **envp)
         }
     }
 
+    if (qemu_opts_foreach(qemu_find_opts("sandbox"), parse_sandbox, NULL, 0)) {
+        exit(1);
+    }
+
     /* second pass of option parsing */
     optind = 1;
     for(;;) {
@@ -3843,12 +3853,6 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_qtest_log:
                 qtest_log = optarg;
                 break;
-            case QEMU_OPTION_sandbox:
-                opts = qemu_opts_parse(qemu_find_opts("sandbox"), optarg, 1);
-                if (!opts) {
-                    exit(1);
-                }
-                break;
             case QEMU_OPTION_add_fd:
 #ifndef _WIN32
                 opts = qemu_opts_parse(qemu_find_opts("add-fd"), optarg, 0);
@@ -3879,10 +3883,6 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     }
 
-    if (qemu_opts_foreach(qemu_find_opts("sandbox"), parse_sandbox, NULL, 0)) {
-        exit(1);
-    }
-
 #ifndef _WIN32
     if (qemu_opts_foreach(qemu_find_opts("add-fd"), parse_add_fd, NULL, 1)) {
         exit(1);
