From b433149884778254042b6f4b29cb3c098313c5ad Mon Sep 17 00:00:00 2001
From: Larry Dewey <ldewey@suse.com>
Date: Wed, 24 Oct 2018 12:41:30 -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/usb/ccid-card-emulated.c | 12 ++++++++++++
 include/sysemu/seccomp.h    |  2 +-
 iothread.c                  |  8 ++++++++
 libcacard/vscclient.c       |  7 +++++++
 migration.c                 |  8 ++++++++
 qemu-img.c                  |  7 +++++++
 qemu-io.c                   |  7 +++++++
 qemu-nbd.c                  |  7 +++++++
 qemu-seccomp.c              | 13 ++++++++++++-
 stubs/qtest.c               |  5 +++++
 tests/test-aio.c            |  8 ++++++++
 tests/test-rfifolock.c      |  8 ++++++++
 thread-pool.c               |  9 +++++++++
 ui/vnc-jobs.c               |  8 ++++++++
 util/compatfd.c             |  9 +++++++++
 vl.c                        | 22 +++++++++++-----------
 17 files changed, 143 insertions(+), 13 deletions(-)

diff --git a/cpus.c b/cpus.c
index 4ee6df99c6..f5e28311b5 100644
--- a/cpus.c
+++ b/cpus.c
@@ -39,6 +39,10 @@
 #include "qemu/bitmap.h"
 #include "qemu/seqlock.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 #ifndef _WIN32
 #include "qemu/compatfd.h"
 #endif
@@ -860,6 +864,10 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
     CPUState *cpu = arg;
     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();
@@ -900,6 +908,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();
@@ -938,6 +950,10 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
 {
     CPUState *cpu = arg;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     qemu_tcg_init_cpu_signals();
     qemu_thread_get_self(cpu->thread);
 
diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c
index 7213c8909c..d973bd1aaa 100644
--- a/hw/usb/ccid-card-emulated.c
+++ b/hw/usb/ccid-card-emulated.c
@@ -36,6 +36,10 @@
 #include "monitor/monitor.h"
 #include "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/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/iothread.c b/iothread.c
index 1fbf9f1c49..099510b95d 100644
--- a/iothread.c
+++ b/iothread.c
@@ -18,6 +18,10 @@
 #include "sysemu/iothread.h"
 #include "qmp-commands.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 #define IOTHREADS_PATH "/objects"
 
 typedef ObjectClass IOThreadClass;
@@ -31,6 +35,10 @@ static void *iothread_run(void *opaque)
 {
     IOThread *iothread = opaque;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     qemu_mutex_lock(&iothread->init_done_lock);
     iothread->thread_id = qemu_get_thread_id();
     qemu_cond_signal(&iothread->init_done_cond);
diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c
index 3477ab3e1b..1912e145a8 100644
--- a/libcacard/vscclient.c
+++ b/libcacard/vscclient.c
@@ -25,6 +25,10 @@
 #include "vcard_emul.h"
 #include "vevent.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 static int verbose;
 
 static void
@@ -135,6 +139,9 @@ event_thread(void *arg)
     VEvent *event = NULL;
     unsigned int reader_id;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
 
     while (1) {
         const char *reader_name;
diff --git a/migration.c b/migration.c
index b391a8304f..9c8418abe4 100644
--- a/migration.c
+++ b/migration.c
@@ -26,6 +26,10 @@
 #include "qmp-commands.h"
 #include "trace.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 enum {
     MIG_STATE_ERROR = -1,
     MIG_STATE_NONE,
@@ -578,6 +582,10 @@ static void *migration_thread(void *opaque)
     int64_t start_time = initial_time;
     bool old_vm_running = false;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     qemu_savevm_state_begin(s->file, &s->params);
 
     s->setup_time = qemu_clock_get_ms(QEMU_CLOCK_HOST) - setup_start;
diff --git a/qemu-img.c b/qemu-img.c
index 26700e3e86..6844b743ca 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -33,6 +33,13 @@
 #include "block/qapi.h"
 #include <getopt.h>
 
+#include "qemu/compiler.h"
+
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+int seccomp_start(_Bool enabled) { return 0; }
+#endif
+
 typedef struct img_cmd_t {
     const char *name;
     int (*handler)(int argc, char **argv);
diff --git a/qemu-io.c b/qemu-io.c
index bc1277d096..2d6e644ae2 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -22,6 +22,13 @@
 #include "block/block_int.h"
 #include "trace/control.h"
 
+#include "qemu/compiler.h"
+
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+int seccomp_start(_Bool enabled) { return 0; }
+#endif
+
 #define CMD_NOFILE_OK   0x01
 
 static char *progname;
diff --git a/qemu-nbd.c b/qemu-nbd.c
index c39935409d..6ba780197a 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -37,6 +37,13 @@
 #include <libgen.h>
 #include <pthread.h>
 
+#include "qemu/compiler.h"
+
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+int seccomp_start(_Bool enabled) { return 0; }
+#endif
+
 #define SOCKET_PATH          "/var/lock/qemu-nbd-%s"
 #define QEMU_NBD_OPT_CACHE   1
 #define QEMU_NBD_OPT_AIO     2
diff --git a/qemu-seccomp.c b/qemu-seccomp.c
index ea8094d043..951526a55c 100644
--- a/qemu-seccomp.c
+++ b/qemu-seccomp.c
@@ -233,12 +233,23 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = {
     { SCMP_SYS(munlock), 240 }
 };
 
-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) {
         rc = -1;
diff --git a/stubs/qtest.c b/stubs/qtest.c
index e671ed8e8e..02a5201562 100644
--- a/stubs/qtest.c
+++ b/stubs/qtest.c
@@ -10,5 +10,10 @@
 
 #include "qemu-common.h"
 
+/* Needed to stub for seccomp */
+
+int seccomp_start(_Bool enabled) __attribute__ ((weak));
+int seccomp_start(_Bool enabled) { return 0; }
+
 /* Needed for qtest_allowed() */
 bool qtest_allowed;
diff --git a/tests/test-aio.c b/tests/test-aio.c
index e5f8b55d30..3a5d8bc613 100644
--- a/tests/test-aio.c
+++ b/tests/test-aio.c
@@ -15,6 +15,10 @@
 #include "qemu/timer.h"
 #include "qemu/sockets.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 AioContext *ctx;
 
 typedef struct {
@@ -125,6 +129,10 @@ static void *test_acquire_thread(void *opaque)
 {
     AcquireTestData *data = opaque;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     /* Wait for other thread to let us start */
     qemu_mutex_lock(&data->start_lock);
     qemu_mutex_unlock(&data->start_lock);
diff --git a/tests/test-rfifolock.c b/tests/test-rfifolock.c
index 0572ebb42a..d272aca6eb 100644
--- a/tests/test-rfifolock.c
+++ b/tests/test-rfifolock.c
@@ -14,6 +14,10 @@
 #include "qemu-common.h"
 #include "qemu/rfifolock.h"
 
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
+
 static void test_nesting(void)
 {
     RFifoLock lock;
@@ -48,6 +52,10 @@ static void *callback_thread(void *opaque)
 {
     CallbackTestData *data = opaque;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     /* The other thread holds the lock so the contention callback will be
      * invoked...
      */
diff --git a/thread-pool.c b/thread-pool.c
index 04af589456..6cae781cf3 100644
--- a/thread-pool.c
+++ b/thread-pool.c
@@ -23,6 +23,11 @@
 #include "qemu/event_notifier.h"
 #include "block/thread-pool.h"
 #include "qemu/main-loop.h"
+#include "qemu/compiler.h"
+
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
 
 static void do_spawn_thread(ThreadPool *pool);
 
@@ -82,6 +87,10 @@ static void *worker_thread(void *opaque)
 {
     ThreadPool *pool = opaque;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     qemu_mutex_lock(&pool->lock);
     pool->pending_threads--;
     do_spawn_thread(pool);
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index 68f3d773d9..fc1217880f 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:
  *
@@ -318,6 +322,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/util/compatfd.c b/util/compatfd.c
index 341ada638f..12128b467c 100644
--- a/util/compatfd.c
+++ b/util/compatfd.c
@@ -16,6 +16,11 @@
 #include "qemu-common.h"
 #include "qemu/compatfd.h"
 #include "qemu/thread.h"
+#include "qemu/compiler.h"
+
+#ifdef CONFIG_SECCOMP
+#include "sysemu/seccomp.h"
+#endif
 
 #include <sys/syscall.h>
 
@@ -29,6 +34,10 @@ static void *sigwait_compat(void *opaque)
 {
     struct sigfd_compat_info *info = opaque;
 
+#ifdef CONFIG_SECCOMP
+    seccomp_start(!!0);
+#endif
+
     while (1) {
         int sig;
         int err;
diff --git a/vl.c b/vl.c
index 1459ffdedf..e00ed98e0b 100644
--- a/vl.c
+++ b/vl.c
@@ -947,7 +947,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;
@@ -3059,6 +3059,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;
             }
         }
     }
@@ -3071,6 +3077,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(;;) {
@@ -3885,12 +3895,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);
@@ -3935,10 +3939,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);
