passthrough_seccomp.c (4522B)
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 24 static 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(fstatfs64), 55 SCMP_SYS(fsync), 56 SCMP_SYS(ftruncate), 57 SCMP_SYS(futex), 58 SCMP_SYS(getdents), 59 SCMP_SYS(getdents64), 60 SCMP_SYS(getegid), 61 SCMP_SYS(geteuid), 62 SCMP_SYS(getpid), 63 SCMP_SYS(gettid), 64 SCMP_SYS(gettimeofday), 65 SCMP_SYS(getxattr), 66 SCMP_SYS(linkat), 67 SCMP_SYS(listxattr), 68 SCMP_SYS(lseek), 69 SCMP_SYS(_llseek), /* For POWER */ 70 SCMP_SYS(madvise), 71 SCMP_SYS(mkdirat), 72 SCMP_SYS(mknodat), 73 SCMP_SYS(mmap), 74 SCMP_SYS(mprotect), 75 SCMP_SYS(mremap), 76 SCMP_SYS(munmap), 77 SCMP_SYS(newfstatat), 78 SCMP_SYS(statx), 79 SCMP_SYS(open), 80 SCMP_SYS(openat), 81 SCMP_SYS(ppoll), 82 SCMP_SYS(prctl), /* TODO restrict to just PR_SET_NAME? */ 83 SCMP_SYS(preadv), 84 SCMP_SYS(pread64), 85 SCMP_SYS(pwritev), 86 SCMP_SYS(pwrite64), 87 SCMP_SYS(read), 88 SCMP_SYS(readlinkat), 89 SCMP_SYS(recvmsg), 90 SCMP_SYS(renameat), 91 SCMP_SYS(renameat2), 92 SCMP_SYS(removexattr), 93 SCMP_SYS(restart_syscall), 94 #ifdef __NR_rseq 95 SCMP_SYS(rseq), /* required since glibc 2.35 */ 96 #endif 97 SCMP_SYS(rt_sigaction), 98 SCMP_SYS(rt_sigprocmask), 99 SCMP_SYS(rt_sigreturn), 100 SCMP_SYS(sched_getattr), 101 SCMP_SYS(sched_setattr), 102 SCMP_SYS(sendmsg), 103 SCMP_SYS(setresgid), 104 SCMP_SYS(setresuid), 105 #ifdef __NR_setresgid32 106 SCMP_SYS(setresgid32), 107 #endif 108 #ifdef __NR_setresuid32 109 SCMP_SYS(setresuid32), 110 #endif 111 SCMP_SYS(set_robust_list), 112 SCMP_SYS(setxattr), 113 SCMP_SYS(sigreturn), 114 SCMP_SYS(symlinkat), 115 SCMP_SYS(syncfs), 116 SCMP_SYS(time), /* Rarely needed, except on static builds */ 117 SCMP_SYS(tgkill), 118 SCMP_SYS(unlinkat), 119 SCMP_SYS(unshare), 120 SCMP_SYS(utimensat), 121 SCMP_SYS(write), 122 SCMP_SYS(writev), 123 SCMP_SYS(umask), 124 }; 125 126 /* Syscalls used when --syslog is enabled */ 127 static const int syscall_allowlist_syslog[] = { 128 SCMP_SYS(send), 129 SCMP_SYS(sendto), 130 }; 131 132 static void add_allowlist(scmp_filter_ctx ctx, const int syscalls[], size_t len) 133 { 134 size_t i; 135 136 for (i = 0; i < len; i++) { 137 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls[i], 0) != 0) { 138 fuse_log(FUSE_LOG_ERR, "seccomp_rule_add syscall %d failed\n", 139 syscalls[i]); 140 exit(1); 141 } 142 } 143 } 144 145 void setup_seccomp(bool enable_syslog) 146 { 147 scmp_filter_ctx ctx; 148 149 #ifdef SCMP_ACT_KILL_PROCESS 150 ctx = seccomp_init(SCMP_ACT_KILL_PROCESS); 151 /* Handle a newer libseccomp but an older kernel */ 152 if (!ctx && errno == EOPNOTSUPP) { 153 ctx = seccomp_init(SCMP_ACT_TRAP); 154 } 155 #else 156 ctx = seccomp_init(SCMP_ACT_TRAP); 157 #endif 158 if (!ctx) { 159 fuse_log(FUSE_LOG_ERR, "seccomp_init() failed\n"); 160 exit(1); 161 } 162 163 add_allowlist(ctx, syscall_allowlist, G_N_ELEMENTS(syscall_allowlist)); 164 if (enable_syslog) { 165 add_allowlist(ctx, syscall_allowlist_syslog, 166 G_N_ELEMENTS(syscall_allowlist_syslog)); 167 } 168 169 /* libvhost-user calls this for post-copy migration, we don't need it */ 170 if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOSYS), 171 SCMP_SYS(userfaultfd), 0) != 0) { 172 fuse_log(FUSE_LOG_ERR, "seccomp_rule_add userfaultfd failed\n"); 173 exit(1); 174 } 175 176 if (seccomp_load(ctx) < 0) { 177 fuse_log(FUSE_LOG_ERR, "seccomp_load() failed\n"); 178 exit(1); 179 } 180 181 seccomp_release(ctx); 182 }