Blame 0061-virtiofsd-add-seccomp-whitelist.patch

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