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     SCMP_SYS(rt_sigaction),
95     SCMP_SYS(rt_sigprocmask),
96     SCMP_SYS(rt_sigreturn),
97     SCMP_SYS(sched_getattr),
98     SCMP_SYS(sched_setattr),
99     SCMP_SYS(sendmsg),
100     SCMP_SYS(setresgid),
101     SCMP_SYS(setresuid),
102 #ifdef __NR_setresgid32
103     SCMP_SYS(setresgid32),
104 #endif
105 #ifdef __NR_setresuid32
106     SCMP_SYS(setresuid32),
107 #endif
108     SCMP_SYS(set_robust_list),
109     SCMP_SYS(setxattr),
110     SCMP_SYS(symlinkat),
111     SCMP_SYS(time), /* Rarely needed, except on static builds */
112     SCMP_SYS(tgkill),
113     SCMP_SYS(unlinkat),
114     SCMP_SYS(unshare),
115     SCMP_SYS(utimensat),
116     SCMP_SYS(write),
117     SCMP_SYS(writev),
118     SCMP_SYS(umask),
119 };
120 
121 /* Syscalls used when --syslog is enabled */
122 static const int syscall_allowlist_syslog[] = {
123     SCMP_SYS(send),
124     SCMP_SYS(sendto),
125 };
126 
add_allowlist(scmp_filter_ctx ctx,const int syscalls[],size_t len)127 static void add_allowlist(scmp_filter_ctx ctx, const int syscalls[], size_t len)
128 {
129     size_t i;
130 
131     for (i = 0; i < len; i++) {
132         if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls[i], 0) != 0) {
133             fuse_log(FUSE_LOG_ERR, "seccomp_rule_add syscall %d failed\n",
134                      syscalls[i]);
135             exit(1);
136         }
137     }
138 }
139 
setup_seccomp(bool enable_syslog)140 void setup_seccomp(bool enable_syslog)
141 {
142     scmp_filter_ctx ctx;
143 
144 #ifdef SCMP_ACT_KILL_PROCESS
145     ctx = seccomp_init(SCMP_ACT_KILL_PROCESS);
146     /* Handle a newer libseccomp but an older kernel */
147     if (!ctx && errno == EOPNOTSUPP) {
148         ctx = seccomp_init(SCMP_ACT_TRAP);
149     }
150 #else
151     ctx = seccomp_init(SCMP_ACT_TRAP);
152 #endif
153     if (!ctx) {
154         fuse_log(FUSE_LOG_ERR, "seccomp_init() failed\n");
155         exit(1);
156     }
157 
158     add_allowlist(ctx, syscall_allowlist, G_N_ELEMENTS(syscall_allowlist));
159     if (enable_syslog) {
160         add_allowlist(ctx, syscall_allowlist_syslog,
161                       G_N_ELEMENTS(syscall_allowlist_syslog));
162     }
163 
164     /* libvhost-user calls this for post-copy migration, we don't need it */
165     if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOSYS),
166                          SCMP_SYS(userfaultfd), 0) != 0) {
167         fuse_log(FUSE_LOG_ERR, "seccomp_rule_add userfaultfd failed\n");
168         exit(1);
169     }
170 
171     if (seccomp_load(ctx) < 0) {
172         fuse_log(FUSE_LOG_ERR, "seccomp_load() failed\n");
173         exit(1);
174     }
175 
176     seccomp_release(ctx);
177 }
178