ddf19c
From 58c4e9473b364fb62aac797b0d69fd8ddb02c8c7 Mon Sep 17 00:00:00 2001
ddf19c
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
ddf19c
Date: Mon, 27 Jan 2020 19:01:30 +0100
ddf19c
Subject: [PATCH 059/116] virtiofsd: add seccomp whitelist
ddf19c
MIME-Version: 1.0
ddf19c
Content-Type: text/plain; charset=UTF-8
ddf19c
Content-Transfer-Encoding: 8bit
ddf19c
ddf19c
RH-Author: Dr. David Alan Gilbert <dgilbert@redhat.com>
ddf19c
Message-id: <20200127190227.40942-56-dgilbert@redhat.com>
ddf19c
Patchwork-id: 93511
ddf19c
O-Subject: [RHEL-AV-8.2 qemu-kvm PATCH 055/112] virtiofsd: add seccomp whitelist
ddf19c
Bugzilla: 1694164
ddf19c
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
ddf19c
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
ddf19c
RH-Acked-by: Sergio Lopez Pascual <slp@redhat.com>
ddf19c
ddf19c
From: Stefan Hajnoczi <stefanha@redhat.com>
ddf19c
ddf19c
Only allow system calls that are needed by virtiofsd.  All other system
ddf19c
calls cause SIGSYS to be directed at the thread and the process will
ddf19c
coredump.
ddf19c
ddf19c
Restricting system calls reduces the kernel attack surface and limits
ddf19c
what the process can do when compromised.
ddf19c
ddf19c
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
ddf19c
with additional entries by:
ddf19c
Signed-off-by: Ganesh Maharaj Mahalingam <ganesh.mahalingam@intel.com>
ddf19c
Signed-off-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
ddf19c
Signed-off-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
ddf19c
Signed-off-by: piaojun <piaojun@huawei.com>
ddf19c
Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
ddf19c
Signed-off-by: Eric Ren <renzhen@linux.alibaba.com>
ddf19c
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
ddf19c
(cherry picked from commit 4f8bde99c175ffd86b5125098a4707d43f5e80c6)
ddf19c
ddf19c
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
ddf19c
---
ddf19c
 Makefile                         |   5 +-
ddf19c
 tools/virtiofsd/Makefile.objs    |   5 +-
ddf19c
 tools/virtiofsd/passthrough_ll.c |   2 +
ddf19c
 tools/virtiofsd/seccomp.c        | 151 +++++++++++++++++++++++++++++++++++++++
ddf19c
 tools/virtiofsd/seccomp.h        |  14 ++++
ddf19c
 5 files changed, 174 insertions(+), 3 deletions(-)
ddf19c
 create mode 100644 tools/virtiofsd/seccomp.c
ddf19c
 create mode 100644 tools/virtiofsd/seccomp.h
ddf19c
ddf19c
diff --git a/Makefile b/Makefile
ddf19c
index 0e9755d..6879a06 100644
ddf19c
--- a/Makefile
ddf19c
+++ b/Makefile
ddf19c
@@ -330,7 +330,7 @@ endif
ddf19c
 endif
ddf19c
 endif
ddf19c
 
ddf19c
-ifdef CONFIG_LINUX
ddf19c
+ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP),yy)
ddf19c
 HELPERS-y += virtiofsd$(EXESUF)
ddf19c
 vhost-user-json-y += tools/virtiofsd/50-qemu-virtiofsd.json
ddf19c
 endif
ddf19c
@@ -681,7 +681,8 @@ rdmacm-mux$(EXESUF): LIBS += "-libumad"
ddf19c
 rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
ddf19c
 	$(call LINK, $^)
ddf19c
 
ddf19c
-ifdef CONFIG_LINUX # relies on Linux-specific syscalls
ddf19c
+# relies on Linux-specific syscalls
ddf19c
+ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP),yy)
ddf19c
 virtiofsd$(EXESUF): $(virtiofsd-obj-y) libvhost-user.a $(COMMON_LDADDS)
ddf19c
 	$(call LINK, $^)
ddf19c
 endif
ddf19c
diff --git a/tools/virtiofsd/Makefile.objs b/tools/virtiofsd/Makefile.objs
ddf19c
index 45a8075..076f667 100644
ddf19c
--- a/tools/virtiofsd/Makefile.objs
ddf19c
+++ b/tools/virtiofsd/Makefile.objs
ddf19c
@@ -5,5 +5,8 @@ virtiofsd-obj-y = buffer.o \
ddf19c
                   fuse_signals.o \
ddf19c
                   fuse_virtio.o \
ddf19c
                   helper.o \
ddf19c
-                  passthrough_ll.o
ddf19c
+                  passthrough_ll.o \
ddf19c
+                  seccomp.o
ddf19c
 
ddf19c
+seccomp.o-cflags := $(SECCOMP_CFLAGS)
ddf19c
+seccomp.o-libs := $(SECCOMP_LIBS)
ddf19c
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
ddf19c
index 0947d14..bd8925b 100644
ddf19c
--- a/tools/virtiofsd/passthrough_ll.c
ddf19c
+++ b/tools/virtiofsd/passthrough_ll.c
ddf19c
@@ -59,6 +59,7 @@
ddf19c
 #include <unistd.h>
ddf19c
 
ddf19c
 #include "passthrough_helpers.h"
ddf19c
+#include "seccomp.h"
ddf19c
 
ddf19c
 struct lo_map_elem {
ddf19c
     union {
ddf19c
@@ -2091,6 +2092,7 @@ static void setup_sandbox(struct lo_data *lo, struct fuse_session *se)
ddf19c
 {
ddf19c
     setup_namespaces(lo, se);
ddf19c
     setup_mounts(lo->source);
ddf19c
+    setup_seccomp();
ddf19c
 }
ddf19c
 
ddf19c
 int main(int argc, char *argv[])
ddf19c
diff --git a/tools/virtiofsd/seccomp.c b/tools/virtiofsd/seccomp.c
ddf19c
new file mode 100644
ddf19c
index 0000000..691fb63
ddf19c
--- /dev/null
ddf19c
+++ b/tools/virtiofsd/seccomp.c
ddf19c
@@ -0,0 +1,151 @@
ddf19c
+/*
ddf19c
+ * Seccomp sandboxing for virtiofsd
ddf19c
+ *
ddf19c
+ * Copyright (C) 2019 Red Hat, Inc.
ddf19c
+ *
ddf19c
+ * SPDX-License-Identifier: GPL-2.0-or-later
ddf19c
+ */
ddf19c
+
ddf19c
+#include "qemu/osdep.h"
ddf19c
+#include "seccomp.h"
ddf19c
+#include "fuse_i.h"
ddf19c
+#include "fuse_log.h"
ddf19c
+#include <errno.h>
ddf19c
+#include <glib.h>
ddf19c
+#include <seccomp.h>
ddf19c
+#include <stdlib.h>
ddf19c
+
ddf19c
+/* Bodge for libseccomp 2.4.2 which broke ppoll */
ddf19c
+#if !defined(__SNR_ppoll) && defined(__SNR_brk)
ddf19c
+#ifdef __NR_ppoll
ddf19c
+#define __SNR_ppoll __NR_ppoll
ddf19c
+#else
ddf19c
+#define __SNR_ppoll __PNR_ppoll
ddf19c
+#endif
ddf19c
+#endif
ddf19c
+
ddf19c
+static const int syscall_whitelist[] = {
ddf19c
+    /* TODO ireg sem*() syscalls */
ddf19c
+    SCMP_SYS(brk),
ddf19c
+    SCMP_SYS(capget), /* For CAP_FSETID */
ddf19c
+    SCMP_SYS(capset),
ddf19c
+    SCMP_SYS(clock_gettime),
ddf19c
+    SCMP_SYS(clone),
ddf19c
+#ifdef __NR_clone3
ddf19c
+    SCMP_SYS(clone3),
ddf19c
+#endif
ddf19c
+    SCMP_SYS(close),
ddf19c
+    SCMP_SYS(copy_file_range),
ddf19c
+    SCMP_SYS(dup),
ddf19c
+    SCMP_SYS(eventfd2),
ddf19c
+    SCMP_SYS(exit),
ddf19c
+    SCMP_SYS(exit_group),
ddf19c
+    SCMP_SYS(fallocate),
ddf19c
+    SCMP_SYS(fchmodat),
ddf19c
+    SCMP_SYS(fchownat),
ddf19c
+    SCMP_SYS(fcntl),
ddf19c
+    SCMP_SYS(fdatasync),
ddf19c
+    SCMP_SYS(fgetxattr),
ddf19c
+    SCMP_SYS(flistxattr),
ddf19c
+    SCMP_SYS(flock),
ddf19c
+    SCMP_SYS(fremovexattr),
ddf19c
+    SCMP_SYS(fsetxattr),
ddf19c
+    SCMP_SYS(fstat),
ddf19c
+    SCMP_SYS(fstatfs),
ddf19c
+    SCMP_SYS(fsync),
ddf19c
+    SCMP_SYS(ftruncate),
ddf19c
+    SCMP_SYS(futex),
ddf19c
+    SCMP_SYS(getdents),
ddf19c
+    SCMP_SYS(getdents64),
ddf19c
+    SCMP_SYS(getegid),
ddf19c
+    SCMP_SYS(geteuid),
ddf19c
+    SCMP_SYS(getpid),
ddf19c
+    SCMP_SYS(gettid),
ddf19c
+    SCMP_SYS(gettimeofday),
ddf19c
+    SCMP_SYS(linkat),
ddf19c
+    SCMP_SYS(lseek),
ddf19c
+    SCMP_SYS(madvise),
ddf19c
+    SCMP_SYS(mkdirat),
ddf19c
+    SCMP_SYS(mknodat),
ddf19c
+    SCMP_SYS(mmap),
ddf19c
+    SCMP_SYS(mprotect),
ddf19c
+    SCMP_SYS(mremap),
ddf19c
+    SCMP_SYS(munmap),
ddf19c
+    SCMP_SYS(newfstatat),
ddf19c
+    SCMP_SYS(open),
ddf19c
+    SCMP_SYS(openat),
ddf19c
+    SCMP_SYS(ppoll),
ddf19c
+    SCMP_SYS(prctl), /* TODO restrict to just PR_SET_NAME? */
ddf19c
+    SCMP_SYS(preadv),
ddf19c
+    SCMP_SYS(pread64),
ddf19c
+    SCMP_SYS(pwritev),
ddf19c
+    SCMP_SYS(pwrite64),
ddf19c
+    SCMP_SYS(read),
ddf19c
+    SCMP_SYS(readlinkat),
ddf19c
+    SCMP_SYS(recvmsg),
ddf19c
+    SCMP_SYS(renameat),
ddf19c
+    SCMP_SYS(renameat2),
ddf19c
+    SCMP_SYS(rt_sigaction),
ddf19c
+    SCMP_SYS(rt_sigprocmask),
ddf19c
+    SCMP_SYS(rt_sigreturn),
ddf19c
+    SCMP_SYS(sendmsg),
ddf19c
+    SCMP_SYS(setresgid),
ddf19c
+    SCMP_SYS(setresuid),
ddf19c
+#ifdef __NR_setresgid32
ddf19c
+    SCMP_SYS(setresgid32),
ddf19c
+#endif
ddf19c
+#ifdef __NR_setresuid32
ddf19c
+    SCMP_SYS(setresuid32),
ddf19c
+#endif
ddf19c
+    SCMP_SYS(set_robust_list),
ddf19c
+    SCMP_SYS(symlinkat),
ddf19c
+    SCMP_SYS(time), /* Rarely needed, except on static builds */
ddf19c
+    SCMP_SYS(tgkill),
ddf19c
+    SCMP_SYS(unlinkat),
ddf19c
+    SCMP_SYS(utimensat),
ddf19c
+    SCMP_SYS(write),
ddf19c
+    SCMP_SYS(writev),
ddf19c
+};
ddf19c
+
ddf19c
+void setup_seccomp(void)
ddf19c
+{
ddf19c
+    scmp_filter_ctx ctx;
ddf19c
+    size_t i;
ddf19c
+
ddf19c
+#ifdef SCMP_ACT_KILL_PROCESS
ddf19c
+    ctx = seccomp_init(SCMP_ACT_KILL_PROCESS);
ddf19c
+    /* Handle a newer libseccomp but an older kernel */
ddf19c
+    if (!ctx && errno == EOPNOTSUPP) {
ddf19c
+        ctx = seccomp_init(SCMP_ACT_TRAP);
ddf19c
+    }
ddf19c
+#else
ddf19c
+    ctx = seccomp_init(SCMP_ACT_TRAP);
ddf19c
+#endif
ddf19c
+    if (!ctx) {
ddf19c
+        fuse_log(FUSE_LOG_ERR, "seccomp_init() failed\n");
ddf19c
+        exit(1);
ddf19c
+    }
ddf19c
+
ddf19c
+    for (i = 0; i < G_N_ELEMENTS(syscall_whitelist); i++) {
ddf19c
+        if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW,
ddf19c
+                             syscall_whitelist[i], 0) != 0) {
ddf19c
+            fuse_log(FUSE_LOG_ERR, "seccomp_rule_add syscall %d",
ddf19c
+                     syscall_whitelist[i]);
ddf19c
+            exit(1);
ddf19c
+        }
ddf19c
+    }
ddf19c
+
ddf19c
+    /* libvhost-user calls this for post-copy migration, we don't need it */
ddf19c
+    if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOSYS),
ddf19c
+                         SCMP_SYS(userfaultfd), 0) != 0) {
ddf19c
+        fuse_log(FUSE_LOG_ERR, "seccomp_rule_add userfaultfd failed\n");
ddf19c
+        exit(1);
ddf19c
+    }
ddf19c
+
ddf19c
+    if (seccomp_load(ctx) < 0) {
ddf19c
+        fuse_log(FUSE_LOG_ERR, "seccomp_load() failed\n");
ddf19c
+        exit(1);
ddf19c
+    }
ddf19c
+
ddf19c
+    seccomp_release(ctx);
ddf19c
+}
ddf19c
diff --git a/tools/virtiofsd/seccomp.h b/tools/virtiofsd/seccomp.h
ddf19c
new file mode 100644
ddf19c
index 0000000..86bce72
ddf19c
--- /dev/null
ddf19c
+++ b/tools/virtiofsd/seccomp.h
ddf19c
@@ -0,0 +1,14 @@
ddf19c
+/*
ddf19c
+ * Seccomp sandboxing for virtiofsd
ddf19c
+ *
ddf19c
+ * Copyright (C) 2019 Red Hat, Inc.
ddf19c
+ *
ddf19c
+ * SPDX-License-Identifier: GPL-2.0-or-later
ddf19c
+ */
ddf19c
+
ddf19c
+#ifndef VIRTIOFSD_SECCOMP_H
ddf19c
+#define VIRTIOFSD_SECCOMP_H
ddf19c
+
ddf19c
+void setup_seccomp(void);
ddf19c
+
ddf19c
+#endif /* VIRTIOFSD_SECCOMP_H */
ddf19c
-- 
ddf19c
1.8.3.1
ddf19c