1 /* $NetBSD: seccomp.c,v 1.1.1.8 2023/08/18 18:36:50 christos Exp $ */
2
3 /*
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice immediately at the beginning of the file, without modification,
9 * this list of conditions, and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26 /*
27 * libseccomp hooks.
28 */
29 #include "file.h"
30
31 #ifndef lint
32 #if 0
33 FILE_RCSID("@(#)$File: seccomp.c,v 1.25 2022/12/26 18:57:29 christos Exp $")
34 #else
35 __RCSID("$NetBSD: seccomp.c,v 1.1.1.8 2023/08/18 18:36:50 christos Exp $");
36 #endif
37 #endif /* lint */
38
39 #if HAVE_LIBSECCOMP
40 #include <seccomp.h> /* libseccomp */
41 #include <sys/prctl.h> /* prctl */
42 #include <sys/ioctl.h>
43 #include <sys/socket.h>
44 #include <termios.h>
45 #include <fcntl.h>
46 #include <stdlib.h>
47 #include <errno.h>
48
49 #define DENY_RULE(call) \
50 do \
51 if (seccomp_rule_add (ctx, SCMP_ACT_KILL, SCMP_SYS(call), 0) == -1) \
52 goto out; \
53 while (/*CONSTCOND*/0)
54 #define ALLOW_RULE(call) \
55 do \
56 if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(call), 0) == -1) \
57 goto out; \
58 while (/*CONSTCOND*/0)
59
60 #define ALLOW_IOCTL_RULE(param) \
61 do \
62 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1, \
63 SCMP_CMP(1, SCMP_CMP_EQ, (scmp_datum_t)param, \
64 (scmp_datum_t)0)) == -1) \
65 goto out; \
66 while (/*CONSTCOND*/0)
67
68 static scmp_filter_ctx ctx;
69
70 int
enable_sandbox_basic(void)71 enable_sandbox_basic(void)
72 {
73
74 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
75 return -1;
76
77 if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1)
78 return -1;
79
80 // initialize the filter
81 ctx = seccomp_init(SCMP_ACT_ALLOW);
82 if (ctx == NULL)
83 return 1;
84
85 DENY_RULE(_sysctl);
86 DENY_RULE(acct);
87 DENY_RULE(add_key);
88 DENY_RULE(adjtimex);
89 DENY_RULE(chroot);
90 DENY_RULE(clock_adjtime);
91 DENY_RULE(create_module);
92 DENY_RULE(delete_module);
93 DENY_RULE(fanotify_init);
94 DENY_RULE(finit_module);
95 DENY_RULE(get_kernel_syms);
96 DENY_RULE(get_mempolicy);
97 DENY_RULE(init_module);
98 DENY_RULE(io_cancel);
99 DENY_RULE(io_destroy);
100 DENY_RULE(io_getevents);
101 DENY_RULE(io_setup);
102 DENY_RULE(io_submit);
103 DENY_RULE(ioperm);
104 DENY_RULE(iopl);
105 DENY_RULE(ioprio_set);
106 DENY_RULE(kcmp);
107 #ifdef __NR_kexec_file_load
108 DENY_RULE(kexec_file_load);
109 #endif
110 DENY_RULE(kexec_load);
111 DENY_RULE(keyctl);
112 DENY_RULE(lookup_dcookie);
113 DENY_RULE(mbind);
114 DENY_RULE(nfsservctl);
115 DENY_RULE(migrate_pages);
116 DENY_RULE(modify_ldt);
117 DENY_RULE(mount);
118 DENY_RULE(move_pages);
119 DENY_RULE(name_to_handle_at);
120 DENY_RULE(open_by_handle_at);
121 DENY_RULE(perf_event_open);
122 DENY_RULE(pivot_root);
123 DENY_RULE(process_vm_readv);
124 DENY_RULE(process_vm_writev);
125 DENY_RULE(ptrace);
126 DENY_RULE(reboot);
127 DENY_RULE(remap_file_pages);
128 DENY_RULE(request_key);
129 DENY_RULE(set_mempolicy);
130 DENY_RULE(swapoff);
131 DENY_RULE(swapon);
132 DENY_RULE(sysfs);
133 DENY_RULE(syslog);
134 DENY_RULE(tuxcall);
135 DENY_RULE(umount2);
136 DENY_RULE(uselib);
137 DENY_RULE(vmsplice);
138
139 // blocking dangerous syscalls that file should not need
140 DENY_RULE (execve);
141 DENY_RULE (socket);
142 // ...
143
144
145 // applying filter...
146 if (seccomp_load (ctx) == -1)
147 goto out;
148 // free ctx after the filter has been loaded into the kernel
149 seccomp_release(ctx);
150 return 0;
151
152 out:
153 seccomp_release(ctx);
154 return -1;
155 }
156
157
158 int
enable_sandbox_full(void)159 enable_sandbox_full(void)
160 {
161
162 // prevent child processes from getting more priv e.g. via setuid,
163 // capabilities, ...
164 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
165 return -1;
166
167 if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1)
168 return -1;
169
170 // initialize the filter
171 ctx = seccomp_init(SCMP_ACT_KILL);
172 if (ctx == NULL)
173 return -1;
174
175 ALLOW_RULE(access);
176 ALLOW_RULE(brk);
177 ALLOW_RULE(close);
178 ALLOW_RULE(dup2);
179 ALLOW_RULE(exit);
180 ALLOW_RULE(exit_group);
181 #ifdef __NR_faccessat
182 ALLOW_RULE(faccessat);
183 #endif
184 ALLOW_RULE(fcntl);
185 ALLOW_RULE(fcntl64);
186 #ifdef __NR_fstat
187 ALLOW_RULE(fstat);
188 #endif
189 ALLOW_RULE(fstat64);
190 #ifdef __NR_fstatat64
191 ALLOW_RULE(fstatat64);
192 #endif
193 ALLOW_RULE(futex);
194 ALLOW_RULE(getdents);
195 #ifdef __NR_getdents64
196 ALLOW_RULE(getdents64);
197 #endif
198 #ifdef FIONREAD
199 // called in src/compress.c under sread
200 ALLOW_IOCTL_RULE(FIONREAD);
201 #endif
202 #ifdef TIOCGWINSZ
203 // musl libc may call ioctl TIOCGWINSZ on stdout
204 ALLOW_IOCTL_RULE(TIOCGWINSZ);
205 #endif
206 #ifdef TCGETS
207 // glibc may call ioctl TCGETS on stdout on physical terminal
208 ALLOW_IOCTL_RULE(TCGETS);
209 #endif
210 ALLOW_RULE(lseek);
211 ALLOW_RULE(_llseek);
212 ALLOW_RULE(lstat);
213 ALLOW_RULE(lstat64);
214 ALLOW_RULE(madvise);
215 ALLOW_RULE(mmap);
216 ALLOW_RULE(mmap2);
217 ALLOW_RULE(mprotect);
218 ALLOW_RULE(mremap);
219 ALLOW_RULE(munmap);
220 #ifdef __NR_newfstatat
221 ALLOW_RULE(newfstatat);
222 #endif
223 ALLOW_RULE(open);
224 ALLOW_RULE(openat);
225 ALLOW_RULE(pread64);
226 ALLOW_RULE(read);
227 ALLOW_RULE(readlink);
228 #ifdef __NR_readlinkat
229 ALLOW_RULE(readlinkat);
230 #endif
231 ALLOW_RULE(rt_sigaction);
232 ALLOW_RULE(rt_sigprocmask);
233 ALLOW_RULE(rt_sigreturn);
234 ALLOW_RULE(select);
235 ALLOW_RULE(stat);
236 ALLOW_RULE(statx);
237 ALLOW_RULE(stat64);
238 ALLOW_RULE(sysinfo);
239 ALLOW_RULE(umask); // Used in file_pipe2file()
240 ALLOW_RULE(getpid); // Used by glibc in file_pipe2file()
241 ALLOW_RULE(unlink);
242 ALLOW_RULE(utimes);
243 ALLOW_RULE(write);
244 ALLOW_RULE(writev);
245
246
247 #if 0
248 // needed by valgrind
249 ALLOW_RULE(gettid);
250 ALLOW_RULE(rt_sigtimedwait);
251 #endif
252
253 #if 0
254 /* special restrictions for socket, only allow AF_UNIX/AF_LOCAL */
255 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
256 SCMP_CMP(0, SCMP_CMP_EQ, AF_UNIX)) == -1)
257 goto out;
258
259 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
260 SCMP_CMP(0, SCMP_CMP_EQ, AF_LOCAL)) == -1)
261 goto out;
262
263
264 /* special restrictions for open, prevent opening files for writing */
265 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1,
266 SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR, 0)) == -1)
267 goto out;
268
269 if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1,
270 SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)) == -1)
271 goto out;
272
273 if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1,
274 SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)) == -1)
275 goto out;
276
277
278 /* allow stderr */
279 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1,
280 SCMP_CMP(0, SCMP_CMP_EQ, 2)) == -1)
281 goto out;
282 #endif
283
284 // applying filter...
285 if (seccomp_load(ctx) == -1)
286 goto out;
287 // free ctx after the filter has been loaded into the kernel
288 seccomp_release(ctx);
289 return 0;
290
291 out:
292 // something went wrong
293 seccomp_release(ctx);
294 return -1;
295 }
296 #endif
297