summaryrefslogtreecommitdiffstats
path: root/tools/virtiofsd/passthrough_seccomp.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/virtiofsd/passthrough_seccomp.c')
-rw-r--r--tools/virtiofsd/passthrough_seccomp.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/tools/virtiofsd/passthrough_seccomp.c b/tools/virtiofsd/passthrough_seccomp.c
new file mode 100644
index 0000000000..19fee60011
--- /dev/null
+++ b/tools/virtiofsd/passthrough_seccomp.c
@@ -0,0 +1,172 @@
+/*
+ * Seccomp sandboxing for virtiofsd
+ *
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "passthrough_seccomp.h"
+#include "fuse_i.h"
+#include "fuse_log.h"
+#include <errno.h>
+#include <glib.h>
+#include <seccomp.h>
+#include <stdlib.h>
+
+/* Bodge for libseccomp 2.4.2 which broke ppoll */
+#if !defined(__SNR_ppoll) && defined(__SNR_brk)
+#ifdef __NR_ppoll
+#define __SNR_ppoll __NR_ppoll
+#else
+#define __SNR_ppoll __PNR_ppoll
+#endif
+#endif
+
+static const int syscall_whitelist[] = {
+ /* TODO ireg sem*() syscalls */
+ SCMP_SYS(brk),
+ SCMP_SYS(capget), /* For CAP_FSETID */
+ SCMP_SYS(capset),
+ SCMP_SYS(clock_gettime),
+ SCMP_SYS(clone),
+#ifdef __NR_clone3
+ SCMP_SYS(clone3),
+#endif
+ SCMP_SYS(close),
+ SCMP_SYS(copy_file_range),
+ SCMP_SYS(dup),
+ SCMP_SYS(eventfd2),
+ SCMP_SYS(exit),
+ SCMP_SYS(exit_group),
+ SCMP_SYS(fallocate),
+ SCMP_SYS(fchdir),
+ SCMP_SYS(fchmod),
+ SCMP_SYS(fchmodat),
+ SCMP_SYS(fchownat),
+ SCMP_SYS(fcntl),
+ SCMP_SYS(fdatasync),
+ SCMP_SYS(fgetxattr),
+ SCMP_SYS(flistxattr),
+ SCMP_SYS(flock),
+ SCMP_SYS(fremovexattr),
+ SCMP_SYS(fsetxattr),
+ SCMP_SYS(fstat),
+ SCMP_SYS(fstatfs),
+ SCMP_SYS(fsync),
+ SCMP_SYS(ftruncate),
+ SCMP_SYS(futex),
+ SCMP_SYS(getdents),
+ SCMP_SYS(getdents64),
+ SCMP_SYS(getegid),
+ SCMP_SYS(geteuid),
+ SCMP_SYS(getpid),
+ SCMP_SYS(gettid),
+ SCMP_SYS(gettimeofday),
+ SCMP_SYS(getxattr),
+ SCMP_SYS(linkat),
+ SCMP_SYS(listxattr),
+ SCMP_SYS(lseek),
+ SCMP_SYS(madvise),
+ SCMP_SYS(mkdirat),
+ SCMP_SYS(mknodat),
+ SCMP_SYS(mmap),
+ SCMP_SYS(mprotect),
+ SCMP_SYS(mremap),
+ SCMP_SYS(munmap),
+ SCMP_SYS(newfstatat),
+ SCMP_SYS(open),
+ SCMP_SYS(openat),
+ SCMP_SYS(ppoll),
+ SCMP_SYS(prctl), /* TODO restrict to just PR_SET_NAME? */
+ SCMP_SYS(preadv),
+ SCMP_SYS(pread64),
+ SCMP_SYS(pwritev),
+ SCMP_SYS(pwrite64),
+ SCMP_SYS(read),
+ SCMP_SYS(readlinkat),
+ SCMP_SYS(recvmsg),
+ SCMP_SYS(renameat),
+ SCMP_SYS(renameat2),
+ SCMP_SYS(removexattr),
+ SCMP_SYS(rt_sigaction),
+ SCMP_SYS(rt_sigprocmask),
+ SCMP_SYS(rt_sigreturn),
+ SCMP_SYS(sendmsg),
+ SCMP_SYS(setresgid),
+ SCMP_SYS(setresuid),
+#ifdef __NR_setresgid32
+ SCMP_SYS(setresgid32),
+#endif
+#ifdef __NR_setresuid32
+ SCMP_SYS(setresuid32),
+#endif
+ SCMP_SYS(set_robust_list),
+ SCMP_SYS(setxattr),
+ SCMP_SYS(symlinkat),
+ SCMP_SYS(time), /* Rarely needed, except on static builds */
+ SCMP_SYS(tgkill),
+ SCMP_SYS(unlinkat),
+ SCMP_SYS(unshare),
+ SCMP_SYS(utimensat),
+ SCMP_SYS(write),
+ SCMP_SYS(writev),
+};
+
+/* Syscalls used when --syslog is enabled */
+static const int syscall_whitelist_syslog[] = {
+ SCMP_SYS(sendto),
+};
+
+static void add_whitelist(scmp_filter_ctx ctx, const int syscalls[], size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls[i], 0) != 0) {
+ fuse_log(FUSE_LOG_ERR, "seccomp_rule_add syscall %d failed\n",
+ syscalls[i]);
+ exit(1);
+ }
+ }
+}
+
+void setup_seccomp(bool enable_syslog)
+{
+ scmp_filter_ctx ctx;
+
+#ifdef SCMP_ACT_KILL_PROCESS
+ ctx = seccomp_init(SCMP_ACT_KILL_PROCESS);
+ /* Handle a newer libseccomp but an older kernel */
+ if (!ctx && errno == EOPNOTSUPP) {
+ ctx = seccomp_init(SCMP_ACT_TRAP);
+ }
+#else
+ ctx = seccomp_init(SCMP_ACT_TRAP);
+#endif
+ if (!ctx) {
+ fuse_log(FUSE_LOG_ERR, "seccomp_init() failed\n");
+ exit(1);
+ }
+
+ add_whitelist(ctx, syscall_whitelist, G_N_ELEMENTS(syscall_whitelist));
+ if (enable_syslog) {
+ add_whitelist(ctx, syscall_whitelist_syslog,
+ G_N_ELEMENTS(syscall_whitelist_syslog));
+ }
+
+ /* libvhost-user calls this for post-copy migration, we don't need it */
+ if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOSYS),
+ SCMP_SYS(userfaultfd), 0) != 0) {
+ fuse_log(FUSE_LOG_ERR, "seccomp_rule_add userfaultfd failed\n");
+ exit(1);
+ }
+
+ if (seccomp_load(ctx) < 0) {
+ fuse_log(FUSE_LOG_ERR, "seccomp_load() failed\n");
+ exit(1);
+ }
+
+ seccomp_release(ctx);
+}