Merge branch 'maint-0.4.6' into maint-0.4.7
[tor.git] / src / lib / sandbox / sandbox.c
blobcc00d2048faec22539dcd5633b9d81db3bdd261f
1 /* Copyright (c) 2001 Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2021, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
7 /**
8 * \file sandbox.c
9 * \brief Code to enable sandboxing.
10 **/
12 #include "orconfig.h"
14 #ifndef _LARGEFILE64_SOURCE
15 /**
16 * Temporarily required for O_LARGEFILE flag. Needs to be removed
17 * with the libevent fix.
19 #define _LARGEFILE64_SOURCE
20 #endif /* !defined(_LARGEFILE64_SOURCE) */
22 /** Malloc mprotect limit in bytes.
24 * 28/06/2017: This value was increased from 16 MB to 20 MB after we introduced
25 * LZMA support in Tor (0.3.1.1-alpha). We limit our LZMA coder to 16 MB, but
26 * liblzma have a small overhead that we need to compensate for to avoid being
27 * killed by the sandbox.
29 #define MALLOC_MP_LIM (20*1024*1024)
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <errno.h>
36 #include "lib/sandbox/sandbox.h"
37 #include "lib/container/map.h"
38 #include "lib/err/torerr.h"
39 #include "lib/log/log.h"
40 #include "lib/cc/torint.h"
41 #include "lib/malloc/malloc.h"
42 #include "lib/string/scanf.h"
44 #include "ext/tor_queue.h"
45 #include "ext/ht.h"
46 #include "ext/siphash.h"
48 #define DEBUGGING_CLOSE
50 #if defined(USE_LIBSECCOMP)
52 #include <sys/mman.h>
53 #include <sys/syscall.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <sys/epoll.h>
57 #include <sys/prctl.h>
58 #include <linux/futex.h>
59 #include <sys/file.h>
61 #ifdef ENABLE_FRAGILE_HARDENING
62 #include <sys/ptrace.h>
63 #endif
65 #include <stdarg.h>
66 #include <seccomp.h>
67 #include <signal.h>
68 #include <unistd.h>
69 #include <fcntl.h>
70 #include <time.h>
71 #include <poll.h>
73 #ifdef HAVE_GNU_LIBC_VERSION_H
74 #include <gnu/libc-version.h>
75 #endif
76 #ifdef HAVE_LINUX_NETFILTER_IPV4_H
77 #include <linux/netfilter_ipv4.h>
78 #endif
79 #ifdef HAVE_LINUX_IF_H
80 #include <linux/if.h>
81 #endif
82 #ifdef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H
83 #include <linux/netfilter_ipv6/ip6_tables.h>
84 #endif
86 #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
87 defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
88 #define USE_BACKTRACE
89 #define BACKTRACE_PRIVATE
90 #include "lib/err/backtrace.h"
91 #endif /* defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && ... */
93 #ifdef USE_BACKTRACE
94 #include <execinfo.h>
95 #endif
97 /**
98 * Linux 32 bit definitions
100 #if defined(__i386__)
102 #define REG_SYSCALL REG_EAX
103 #define M_SYSCALL gregs[REG_SYSCALL]
106 * Linux 64 bit definitions
108 #elif defined(__x86_64__)
110 #define REG_SYSCALL REG_RAX
111 #define M_SYSCALL gregs[REG_SYSCALL]
113 #elif defined(__arm__)
115 #define M_SYSCALL arm_r7
117 #elif defined(__aarch64__) && defined(__LP64__)
119 #define REG_SYSCALL 8
120 #define M_SYSCALL regs[REG_SYSCALL]
122 #endif /* defined(__i386__) || ... */
124 #ifdef M_SYSCALL
125 #define SYSCALL_NAME_DEBUGGING
126 #endif
128 /**Determines if at least one sandbox is active.*/
129 static int sandbox_active = 0;
130 /** Holds the parameter list configuration for the sandbox.*/
131 static sandbox_cfg_t *filter_dynamic = NULL;
133 #undef SCMP_CMP
134 #define SCMP_CMP(a,b,c) ((struct scmp_arg_cmp){(a),(b),(c),0})
135 #define SCMP_CMP_STR(a,b,c) \
136 ((struct scmp_arg_cmp) {(a),(b),(intptr_t)(void*)(c),0})
137 #define SCMP_CMP4(a,b,c,d) ((struct scmp_arg_cmp){(a),(b),(c),(d)})
138 /* We use a wrapper here because these masked comparisons seem to be pretty
139 * verbose. Also, it's important to cast to scmp_datum_t before negating the
140 * mask, since otherwise the negation might get applied to a 32 bit value, and
141 * the high bits of the value might get masked out improperly. */
142 #define SCMP_CMP_MASKED(a,b,c) \
143 SCMP_CMP4((a), SCMP_CMP_MASKED_EQ, ~(scmp_datum_t)(b), (c))
144 /* For negative constants, the rule to add depends on the glibc version. */
145 #define SCMP_CMP_NEG(a,op,b) (libc_negative_constant_needs_cast() ? \
146 (SCMP_CMP((a), (op), (unsigned int)(b))) : \
147 (SCMP_CMP_STR((a), (op), (b))))
149 /** Variable used for storing all syscall numbers that will be allowed with the
150 * stage 1 general Tor sandbox.
152 static int filter_nopar_gen[] = {
153 SCMP_SYS(access),
154 SCMP_SYS(brk),
155 #ifdef __NR_clock_gettime64
156 SCMP_SYS(clock_gettime64),
157 #else
158 SCMP_SYS(clock_gettime),
159 #endif
160 SCMP_SYS(close),
161 SCMP_SYS(clone),
162 SCMP_SYS(dup),
163 #ifdef __NR_clone3
164 SCMP_SYS(clone3),
165 #endif
166 SCMP_SYS(epoll_create),
167 SCMP_SYS(epoll_wait),
168 #ifdef __NR_epoll_pwait
169 SCMP_SYS(epoll_pwait),
170 #endif
171 #ifdef HAVE_EVENTFD
172 SCMP_SYS(eventfd2),
173 #endif
174 #ifdef HAVE_PIPE2
175 SCMP_SYS(pipe2),
176 #endif
177 #ifdef HAVE_PIPE
178 SCMP_SYS(pipe),
179 #endif
180 #ifdef __NR_fchmod
181 SCMP_SYS(fchmod),
182 #endif
183 SCMP_SYS(fcntl),
184 SCMP_SYS(fstat),
185 #ifdef __NR_fstat64
186 SCMP_SYS(fstat64),
187 #endif
188 SCMP_SYS(fsync),
189 SCMP_SYS(futex),
190 SCMP_SYS(getdents),
191 SCMP_SYS(getdents64),
192 SCMP_SYS(getegid),
193 #ifdef __NR_getegid32
194 SCMP_SYS(getegid32),
195 #endif
196 SCMP_SYS(geteuid),
197 #ifdef __NR_geteuid32
198 SCMP_SYS(geteuid32),
199 #endif
200 SCMP_SYS(getgid),
201 #ifdef __NR_getgid32
202 SCMP_SYS(getgid32),
203 #endif
204 SCMP_SYS(getpid),
205 #ifdef ENABLE_FRAGILE_HARDENING
206 SCMP_SYS(getppid),
207 #endif
208 #ifdef __NR_getrlimit
209 SCMP_SYS(getrlimit),
210 #endif
211 SCMP_SYS(gettimeofday),
212 SCMP_SYS(gettid),
213 SCMP_SYS(getuid),
214 #ifdef __NR_getuid32
215 SCMP_SYS(getuid32),
216 #endif
217 SCMP_SYS(lseek),
218 #ifdef __NR__llseek
219 SCMP_SYS(_llseek),
220 #endif
221 // glob uses this..
222 SCMP_SYS(lstat),
223 SCMP_SYS(mkdir),
224 SCMP_SYS(mlockall),
225 #ifdef __NR_mmap
226 /* XXXX restrict this in the same ways as mmap2 */
227 SCMP_SYS(mmap),
228 #endif
229 SCMP_SYS(munmap),
230 #ifdef __NR_nanosleep
231 SCMP_SYS(nanosleep),
232 #endif
233 #ifdef __NR_prlimit
234 SCMP_SYS(prlimit),
235 #endif
236 #ifdef __NR_prlimit64
237 SCMP_SYS(prlimit64),
238 #endif
239 SCMP_SYS(read),
240 SCMP_SYS(rt_sigreturn),
241 #ifdef __NR_rseq
242 SCMP_SYS(rseq),
243 #endif
244 SCMP_SYS(sched_getaffinity),
245 #ifdef __NR_sched_yield
246 SCMP_SYS(sched_yield),
247 #endif
248 SCMP_SYS(sendmsg),
249 SCMP_SYS(set_robust_list),
250 #ifdef __NR_setrlimit
251 SCMP_SYS(setrlimit),
252 #endif
253 SCMP_SYS(shutdown),
254 #ifdef __NR_sigaltstack
255 SCMP_SYS(sigaltstack),
256 #endif
257 #ifdef __NR_sigreturn
258 SCMP_SYS(sigreturn),
259 #endif
260 SCMP_SYS(stat),
261 #if defined(__i386__) && defined(__NR_statx)
262 SCMP_SYS(statx),
263 #endif
264 SCMP_SYS(uname),
265 SCMP_SYS(wait4),
266 SCMP_SYS(write),
267 SCMP_SYS(writev),
268 SCMP_SYS(exit_group),
269 SCMP_SYS(exit),
271 SCMP_SYS(madvise),
272 #ifdef __NR_stat64
273 // getaddrinfo uses this..
274 SCMP_SYS(stat64),
275 #endif
277 #ifdef __NR_getrandom
278 SCMP_SYS(getrandom),
279 #endif
281 #ifdef __NR_sysinfo
282 // qsort uses this..
283 SCMP_SYS(sysinfo),
284 #endif
286 * These socket syscalls are not required on x86_64 and not supported with
287 * some libseccomp versions (eg: 1.0.1)
289 #if defined(__i386)
290 SCMP_SYS(recv),
291 SCMP_SYS(send),
292 #endif
294 // socket syscalls
295 SCMP_SYS(bind),
296 SCMP_SYS(listen),
297 SCMP_SYS(connect),
298 SCMP_SYS(getsockname),
299 #ifdef ENABLE_NSS
300 #ifdef __NR_getpeername
301 SCMP_SYS(getpeername),
302 #endif
303 #endif
304 SCMP_SYS(recvmsg),
305 SCMP_SYS(recvfrom),
306 SCMP_SYS(sendto),
307 SCMP_SYS(unlink),
308 #ifdef __NR_unlinkat
309 SCMP_SYS(unlinkat),
310 #endif
311 SCMP_SYS(poll)
314 /* opendir is not a syscall but it will use either open or openat. We do not
315 * want the decision to allow open/openat to be the callers reponsability, so
316 * we create a phony syscall number for opendir and sb_opendir will choose the
317 * correct syscall. */
318 #define PHONY_OPENDIR_SYSCALL -2
320 /* These macros help avoid the error where the number of filters we add on a
321 * single rule don't match the arg_cnt param. */
322 #define seccomp_rule_add_0(ctx,act,call) \
323 seccomp_rule_add((ctx),(act),(call),0)
324 #define seccomp_rule_add_1(ctx,act,call,f1) \
325 seccomp_rule_add((ctx),(act),(call),1,(f1))
326 #define seccomp_rule_add_2(ctx,act,call,f1,f2) \
327 seccomp_rule_add((ctx),(act),(call),2,(f1),(f2))
328 #define seccomp_rule_add_3(ctx,act,call,f1,f2,f3) \
329 seccomp_rule_add((ctx),(act),(call),3,(f1),(f2),(f3))
330 #define seccomp_rule_add_4(ctx,act,call,f1,f2,f3,f4) \
331 seccomp_rule_add((ctx),(act),(call),4,(f1),(f2),(f3),(f4))
333 static const char *sandbox_get_interned_string(const char *str);
336 * Function responsible for setting up the rt_sigaction syscall for
337 * the seccomp filter sandbox.
339 static int
340 sb_rt_sigaction(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
342 unsigned i;
343 int rc;
344 int param[] = { SIGINT, SIGTERM, SIGPIPE, SIGUSR1, SIGUSR2, SIGHUP, SIGCHLD,
345 SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS, SIGIO,
346 #ifdef SIGXFSZ
347 SIGXFSZ
348 #endif
350 (void) filter;
352 for (i = 0; i < ARRAY_LENGTH(param); i++) {
353 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction),
354 SCMP_CMP(0, SCMP_CMP_EQ, param[i]));
355 if (rc)
356 break;
359 return rc;
362 #ifdef __NR_time
364 * Function responsible for setting up the time syscall for
365 * the seccomp filter sandbox.
367 static int
368 sb_time(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
370 (void) filter;
372 return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(time),
373 SCMP_CMP(0, SCMP_CMP_EQ, 0));
375 #endif /* defined(__NR_time) */
378 * Function responsible for setting up the accept4 syscall for
379 * the seccomp filter sandbox.
381 static int
382 sb_accept4(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
384 int rc = 0;
385 (void)filter;
387 #ifdef __i386__
388 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketcall),
389 SCMP_CMP(0, SCMP_CMP_EQ, 18));
390 if (rc) {
391 return rc;
393 #endif /* defined(__i386__) */
395 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept4),
396 SCMP_CMP_MASKED(3, SOCK_CLOEXEC|SOCK_NONBLOCK, 0));
397 if (rc) {
398 return rc;
401 return 0;
404 #ifdef __NR_mmap2
406 * Function responsible for setting up the mmap2 syscall for
407 * the seccomp filter sandbox.
409 static int
410 sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
412 int rc = 0;
413 (void)filter;
415 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
416 SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ),
417 SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE));
418 if (rc) {
419 return rc;
422 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
423 SCMP_CMP(2, SCMP_CMP_EQ, PROT_NONE),
424 SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE));
425 if (rc) {
426 return rc;
429 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
430 SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
431 SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS));
432 if (rc) {
433 return rc;
436 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
437 SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
438 SCMP_CMP(3, SCMP_CMP_EQ,MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK));
439 if (rc) {
440 return rc;
443 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
444 SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
445 SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE));
446 if (rc) {
447 return rc;
450 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
451 SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
452 SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS));
453 if (rc) {
454 return rc;
457 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
458 SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_EXEC),
459 SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_DENYWRITE));
460 if (rc) {
461 return rc;
464 return 0;
466 #endif /* defined(__NR_mmap2) */
468 #ifdef HAVE_GNU_LIBC_VERSION_H
469 #ifdef HAVE_GNU_GET_LIBC_VERSION
470 #define CHECK_LIBC_VERSION
471 #endif
472 #endif
474 /* Return true the libc version is greater or equal than
475 * <b>major</b>.<b>minor</b>. Returns false otherwise. */
476 static int
477 is_libc_at_least(int major, int minor)
479 #ifdef CHECK_LIBC_VERSION
480 const char *version = gnu_get_libc_version();
481 if (version == NULL)
482 return 0;
484 int libc_major = -1;
485 int libc_minor = -1;
487 tor_sscanf(version, "%d.%d", &libc_major, &libc_minor);
488 if (libc_major > major)
489 return 1;
490 else if (libc_major == major && libc_minor >= minor)
491 return 1;
492 else
493 return 0;
494 #else /* !defined(CHECK_LIBC_VERSION) */
495 (void)major;
496 (void)minor;
497 return 0;
498 #endif /* defined(CHECK_LIBC_VERSION) */
501 /* Return true if we think we're running with a libc that uses openat for the
502 * open function on linux. */
503 static int
504 libc_uses_openat_for_open(void)
506 return is_libc_at_least(2, 26);
509 /* Return true if we think we're running with a libc that uses openat for the
510 * opendir function on linux. */
511 static int
512 libc_uses_openat_for_opendir(void)
514 // libc 2.27 and above or between 2.15 (inclusive) and 2.22 (exclusive)
515 return is_libc_at_least(2, 27) ||
516 (is_libc_at_least(2, 15) && !is_libc_at_least(2, 22));
519 /* Return true if we think we're running with a libc that needs to cast
520 * negative arguments like AT_FDCWD for seccomp rules. */
521 static int
522 libc_negative_constant_needs_cast(void)
524 return is_libc_at_least(2, 27);
527 /** Allow a single file to be opened. If <b>use_openat</b> is true,
528 * we're using a libc that remaps all the opens into openats. */
529 static int
530 allow_file_open(scmp_filter_ctx ctx, int use_openat, const char *file)
532 if (use_openat) {
533 return seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat),
534 SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD),
535 SCMP_CMP_STR(1, SCMP_CMP_EQ, file));
536 } else {
537 return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open),
538 SCMP_CMP_STR(0, SCMP_CMP_EQ, file));
543 * Function responsible for setting up the open syscall for
544 * the seccomp filter sandbox.
546 static int
547 sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
549 int rc;
550 sandbox_cfg_t *elem = NULL;
552 int use_openat = libc_uses_openat_for_open();
554 #ifdef ENABLE_FRAGILE_HARDENING
555 /* AddressSanitizer uses the "open" syscall to access information about the
556 * running process via the filesystem, so that call must be allowed without
557 * restriction or the sanitizer will be unable to execute normally when the
558 * process terminates. */
559 rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open));
560 if (rc != 0) {
561 log_err(LD_BUG,"(Sandbox) failed to add open syscall, received "
562 "libseccomp error %d", rc);
563 return rc;
566 /* If glibc also uses only the "open" syscall to open files on this system
567 * there is no need to consider any additional rules. */
568 if (!use_openat)
569 return 0;
570 #endif
572 // for each dynamic parameter filters
573 for (elem = filter; elem != NULL; elem = elem->next) {
574 smp_param_t *param = elem->param;
576 if (param != NULL && param->prot == 1 && param->syscall
577 == SCMP_SYS(open)) {
578 rc = allow_file_open(ctx, use_openat, param->value);
579 if (rc != 0) {
580 log_err(LD_BUG,"(Sandbox) failed to add open syscall, received "
581 "libseccomp error %d", rc);
582 return rc;
587 return 0;
590 static int
591 sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
593 int rc;
594 sandbox_cfg_t *elem = NULL;
596 // for each dynamic parameter filters
597 for (elem = filter; elem != NULL; elem = elem->next) {
598 smp_param_t *param = elem->param;
600 if (param != NULL && param->prot == 1 && param->syscall
601 == SCMP_SYS(chmod)) {
602 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chmod),
603 SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
604 if (rc != 0) {
605 log_err(LD_BUG,"(Sandbox) failed to add chmod syscall, received "
606 "libseccomp error %d", rc);
607 return rc;
612 return 0;
615 #ifdef __i386__
616 static int
617 sb_chown32(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
619 int rc;
620 sandbox_cfg_t *elem = NULL;
622 // for each dynamic parameter filters
623 for (elem = filter; elem != NULL; elem = elem->next) {
624 smp_param_t *param = elem->param;
626 if (param != NULL && param->prot == 1 && param->syscall
627 == SCMP_SYS(chown32)) {
628 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chown32),
629 SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
630 if (rc != 0) {
631 log_err(LD_BUG,"(Sandbox) failed to add chown32 syscall, received "
632 "libseccomp error %d", rc);
633 return rc;
638 return 0;
640 #else
641 static int
642 sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
644 int rc;
645 sandbox_cfg_t *elem = NULL;
647 // for each dynamic parameter filters
648 for (elem = filter; elem != NULL; elem = elem->next) {
649 smp_param_t *param = elem->param;
651 if (param != NULL && param->prot == 1 && param->syscall
652 == SCMP_SYS(chown)) {
653 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chown),
654 SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
655 if (rc != 0) {
656 log_err(LD_BUG,"(Sandbox) failed to add chown syscall, received "
657 "libseccomp error %d", rc);
658 return rc;
663 return 0;
665 #endif /* defined(__i386__) */
668 * Function responsible for setting up the rename syscall for
669 * the seccomp filter sandbox.
671 static int
672 sb_rename(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
674 int rc;
675 sandbox_cfg_t *elem = NULL;
677 // for each dynamic parameter filters
678 for (elem = filter; elem != NULL; elem = elem->next) {
679 smp_param_t *param = elem->param;
681 if (param != NULL && param->prot == 1 &&
682 param->syscall == SCMP_SYS(rename)) {
684 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rename),
685 SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value),
686 SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value2));
687 if (rc != 0) {
688 log_err(LD_BUG,"(Sandbox) failed to add rename syscall, received "
689 "libseccomp error %d", rc);
690 return rc;
695 return 0;
699 * Function responsible for setting up the openat syscall for
700 * the seccomp filter sandbox.
702 static int
703 sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
705 int rc;
706 sandbox_cfg_t *elem = NULL;
708 // for each dynamic parameter filters
709 for (elem = filter; elem != NULL; elem = elem->next) {
710 smp_param_t *param = elem->param;
712 if (param != NULL && param->prot == 1 && param->syscall
713 == SCMP_SYS(openat)) {
714 rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat),
715 SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD),
716 SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value),
717 SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|
718 O_CLOEXEC));
719 if (rc != 0) {
720 log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received "
721 "libseccomp error %d", rc);
722 return rc;
727 return 0;
730 static int
731 sb_opendir(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
733 int rc;
734 sandbox_cfg_t *elem = NULL;
736 // for each dynamic parameter filters
737 for (elem = filter; elem != NULL; elem = elem->next) {
738 smp_param_t *param = elem->param;
740 if (param != NULL && param->prot == 1 && param->syscall
741 == PHONY_OPENDIR_SYSCALL) {
742 rc = allow_file_open(ctx, libc_uses_openat_for_opendir(), param->value);
743 if (rc != 0) {
744 log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received "
745 "libseccomp error %d", rc);
746 return rc;
751 return 0;
754 #ifdef ENABLE_FRAGILE_HARDENING
756 * Function responsible for setting up the ptrace syscall for
757 * the seccomp filter sandbox.
759 static int
760 sb_ptrace(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
762 int rc;
763 pid_t pid = getpid();
764 (void) filter;
766 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ptrace),
767 SCMP_CMP(0, SCMP_CMP_EQ, PTRACE_ATTACH),
768 SCMP_CMP(1, SCMP_CMP_EQ, pid));
769 if (rc)
770 return rc;
772 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ptrace),
773 SCMP_CMP(0, SCMP_CMP_EQ, PTRACE_GETREGS),
774 SCMP_CMP(1, SCMP_CMP_EQ, pid));
775 if (rc)
776 return rc;
778 return 0;
780 #endif
783 * Function responsible for setting up the socket syscall for
784 * the seccomp filter sandbox.
786 static int
787 sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
789 int rc = 0;
790 int i, j;
791 (void) filter;
793 #ifdef __i386__
794 rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket));
795 if (rc)
796 return rc;
797 #endif
799 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
800 SCMP_CMP(0, SCMP_CMP_EQ, PF_FILE),
801 SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_STREAM));
802 if (rc)
803 return rc;
805 for (i = 0; i < 2; ++i) {
806 const int pf = i ? PF_INET : PF_INET6;
807 for (j=0; j < 3; ++j) {
808 const int type = (j == 0) ? SOCK_STREAM :
809 SOCK_DGRAM;
810 const int protocol = (j == 0) ? IPPROTO_TCP :
811 (j == 1) ? IPPROTO_IP :
812 IPPROTO_UDP;
813 rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
814 SCMP_CMP(0, SCMP_CMP_EQ, pf),
815 SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, type),
816 SCMP_CMP(2, SCMP_CMP_EQ, protocol));
817 if (rc)
818 return rc;
822 #ifdef ENABLE_NSS
823 rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
824 SCMP_CMP(0, SCMP_CMP_EQ, PF_INET),
825 SCMP_CMP(1, SCMP_CMP_EQ, SOCK_STREAM),
826 SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_IP));
827 if (rc)
828 return rc;
829 #endif /* defined(ENABLE_NSS) */
831 rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
832 SCMP_CMP(0, SCMP_CMP_EQ, PF_UNIX),
833 SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_STREAM),
834 SCMP_CMP(2, SCMP_CMP_EQ, 0));
835 if (rc)
836 return rc;
838 rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
839 SCMP_CMP(0, SCMP_CMP_EQ, PF_UNIX),
840 SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_DGRAM),
841 SCMP_CMP(2, SCMP_CMP_EQ, 0));
842 if (rc)
843 return rc;
845 rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
846 SCMP_CMP(0, SCMP_CMP_EQ, PF_NETLINK),
847 SCMP_CMP_MASKED(1, SOCK_CLOEXEC, SOCK_RAW),
848 SCMP_CMP(2, SCMP_CMP_EQ, 0));
849 if (rc)
850 return rc;
852 return 0;
856 * Function responsible for setting up the socketpair syscall for
857 * the seccomp filter sandbox.
859 static int
860 sb_socketpair(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
862 int rc = 0;
863 (void) filter;
865 #ifdef __i386__
866 rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketpair));
867 if (rc)
868 return rc;
869 #endif
871 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketpair),
872 SCMP_CMP(0, SCMP_CMP_EQ, PF_FILE),
873 SCMP_CMP(1, SCMP_CMP_EQ, SOCK_STREAM|SOCK_CLOEXEC));
874 if (rc)
875 return rc;
877 return 0;
880 #ifdef HAVE_KIST_SUPPORT
882 #include <linux/sockios.h>
884 static int
885 sb_ioctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
887 int rc;
888 (void) filter;
890 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl),
891 SCMP_CMP(1, SCMP_CMP_EQ, SIOCOUTQNSD));
892 if (rc)
893 return rc;
894 return 0;
897 #endif /* defined(HAVE_KIST_SUPPORT) */
900 * Function responsible for setting up the setsockopt syscall for
901 * the seccomp filter sandbox.
903 static int
904 sb_setsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
906 int rc = 0;
907 (void) filter;
909 #ifdef __i386__
910 rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt));
911 if (rc)
912 return rc;
913 #endif
915 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
916 SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
917 SCMP_CMP(2, SCMP_CMP_EQ, SO_REUSEADDR));
918 if (rc)
919 return rc;
921 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
922 SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
923 SCMP_CMP(2, SCMP_CMP_EQ, SO_SNDBUF));
924 if (rc)
925 return rc;
927 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
928 SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
929 SCMP_CMP(2, SCMP_CMP_EQ, SO_RCVBUF));
930 if (rc)
931 return rc;
933 #ifdef HAVE_SYSTEMD
934 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
935 SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
936 SCMP_CMP(2, SCMP_CMP_EQ, SO_SNDBUFFORCE));
937 if (rc)
938 return rc;
939 #endif /* defined(HAVE_SYSTEMD) */
941 #ifdef IP_TRANSPARENT
942 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
943 SCMP_CMP(1, SCMP_CMP_EQ, SOL_IP),
944 SCMP_CMP(2, SCMP_CMP_EQ, IP_TRANSPARENT));
945 if (rc)
946 return rc;
947 #endif /* defined(IP_TRANSPARENT) */
949 #ifdef IPV6_V6ONLY
950 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
951 SCMP_CMP(1, SCMP_CMP_EQ, IPPROTO_IPV6),
952 SCMP_CMP(2, SCMP_CMP_EQ, IPV6_V6ONLY));
953 if (rc)
954 return rc;
955 #endif /* defined(IPV6_V6ONLY) */
957 return 0;
961 * Function responsible for setting up the getsockopt syscall for
962 * the seccomp filter sandbox.
964 static int
965 sb_getsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
967 int rc = 0;
968 (void) filter;
970 #ifdef __i386__
971 rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt));
972 if (rc)
973 return rc;
974 #endif
976 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
977 SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
978 SCMP_CMP(2, SCMP_CMP_EQ, SO_ERROR));
979 if (rc)
980 return rc;
982 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
983 SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
984 SCMP_CMP(2, SCMP_CMP_EQ, SO_ACCEPTCONN));
985 if (rc)
986 return rc;
988 #ifdef HAVE_SYSTEMD
989 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
990 SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
991 SCMP_CMP(2, SCMP_CMP_EQ, SO_SNDBUF));
992 if (rc)
993 return rc;
994 #endif /* defined(HAVE_SYSTEMD) */
996 #ifdef HAVE_LINUX_NETFILTER_IPV4_H
997 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
998 SCMP_CMP(1, SCMP_CMP_EQ, SOL_IP),
999 SCMP_CMP(2, SCMP_CMP_EQ, SO_ORIGINAL_DST));
1000 if (rc)
1001 return rc;
1002 #endif /* defined(HAVE_LINUX_NETFILTER_IPV4_H) */
1004 #ifdef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H
1005 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
1006 SCMP_CMP(1, SCMP_CMP_EQ, SOL_IPV6),
1007 SCMP_CMP(2, SCMP_CMP_EQ, IP6T_SO_ORIGINAL_DST));
1008 if (rc)
1009 return rc;
1010 #endif /* defined(HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H) */
1012 #ifdef HAVE_KIST_SUPPORT
1013 #include <netinet/tcp.h>
1014 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
1015 SCMP_CMP(1, SCMP_CMP_EQ, SOL_TCP),
1016 SCMP_CMP(2, SCMP_CMP_EQ, TCP_INFO));
1017 if (rc)
1018 return rc;
1019 #endif /* defined(HAVE_KIST_SUPPORT) */
1021 return 0;
1024 #ifdef __NR_fcntl64
1026 * Function responsible for setting up the fcntl64 syscall for
1027 * the seccomp filter sandbox.
1029 static int
1030 sb_fcntl64(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
1032 int rc = 0;
1033 (void) filter;
1035 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64),
1036 SCMP_CMP(1, SCMP_CMP_EQ, F_GETFL));
1037 if (rc)
1038 return rc;
1040 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64),
1041 SCMP_CMP(1, SCMP_CMP_EQ, F_SETFL),
1042 SCMP_CMP(2, SCMP_CMP_EQ, O_RDWR|O_NONBLOCK));
1043 if (rc)
1044 return rc;
1046 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64),
1047 SCMP_CMP(1, SCMP_CMP_EQ, F_GETFD));
1048 if (rc)
1049 return rc;
1051 rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64),
1052 SCMP_CMP(1, SCMP_CMP_EQ, F_SETFD),
1053 SCMP_CMP(2, SCMP_CMP_EQ, FD_CLOEXEC));
1054 if (rc)
1055 return rc;
1057 return 0;
1059 #endif /* defined(__NR_fcntl64) */
1062 * Function responsible for setting up the epoll_ctl syscall for
1063 * the seccomp filter sandbox.
1065 * Note: basically allows everything but will keep for now..
1067 static int
1068 sb_epoll_ctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
1070 int rc = 0;
1071 (void) filter;
1073 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl),
1074 SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_ADD));
1075 if (rc)
1076 return rc;
1078 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl),
1079 SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_MOD));
1080 if (rc)
1081 return rc;
1083 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl),
1084 SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_DEL));
1085 if (rc)
1086 return rc;
1088 return 0;
1092 * Function responsible for setting up the prctl syscall for
1093 * the seccomp filter sandbox.
1095 * NOTE: if multiple filters need to be added, the PR_SECCOMP parameter needs
1096 * to be allowlisted in this function.
1098 static int
1099 sb_prctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
1101 int rc = 0;
1102 (void) filter;
1104 #ifdef ENABLE_FRAGILE_HARDENING
1105 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl),
1106 SCMP_CMP(0, SCMP_CMP_EQ, PR_GET_DUMPABLE));
1107 if (rc)
1108 return rc;
1110 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl),
1111 SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_PTRACER));
1112 if (rc)
1113 return rc;
1114 #endif
1116 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl),
1117 SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_DUMPABLE));
1118 if (rc)
1119 return rc;
1121 return 0;
1125 * Function responsible for setting up the mprotect syscall for
1126 * the seccomp filter sandbox.
1128 * NOTE: does not NEED to be here.. currently only occurs before filter; will
1129 * keep just in case for the future.
1131 static int
1132 sb_mprotect(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
1134 int rc = 0;
1135 (void) filter;
1137 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect),
1138 SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ));
1139 if (rc)
1140 return rc;
1142 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect),
1143 SCMP_CMP(2, SCMP_CMP_EQ, PROT_NONE));
1144 if (rc)
1145 return rc;
1147 return 0;
1151 * Function responsible for setting up the rt_sigprocmask syscall for
1152 * the seccomp filter sandbox.
1154 static int
1155 sb_rt_sigprocmask(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
1157 int rc = 0;
1158 (void) filter;
1160 #ifdef ENABLE_FRAGILE_HARDENING
1161 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask),
1162 SCMP_CMP(0, SCMP_CMP_EQ, SIG_BLOCK));
1163 if (rc)
1164 return rc;
1165 #endif
1167 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask),
1168 SCMP_CMP(0, SCMP_CMP_EQ, SIG_UNBLOCK));
1169 if (rc)
1170 return rc;
1172 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask),
1173 SCMP_CMP(0, SCMP_CMP_EQ, SIG_SETMASK));
1174 if (rc)
1175 return rc;
1177 return 0;
1181 * Function responsible for setting up the flock syscall for
1182 * the seccomp filter sandbox.
1184 * NOTE: does not need to be here, occurs before filter is applied.
1186 static int
1187 sb_flock(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
1189 int rc = 0;
1190 (void) filter;
1192 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(flock),
1193 SCMP_CMP(1, SCMP_CMP_EQ, LOCK_EX|LOCK_NB));
1194 if (rc)
1195 return rc;
1197 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(flock),
1198 SCMP_CMP(1, SCMP_CMP_EQ, LOCK_UN));
1199 if (rc)
1200 return rc;
1202 return 0;
1206 * Function responsible for setting up the futex syscall for
1207 * the seccomp filter sandbox.
1209 static int
1210 sb_futex(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
1212 int rc = 0;
1213 (void) filter;
1215 // can remove
1216 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex),
1217 SCMP_CMP(1, SCMP_CMP_EQ,
1218 FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME));
1219 if (rc)
1220 return rc;
1222 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex),
1223 SCMP_CMP(1, SCMP_CMP_EQ, FUTEX_WAKE_PRIVATE));
1224 if (rc)
1225 return rc;
1227 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex),
1228 SCMP_CMP(1, SCMP_CMP_EQ, FUTEX_WAIT_PRIVATE));
1229 if (rc)
1230 return rc;
1232 return 0;
1236 * Function responsible for setting up the mremap syscall for
1237 * the seccomp filter sandbox.
1239 * NOTE: so far only occurs before filter is applied.
1241 static int
1242 sb_mremap(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
1244 int rc = 0;
1245 (void) filter;
1247 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mremap),
1248 SCMP_CMP(3, SCMP_CMP_EQ, MREMAP_MAYMOVE));
1249 if (rc)
1250 return rc;
1252 return 0;
1255 #ifdef __NR_stat64
1257 * Function responsible for setting up the stat64 syscall for
1258 * the seccomp filter sandbox.
1260 static int
1261 sb_stat64(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
1263 int rc = 0;
1264 sandbox_cfg_t *elem = NULL;
1266 // for each dynamic parameter filters
1267 for (elem = filter; elem != NULL; elem = elem->next) {
1268 smp_param_t *param = elem->param;
1270 if (param != NULL && param->prot == 1 && (param->syscall == SCMP_SYS(open)
1271 || param->syscall == SCMP_SYS(stat64))) {
1272 rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(stat64),
1273 SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
1274 if (rc != 0) {
1275 log_err(LD_BUG,"(Sandbox) failed to add stat64 syscall, received "
1276 "libseccomp error %d", rc);
1277 return rc;
1282 return 0;
1284 #endif /* defined(__NR_stat64) */
1286 static int
1287 sb_kill(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
1289 (void) filter;
1290 #ifdef __NR_kill
1291 /* Allow killing anything with signal 0 -- it isn't really a kill. */
1292 return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(kill),
1293 SCMP_CMP(1, SCMP_CMP_EQ, 0));
1294 #else
1295 return 0;
1296 #endif /* defined(__NR_kill) */
1300 * Array of function pointers responsible for filtering different syscalls at
1301 * a parameter level.
1303 static sandbox_filter_func_t filter_func[] = {
1304 sb_rt_sigaction,
1305 sb_rt_sigprocmask,
1306 #ifdef __NR_time
1307 sb_time,
1308 #endif
1309 sb_accept4,
1310 #ifdef __NR_mmap2
1311 sb_mmap2,
1312 #endif
1313 #ifdef __i386__
1314 sb_chown32,
1315 #else
1316 sb_chown,
1317 #endif
1318 sb_chmod,
1319 sb_open,
1320 sb_openat,
1321 sb_opendir,
1322 #ifdef ENABLE_FRAGILE_HARDENING
1323 sb_ptrace,
1324 #endif
1325 sb_rename,
1326 #ifdef __NR_fcntl64
1327 sb_fcntl64,
1328 #endif
1329 sb_epoll_ctl,
1330 sb_prctl,
1331 sb_mprotect,
1332 sb_flock,
1333 sb_futex,
1334 sb_mremap,
1335 #ifdef __NR_stat64
1336 sb_stat64,
1337 #endif
1339 sb_socket,
1340 sb_setsockopt,
1341 sb_getsockopt,
1342 sb_socketpair,
1343 #ifdef HAVE_KIST_SUPPORT
1344 sb_ioctl,
1345 #endif
1346 sb_kill
1350 * Return the interned (and hopefully sandbox-permitted) string equal
1351 * to @a str.
1353 * Return NULL if `str` is NULL, or `str` is not an interned string.
1355 const char *
1356 sandbox_intern_string(const char *str)
1358 const char *interned = sandbox_get_interned_string(str);
1360 if (sandbox_active && str != NULL && interned == NULL) {
1361 log_warn(LD_BUG, "No interned sandbox parameter found for %s", str);
1364 return interned ? interned : str;
1368 * Return true if the sandbox is running and we are missing an interned string
1369 * equal to @a str.
1371 bool
1372 sandbox_interned_string_is_missing(const char *str)
1374 return sandbox_active && sandbox_get_interned_string(str) == NULL;
1378 * Try to find and return the interned string equal to @a str.
1380 * If there is no such string, return NULL.
1382 static const char *
1383 sandbox_get_interned_string(const char *str)
1385 sandbox_cfg_t *elem;
1387 if (str == NULL)
1388 return NULL;
1390 for (elem = filter_dynamic; elem != NULL; elem = elem->next) {
1391 smp_param_t *param = elem->param;
1393 if (param->prot) {
1394 if (!strcmp(str, (char*)(param->value))) {
1395 return (char*)param->value;
1397 if (param->value2 && !strcmp(str, (char*)param->value2)) {
1398 return (char*)param->value2;
1403 return NULL;
1406 /* DOCDOC */
1407 static int
1408 prot_strings_helper(strmap_t *locations,
1409 char **pr_mem_next_p,
1410 size_t *pr_mem_left_p,
1411 char **value_p)
1413 char *param_val;
1414 size_t param_size;
1415 void *location;
1417 if (*value_p == 0)
1418 return 0;
1420 param_val = (char*) *value_p;
1421 param_size = strlen(param_val) + 1;
1422 location = strmap_get(locations, param_val);
1424 if (location) {
1425 // We already interned this string.
1426 tor_free(param_val);
1427 *value_p = location;
1428 return 0;
1429 } else if (*pr_mem_left_p >= param_size) {
1430 // copy to protected
1431 location = *pr_mem_next_p;
1432 memcpy(location, param_val, param_size);
1434 // re-point el parameter to protected
1435 tor_free(param_val);
1436 *value_p = location;
1438 strmap_set(locations, location, location); /* good real estate advice */
1440 // move next available protected memory
1441 *pr_mem_next_p += param_size;
1442 *pr_mem_left_p -= param_size;
1443 return 0;
1444 } else {
1445 log_err(LD_BUG,"(Sandbox) insufficient protected memory!");
1446 return -1;
1451 * Protects all the strings in the sandbox's parameter list configuration. It
1452 * works by calculating the total amount of memory required by the parameter
1453 * list, allocating the memory using mmap, and protecting it from writes with
1454 * mprotect().
1456 static int
1457 prot_strings(scmp_filter_ctx ctx, sandbox_cfg_t* cfg)
1459 int ret = 0;
1460 size_t pr_mem_size = 0, pr_mem_left = 0;
1461 char *pr_mem_next = NULL, *pr_mem_base;
1462 sandbox_cfg_t *el = NULL;
1463 strmap_t *locations = NULL;
1465 // get total number of bytes required to mmap. (Overestimate.)
1466 for (el = cfg; el != NULL; el = el->next) {
1467 pr_mem_size += strlen((char*) el->param->value) + 1;
1468 if (el->param->value2)
1469 pr_mem_size += strlen((char*) el->param->value2) + 1;
1472 // allocate protected memory with MALLOC_MP_LIM canary
1473 pr_mem_base = (char*) mmap(NULL, MALLOC_MP_LIM + pr_mem_size,
1474 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1475 if (pr_mem_base == MAP_FAILED) {
1476 log_err(LD_BUG,"(Sandbox) failed allocate protected memory! mmap: %s",
1477 strerror(errno));
1478 ret = -1;
1479 goto out;
1482 pr_mem_next = pr_mem_base + MALLOC_MP_LIM;
1483 pr_mem_left = pr_mem_size;
1485 locations = strmap_new();
1487 // change el value pointer to protected
1488 for (el = cfg; el != NULL; el = el->next) {
1489 if (prot_strings_helper(locations, &pr_mem_next, &pr_mem_left,
1490 &el->param->value) < 0) {
1491 ret = -2;
1492 goto out;
1494 if (prot_strings_helper(locations, &pr_mem_next, &pr_mem_left,
1495 &el->param->value2) < 0) {
1496 ret = -2;
1497 goto out;
1499 el->param->prot = 1;
1502 // protecting from writes
1503 if (mprotect(pr_mem_base, MALLOC_MP_LIM + pr_mem_size, PROT_READ)) {
1504 log_err(LD_BUG,"(Sandbox) failed to protect memory! mprotect: %s",
1505 strerror(errno));
1506 ret = -3;
1507 goto out;
1511 * Setting sandbox restrictions so the string memory cannot be tampered with
1513 // no mremap of the protected base address
1514 ret = seccomp_rule_add_1(ctx, SCMP_ACT_KILL, SCMP_SYS(mremap),
1515 SCMP_CMP(0, SCMP_CMP_EQ, (intptr_t) pr_mem_base));
1516 if (ret) {
1517 log_err(LD_BUG,"(Sandbox) mremap protected memory filter fail!");
1518 goto out;
1521 // no munmap of the protected base address
1522 ret = seccomp_rule_add_1(ctx, SCMP_ACT_KILL, SCMP_SYS(munmap),
1523 SCMP_CMP(0, SCMP_CMP_EQ, (intptr_t) pr_mem_base));
1524 if (ret) {
1525 log_err(LD_BUG,"(Sandbox) munmap protected memory filter fail!");
1526 goto out;
1530 * Allow mprotect with PROT_READ|PROT_WRITE because openssl uses it, but
1531 * never over the memory region used by the protected strings.
1533 * PROT_READ|PROT_WRITE was originally fully allowed in sb_mprotect(), but
1534 * had to be removed due to limitation of libseccomp regarding intervals.
1536 * There is a restriction on how much you can mprotect with R|W up to the
1537 * size of the canary.
1539 ret = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect),
1540 SCMP_CMP(0, SCMP_CMP_LT, (intptr_t) pr_mem_base),
1541 SCMP_CMP(1, SCMP_CMP_LE, MALLOC_MP_LIM),
1542 SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE));
1543 if (ret) {
1544 log_err(LD_BUG,"(Sandbox) mprotect protected memory filter fail (LT)!");
1545 goto out;
1548 ret = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect),
1549 SCMP_CMP(0, SCMP_CMP_GT, (intptr_t) pr_mem_base + pr_mem_size +
1550 MALLOC_MP_LIM),
1551 SCMP_CMP(1, SCMP_CMP_LE, MALLOC_MP_LIM),
1552 SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE));
1553 if (ret) {
1554 log_err(LD_BUG,"(Sandbox) mprotect protected memory filter fail (GT)!");
1555 goto out;
1558 out:
1559 strmap_free(locations, NULL);
1560 return ret;
1564 * Auxiliary function used in order to allocate a sandbox_cfg_t element and set
1565 * its values according the parameter list. All elements are initialised
1566 * with the 'prot' field set to false, as the pointer is not protected at this
1567 * point.
1569 static sandbox_cfg_t*
1570 new_element2(int syscall, char *value, char *value2)
1572 smp_param_t *param = NULL;
1574 sandbox_cfg_t *elem = tor_malloc_zero(sizeof(sandbox_cfg_t));
1575 param = elem->param = tor_malloc_zero(sizeof(smp_param_t));
1577 param->syscall = syscall;
1578 param->value = value;
1579 param->value2 = value2;
1580 param->prot = 0;
1582 return elem;
1585 static sandbox_cfg_t*
1586 new_element(int syscall, char *value)
1588 return new_element2(syscall, value, NULL);
1591 #ifdef __i386__
1592 #define SCMP_chown SCMP_SYS(chown32)
1593 #else
1594 #define SCMP_chown SCMP_SYS(chown)
1595 #endif
1597 #ifdef __NR_stat64
1598 #define SCMP_stat SCMP_SYS(stat64)
1599 #else
1600 #define SCMP_stat SCMP_SYS(stat)
1601 #endif
1604 sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file)
1606 sandbox_cfg_t *elem = NULL;
1608 elem = new_element(SCMP_stat, file);
1610 elem->next = *cfg;
1611 *cfg = elem;
1613 return 0;
1617 sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file)
1619 sandbox_cfg_t *elem = NULL;
1621 elem = new_element(SCMP_SYS(open), file);
1623 elem->next = *cfg;
1624 *cfg = elem;
1626 return 0;
1630 sandbox_cfg_allow_chmod_filename(sandbox_cfg_t **cfg, char *file)
1632 sandbox_cfg_t *elem = NULL;
1634 elem = new_element(SCMP_SYS(chmod), file);
1636 elem->next = *cfg;
1637 *cfg = elem;
1639 return 0;
1643 sandbox_cfg_allow_chown_filename(sandbox_cfg_t **cfg, char *file)
1645 sandbox_cfg_t *elem = NULL;
1647 elem = new_element(SCMP_chown, file);
1649 elem->next = *cfg;
1650 *cfg = elem;
1652 return 0;
1656 sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2)
1658 sandbox_cfg_t *elem = NULL;
1660 elem = new_element2(SCMP_SYS(rename), file1, file2);
1662 elem->next = *cfg;
1663 *cfg = elem;
1665 return 0;
1669 sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file)
1671 sandbox_cfg_t *elem = NULL;
1673 elem = new_element(SCMP_SYS(openat), file);
1675 elem->next = *cfg;
1676 *cfg = elem;
1678 return 0;
1682 sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir)
1684 sandbox_cfg_t *elem = NULL;
1686 elem = new_element(PHONY_OPENDIR_SYSCALL, dir);
1688 elem->next = *cfg;
1689 *cfg = elem;
1691 return 0;
1695 * Function responsible for going through the parameter syscall filters and
1696 * call each function pointer in the list.
1698 static int
1699 add_param_filter(scmp_filter_ctx ctx, sandbox_cfg_t* cfg)
1701 unsigned i;
1702 int rc = 0;
1704 // function pointer
1705 for (i = 0; i < ARRAY_LENGTH(filter_func); i++) {
1706 rc = filter_func[i](ctx, cfg);
1707 if (rc) {
1708 log_err(LD_BUG,"(Sandbox) failed to add syscall %d, received libseccomp "
1709 "error %d", i, rc);
1710 return rc;
1714 return 0;
1718 * Function responsible of loading the libseccomp syscall filters which do not
1719 * have parameter filtering.
1721 static int
1722 add_noparam_filter(scmp_filter_ctx ctx)
1724 unsigned i;
1725 int rc = 0;
1727 // add general filters
1728 for (i = 0; i < ARRAY_LENGTH(filter_nopar_gen); i++) {
1729 rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, filter_nopar_gen[i]);
1730 if (rc != 0) {
1731 log_err(LD_BUG,"(Sandbox) failed to add syscall index %d (NR=%d), "
1732 "received libseccomp error %d", i, filter_nopar_gen[i], rc);
1733 return rc;
1737 if (is_libc_at_least(2, 33)) {
1738 #ifdef __NR_newfstatat
1739 // Libc 2.33 uses this syscall to implement both fstat() and stat().
1741 // The trouble is that to implement fstat(fd, &st), it calls:
1742 // newfstatat(fs, "", &st, AT_EMPTY_PATH)
1743 // We can't detect this usage in particular, because "" is a pointer
1744 // we don't control. And we can't just look for AT_EMPTY_PATH, since
1745 // AT_EMPTY_PATH only has effect when the path string is empty.
1747 // So our only solution seems to be allowing all fstatat calls, which
1748 // means that an attacker can stat() anything on the filesystem. That's
1749 // not a great solution, but I can't find a better one.
1750 rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(newfstatat));
1751 if (rc != 0) {
1752 log_err(LD_BUG,"(Sandbox) failed to add newfstatat() syscall; "
1753 "received libseccomp error %d", rc);
1754 return rc;
1756 #endif
1759 return 0;
1763 * Function responsible for setting up and enabling a global syscall filter.
1764 * The function is a prototype developed for stage 1 of sandboxing Tor.
1765 * Returns 0 on success.
1767 static int
1768 install_syscall_filter(sandbox_cfg_t* cfg)
1770 int rc = 0;
1771 scmp_filter_ctx ctx;
1773 ctx = seccomp_init(SCMP_ACT_ERRNO(EPERM));
1774 if (ctx == NULL) {
1775 log_err(LD_BUG,"(Sandbox) failed to initialise libseccomp context");
1776 rc = -1;
1777 goto end;
1780 // protecting sandbox parameter strings
1781 if ((rc = prot_strings(ctx, cfg))) {
1782 goto end;
1785 // add parameter filters
1786 if ((rc = add_param_filter(ctx, cfg))) {
1787 log_err(LD_BUG, "(Sandbox) failed to add param filters!");
1788 goto end;
1791 // adding filters with no parameters
1792 if ((rc = add_noparam_filter(ctx))) {
1793 log_err(LD_BUG, "(Sandbox) failed to add param filters!");
1794 goto end;
1797 // loading the seccomp2 filter
1798 if ((rc = seccomp_load(ctx))) {
1799 log_err(LD_BUG, "(Sandbox) failed to load: %d (%s)! "
1800 "Are you sure that your kernel has seccomp2 support? The "
1801 "sandbox won't work without it.", rc,
1802 strerror(-rc));
1803 goto end;
1806 // marking the sandbox as active
1807 sandbox_active = 1;
1809 end:
1810 seccomp_release(ctx);
1811 return (rc < 0 ? -rc : rc);
1814 #ifdef SYSCALL_NAME_DEBUGGING
1815 #include "lib/sandbox/linux_syscalls.inc"
1817 /** Return a string containing the name of a given syscall (if we know it) */
1818 static const char *
1819 get_syscall_name(int syscall_num)
1821 int i;
1822 for (i = 0; SYSCALLS_BY_NUMBER[i].syscall_name; ++i) {
1823 if (SYSCALLS_BY_NUMBER[i].syscall_num == syscall_num)
1824 return SYSCALLS_BY_NUMBER[i].syscall_name;
1828 static char syscall_name_buf[64];
1829 format_dec_number_sigsafe(syscall_num,
1830 syscall_name_buf, sizeof(syscall_name_buf));
1831 return syscall_name_buf;
1835 /** Return the syscall number from a ucontext_t that we got in a signal
1836 * handler (if we know how to do that). */
1837 static int
1838 get_syscall_from_ucontext(const ucontext_t *ctx)
1840 return (int) ctx->uc_mcontext.M_SYSCALL;
1842 #else /* !defined(SYSCALL_NAME_DEBUGGING) */
1843 static const char *
1844 get_syscall_name(int syscall_num)
1846 (void) syscall_num;
1847 return "unknown";
1849 static int
1850 get_syscall_from_ucontext(const ucontext_t *ctx)
1852 (void) ctx;
1853 return -1;
1855 #endif /* defined(SYSCALL_NAME_DEBUGGING) */
1857 #ifdef USE_BACKTRACE
1858 #define MAX_DEPTH 256
1859 static void *syscall_cb_buf[MAX_DEPTH];
1860 #endif
1863 * Function called when a SIGSYS is caught by the application. It notifies the
1864 * user that an error has occurred and either terminates or allows the
1865 * application to continue execution, based on the DEBUGGING_CLOSE symbol.
1867 static void
1868 sigsys_debugging(int nr, siginfo_t *info, void *void_context)
1870 ucontext_t *ctx = (ucontext_t *) (void_context);
1871 const char *syscall_name;
1872 #ifdef USE_BACKTRACE
1873 size_t depth;
1874 int n_fds, i;
1875 const int *fds = NULL;
1876 #endif
1878 (void) nr;
1880 if (info->si_code != SYS_SECCOMP)
1881 return;
1883 if (!ctx)
1884 return;
1886 int syscall = get_syscall_from_ucontext(ctx);
1888 #ifdef USE_BACKTRACE
1889 depth = backtrace(syscall_cb_buf, MAX_DEPTH);
1890 /* Clean up the top stack frame so we get the real function
1891 * name for the most recently failing function. */
1892 clean_backtrace(syscall_cb_buf, depth, ctx);
1893 #endif /* defined(USE_BACKTRACE) */
1895 syscall_name = get_syscall_name(syscall);
1897 tor_log_err_sigsafe("(Sandbox) Caught a bad syscall attempt (syscall ",
1898 syscall_name,
1899 ")\n",
1900 NULL);
1902 #ifdef USE_BACKTRACE
1903 n_fds = tor_log_get_sigsafe_err_fds(&fds);
1904 for (i=0; i < n_fds; ++i)
1905 backtrace_symbols_fd(syscall_cb_buf, (int)depth, fds[i]);
1906 #endif
1908 #if defined(DEBUGGING_CLOSE)
1909 _exit(1); // exit ok: programming error has led to sandbox failure.
1910 #endif // DEBUGGING_CLOSE
1914 * Function that adds a handler for SIGSYS, which is the signal thrown
1915 * when the application is issuing a syscall which is not allowed. The
1916 * main purpose of this function is to help with debugging by identifying
1917 * filtered syscalls.
1919 static int
1920 install_sigsys_debugging(void)
1922 struct sigaction act;
1923 sigset_t mask;
1925 memset(&act, 0, sizeof(act));
1926 sigemptyset(&mask);
1927 sigaddset(&mask, SIGSYS);
1929 act.sa_sigaction = &sigsys_debugging;
1930 act.sa_flags = SA_SIGINFO;
1931 if (sigaction(SIGSYS, &act, NULL) < 0) {
1932 log_err(LD_BUG,"(Sandbox) Failed to register SIGSYS signal handler");
1933 return -1;
1936 if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) {
1937 log_err(LD_BUG,"(Sandbox) Failed call to sigprocmask()");
1938 return -2;
1941 return 0;
1945 * Function responsible of registering the sandbox_cfg_t list of parameter
1946 * syscall filters to the existing parameter list. This is used for incipient
1947 * multiple-sandbox support.
1949 static int
1950 register_cfg(sandbox_cfg_t* cfg)
1952 sandbox_cfg_t *elem = NULL;
1954 if (filter_dynamic == NULL) {
1955 filter_dynamic = cfg;
1956 return 0;
1959 for (elem = filter_dynamic; elem->next != NULL; elem = elem->next)
1962 elem->next = cfg;
1964 return 0;
1967 #endif /* defined(USE_LIBSECCOMP) */
1969 #ifdef USE_LIBSECCOMP
1971 * Initialises the syscall sandbox filter for any linux architecture, taking
1972 * into account various available features for different linux flavours.
1974 static int
1975 initialise_libseccomp_sandbox(sandbox_cfg_t* cfg)
1977 /* Prevent glibc from trying to open /dev/tty on fatal error */
1978 setenv("LIBC_FATAL_STDERR_", "1", 1);
1980 if (install_sigsys_debugging())
1981 return -1;
1983 if (install_syscall_filter(cfg))
1984 return -2;
1986 if (register_cfg(cfg))
1987 return -3;
1989 return 0;
1993 sandbox_is_active(void)
1995 return sandbox_active != 0;
1997 #endif /* defined(USE_LIBSECCOMP) */
1999 sandbox_cfg_t*
2000 sandbox_cfg_new(void)
2002 return NULL;
2006 sandbox_init(sandbox_cfg_t *cfg)
2008 #if defined(USE_LIBSECCOMP)
2009 return initialise_libseccomp_sandbox(cfg);
2011 #elif defined(__linux__)
2012 (void)cfg;
2013 log_warn(LD_GENERAL,
2014 "This version of Tor was built without support for sandboxing. To "
2015 "build with support for sandboxing on Linux, you must have "
2016 "libseccomp and its necessary header files (e.g. seccomp.h).");
2017 return 0;
2019 #else
2020 (void)cfg;
2021 log_warn(LD_GENERAL,
2022 "Currently, sandboxing is only implemented on Linux. The feature "
2023 "is disabled on your platform.");
2024 return 0;
2025 #endif /* defined(USE_LIBSECCOMP) || ... */
2028 #ifndef USE_LIBSECCOMP
2030 sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file)
2032 (void)cfg; (void)file;
2033 return 0;
2037 sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file)
2039 (void)cfg; (void)file;
2040 return 0;
2044 sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir)
2046 (void)cfg; (void)dir;
2047 return 0;
2051 sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file)
2053 (void)cfg; (void)file;
2054 return 0;
2058 sandbox_cfg_allow_chown_filename(sandbox_cfg_t **cfg, char *file)
2060 (void)cfg; (void)file;
2061 return 0;
2065 sandbox_cfg_allow_chmod_filename(sandbox_cfg_t **cfg, char *file)
2067 (void)cfg; (void)file;
2068 return 0;
2072 sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2)
2074 (void)cfg; (void)file1; (void)file2;
2075 return 0;
2079 sandbox_is_active(void)
2081 return 0;
2084 #endif /* !defined(USE_LIBSECCOMP) */