qemu/tools/virtiofsd/passthrough_seccomp.c
<<
>>
Prefs
   1/*
   2 * Seccomp sandboxing for virtiofsd
   3 *
   4 * Copyright (C) 2019 Red Hat, Inc.
   5 *
   6 * SPDX-License-Identifier: GPL-2.0-or-later
   7 */
   8
   9#include "qemu/osdep.h"
  10#include "passthrough_seccomp.h"
  11#include "fuse_i.h"
  12#include "fuse_log.h"
  13#include <seccomp.h>
  14
  15/* Bodge for libseccomp 2.4.2 which broke ppoll */
  16#if !defined(__SNR_ppoll) && defined(__SNR_brk)
  17#ifdef __NR_ppoll
  18#define __SNR_ppoll __NR_ppoll
  19#else
  20#define __SNR_ppoll __PNR_ppoll
  21#endif
  22#endif
  23
  24static const int syscall_allowlist[] = {
  25    /* TODO ireg sem*() syscalls */
  26    SCMP_SYS(brk),
  27    SCMP_SYS(capget), /* For CAP_FSETID */
  28    SCMP_SYS(capset),
  29    SCMP_SYS(clock_gettime),
  30    SCMP_SYS(clone),
  31#ifdef __NR_clone3
  32    SCMP_SYS(clone3),
  33#endif
  34    SCMP_SYS(close),
  35    SCMP_SYS(copy_file_range),
  36    SCMP_SYS(dup),
  37    SCMP_SYS(eventfd2),
  38    SCMP_SYS(exit),
  39    SCMP_SYS(exit_group),
  40    SCMP_SYS(fallocate),
  41    SCMP_SYS(fchdir),
  42    SCMP_SYS(fchmod),
  43    SCMP_SYS(fchmodat),
  44    SCMP_SYS(fchownat),
  45    SCMP_SYS(fcntl),
  46    SCMP_SYS(fdatasync),
  47    SCMP_SYS(fgetxattr),
  48    SCMP_SYS(flistxattr),
  49    SCMP_SYS(flock),
  50    SCMP_SYS(fremovexattr),
  51    SCMP_SYS(fsetxattr),
  52    SCMP_SYS(fstat),
  53    SCMP_SYS(fstatfs),
  54    SCMP_SYS(fsync),
  55    SCMP_SYS(ftruncate),
  56    SCMP_SYS(futex),
  57    SCMP_SYS(getdents),
  58    SCMP_SYS(getdents64),
  59    SCMP_SYS(getegid),
  60    SCMP_SYS(geteuid),
  61    SCMP_SYS(getpid),
  62    SCMP_SYS(gettid),
  63    SCMP_SYS(gettimeofday),
  64    SCMP_SYS(getxattr),
  65    SCMP_SYS(linkat),
  66    SCMP_SYS(listxattr),
  67    SCMP_SYS(lseek),
  68    SCMP_SYS(_llseek), /* For POWER */
  69    SCMP_SYS(madvise),
  70    SCMP_SYS(mkdirat),
  71    SCMP_SYS(mknodat),
  72    SCMP_SYS(mmap),
  73    SCMP_SYS(mprotect),
  74    SCMP_SYS(mremap),
  75    SCMP_SYS(munmap),
  76    SCMP_SYS(newfstatat),
  77    SCMP_SYS(statx),
  78    SCMP_SYS(open),
  79    SCMP_SYS(openat),
  80    SCMP_SYS(ppoll),
  81    SCMP_SYS(prctl), /* TODO restrict to just PR_SET_NAME? */
  82    SCMP_SYS(preadv),
  83    SCMP_SYS(pread64),
  84    SCMP_SYS(pwritev),
  85    SCMP_SYS(pwrite64),
  86    SCMP_SYS(read),
  87    SCMP_SYS(readlinkat),
  88    SCMP_SYS(recvmsg),
  89    SCMP_SYS(renameat),
  90    SCMP_SYS(renameat2),
  91    SCMP_SYS(removexattr),
  92    SCMP_SYS(restart_syscall),
  93    SCMP_SYS(rt_sigaction),
  94    SCMP_SYS(rt_sigprocmask),
  95    SCMP_SYS(rt_sigreturn),
  96    SCMP_SYS(sched_getattr),
  97    SCMP_SYS(sched_setattr),
  98    SCMP_SYS(sendmsg),
  99    SCMP_SYS(setresgid),
 100    SCMP_SYS(setresuid),
 101#ifdef __NR_setresgid32
 102    SCMP_SYS(setresgid32),
 103#endif
 104#ifdef __NR_setresuid32
 105    SCMP_SYS(setresuid32),
 106#endif
 107    SCMP_SYS(set_robust_list),
 108    SCMP_SYS(setxattr),
 109    SCMP_SYS(symlinkat),
 110    SCMP_SYS(time), /* Rarely needed, except on static builds */
 111    SCMP_SYS(tgkill),
 112    SCMP_SYS(unlinkat),
 113    SCMP_SYS(unshare),
 114    SCMP_SYS(utimensat),
 115    SCMP_SYS(write),
 116    SCMP_SYS(writev),
 117};
 118
 119/* Syscalls used when --syslog is enabled */
 120static const int syscall_allowlist_syslog[] = {
 121    SCMP_SYS(send),
 122    SCMP_SYS(sendto),
 123};
 124
 125static void add_allowlist(scmp_filter_ctx ctx, const int syscalls[], size_t len)
 126{
 127    size_t i;
 128
 129    for (i = 0; i < len; i++) {
 130        if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls[i], 0) != 0) {
 131            fuse_log(FUSE_LOG_ERR, "seccomp_rule_add syscall %d failed\n",
 132                     syscalls[i]);
 133            exit(1);
 134        }
 135    }
 136}
 137
 138void setup_seccomp(bool enable_syslog)
 139{
 140    scmp_filter_ctx ctx;
 141
 142#ifdef SCMP_ACT_KILL_PROCESS
 143    ctx = seccomp_init(SCMP_ACT_KILL_PROCESS);
 144    /* Handle a newer libseccomp but an older kernel */
 145    if (!ctx && errno == EOPNOTSUPP) {
 146        ctx = seccomp_init(SCMP_ACT_TRAP);
 147    }
 148#else
 149    ctx = seccomp_init(SCMP_ACT_TRAP);
 150#endif
 151    if (!ctx) {
 152        fuse_log(FUSE_LOG_ERR, "seccomp_init() failed\n");
 153        exit(1);
 154    }
 155
 156    add_allowlist(ctx, syscall_allowlist, G_N_ELEMENTS(syscall_allowlist));
 157    if (enable_syslog) {
 158        add_allowlist(ctx, syscall_allowlist_syslog,
 159                      G_N_ELEMENTS(syscall_allowlist_syslog));
 160    }
 161
 162    /* libvhost-user calls this for post-copy migration, we don't need it */
 163    if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOSYS),
 164                         SCMP_SYS(userfaultfd), 0) != 0) {
 165        fuse_log(FUSE_LOG_ERR, "seccomp_rule_add userfaultfd failed\n");
 166        exit(1);
 167    }
 168
 169    if (seccomp_load(ctx) < 0) {
 170        fuse_log(FUSE_LOG_ERR, "seccomp_load() failed\n");
 171        exit(1);
 172    }
 173
 174    seccomp_release(ctx);
 175}
 176