2 * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #if defined(__FreeBSD__)
21 #include <sys/capsicum.h>
24 sandbox_server_process(void)
26 if (cap_enter() == -1)
31 sandbox_executor_process(void)
33 /* We cannot capsicum the executor process because it needs
34 * to fork(2)+execve(2) cgi scripts */
39 sandbox_logger_process(void)
41 if (cap_enter() == -1)
45 #elif defined(__linux__)
47 #include <sys/prctl.h>
48 #include <sys/syscall.h>
49 #include <sys/syscall.h>
50 #include <sys/types.h>
52 #include <linux/audit.h>
53 #include <linux/filter.h>
54 #include <linux/seccomp.h>
62 /* uncomment to enable debugging. ONLY FOR DEVELOPMENT */
63 /* #define SC_DEBUG */
66 # define SC_FAIL SECCOMP_RET_TRAP
68 # define SC_FAIL SECCOMP_RET_KILL
71 #if (BYTE_ORDER == LITTLE_ENDIAN)
73 # define SC_ARG_HI sizeof(uint32_t)
74 #elif (BYTE_ORDER == BIG_ENDIAN)
75 # define SC_ARG_LO sizeof(uint32_t)
78 # error "Uknown endian"
81 /* make the filter more readable */
82 #define SC_ALLOW(nr) \
83 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_##nr, 0, 1), \
84 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)
87 * SC_ALLOW_ARG and the SECCOMP_AUDIT_ARCH below are courtesy of
88 * https://roy.marples.name/git/dhcpcd/blob/HEAD:/src/privsep-linux.c
90 #define SC_ALLOW_ARG(_nr, _arg, _val) \
91 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (_nr), 0, 6), \
92 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
93 offsetof(struct seccomp_data, args[(_arg)]) + SC_ARG_LO), \
94 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, \
95 ((_val) & 0xffffffff), 0, 3), \
96 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
97 offsetof(struct seccomp_data, args[(_arg)]) + SC_ARG_HI), \
98 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, \
99 (((uint32_t)((uint64_t)(_val) >> 32)) & 0xffffffff), 0, 1), \
100 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW), \
101 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
102 offsetof(struct seccomp_data, nr))
105 * I personally find this quite nutty. Why can a system header not
106 * define a default for this?
108 #if defined(__i386__)
109 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_I386
110 #elif defined(__x86_64__)
111 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_X86_64
112 #elif defined(__arc__)
114 # if (BYTE_ORDER == LITTLE_ENDIAN)
115 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARCOMPACT
117 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARCOMPACTBE
119 # elif defined(__HS__)
120 # if (BYTE_ORDER == LITTLE_ENDIAN)
121 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARCV2
123 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARCV2BE
126 # error "Platform does not support seccomp filter yet"
128 #elif defined(__arm__)
132 # if (BYTE_ORDER == LITTLE_ENDIAN)
133 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM
135 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARMEB
137 #elif defined(__aarch64__)
138 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_AARCH64
139 #elif defined(__alpha__)
140 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ALPHA
141 #elif defined(__hppa__)
142 # if defined(__LP64__)
143 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PARISC64
145 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PARISC
147 #elif defined(__ia64__)
148 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_IA64
149 #elif defined(__microblaze__)
150 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MICROBLAZE
151 #elif defined(__m68k__)
152 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_M68K
153 #elif defined(__mips__)
154 # if defined(__MIPSEL__)
155 # if defined(__LP64__)
156 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPSEL64
158 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPSEL
160 # elif defined(__LP64__)
161 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPS64
163 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPS
165 #elif defined(__nds32__)
166 # if (BYTE_ORDER == LITTLE_ENDIAN)
167 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_NDS32
169 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_NDS32BE
171 #elif defined(__nios2__)
172 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_NIOS2
173 #elif defined(__or1k__)
174 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_OPENRISC
175 #elif defined(__powerpc64__)
176 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PPC64
177 #elif defined(__powerpc__)
178 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PPC
179 #elif defined(__riscv)
180 # if defined(__LP64__)
181 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_RISCV64
183 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_RISCV32
185 #elif defined(__s390x__)
186 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_S390X
187 #elif defined(__s390__)
188 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_S390
189 #elif defined(__sh__)
190 # if defined(__LP64__)
191 # if (BYTE_ORDER == LITTLE_ENDIAN)
192 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_SHEL64
194 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_SH64
197 # if (BYTE_ORDER == LITTLE_ENDIAN)
198 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_SHEL
200 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_SH
203 #elif defined(__sparc__)
204 # if defined(__arch64__)
205 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_SPARC64
207 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_SPARC
209 #elif defined(__xtensa__)
210 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_XTENSA
212 # error "Platform does not support seccomp filter yet"
215 static struct sock_filter filter[] = {
216 /* load the *current* architecture */
217 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
218 (offsetof(struct seccomp_data, arch))),
219 /* ensure it's the same that we've been compiled on */
220 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,
221 SECCOMP_AUDIT_ARCH, 1, 0),
222 /* if not, kill the program */
223 BPF_STMT(BPF_RET | BPF_K, SC_FAIL),
225 /* load the syscall number */
226 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
227 (offsetof(struct seccomp_data, nr))),
238 #ifdef __NR_clock_gettime
239 SC_ALLOW(clock_gettime),
241 #if defined(__x86_64__) && defined(__ILP32__) && defined(__X32_SYSCALL_BIT)
242 SECCOMP_ALLOW(__NR_clock_gettime & ~__X32_SYSCALL_BIT),
244 #ifdef __NR_clock_gettime64
245 SC_ALLOW(clock_gettime64),
250 #ifdef __NR_epoll_ctl
253 #ifdef __NR_epoll_pwait
254 SC_ALLOW(epoll_pwait),
256 #ifdef __NR_epoll_wait
257 SC_ALLOW(epoll_wait),
262 #ifdef __NR_exit_group
263 SC_ALLOW(exit_group),
274 #ifdef __NR_getdents64
275 SC_ALLOW(getdents64),
280 #ifdef __NR_getrandom
283 #ifdef __NR_gettimeofday
284 SC_ALLOW(gettimeofday),
287 /* allow ioctl only on fd 1, glibc doing stuff? */
288 SC_ALLOW_ARG(__NR_ioctl, 0, 1),
305 #ifdef __NR_newfstatat
306 SC_ALLOW(newfstatat),
314 #ifdef __NR_prlimit64
326 #ifdef __NR_rt_sigaction
327 SC_ALLOW(rt_sigaction),
329 #ifdef __NR_rt_sigreturn
330 SC_ALLOW(rt_sigreturn),
345 /* disallow enything else */
346 BPF_STMT(BPF_RET | BPF_K, SC_FAIL),
355 sandbox_seccomp_violation(int signum, siginfo_t *info, void *ctx)
360 fprintf(stderr, "%s: unexpected system call (arch:0x%x,syscall:%d @ %p)\n",
361 __func__, info->si_arch, info->si_syscall, info->si_call_addr);
366 sandbox_seccomp_catch_sigsys(void)
368 struct sigaction act;
371 memset(&act, 0, sizeof(act));
373 sigaddset(&mask, SIGSYS);
375 act.sa_sigaction = &sandbox_seccomp_violation;
376 act.sa_flags = SA_SIGINFO;
377 if (sigaction(SIGSYS, &act, NULL) == -1)
378 fatal("%s: sigaction(SIGSYS): %s",
379 __func__, strerror(errno));
381 if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
382 fatal("%s: sigprocmask(SIGSYS): %s\n",
383 __func__, strerror(errno));
385 #endif /* SC_DEBUG */
388 sandbox_server_process(void)
390 struct sock_fprog prog = {
391 .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])),
396 sandbox_seccomp_catch_sigsys();
399 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
400 fatal("%s: prctl(PR_SET_NO_NEW_PRIVS): %s",
401 __func__, strerror(errno));
403 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) == -1)
404 fatal("%s: prctl(PR_SET_SECCOMP): %s\n",
405 __func__, strerror(errno));
409 sandbox_executor_process(void)
411 /* We cannot use seccomp for the executor process because we
412 * don't know what the child will do. Also, our filter will
413 * be inherited so the child cannot set its own seccomp
419 sandbox_logger_process(void)
421 /* To be honest, here we could use a seccomp policy to only
422 * allow writev(2) and memory allocations. */
426 #elif defined(__OpenBSD__)
431 sandbox_server_process(void)
435 for (h = hosts; h->domain != NULL; ++h) {
436 if (unveil(h->dir, "r") == -1)
437 fatal("unveil %s for domain %s", h->dir, h->domain);
440 if (pledge("stdio recvfd rpath inet", NULL) == -1)
445 sandbox_executor_process(void)
449 for (vhost = hosts; vhost->domain != NULL; ++vhost) {
450 /* r so we can chdir into the correct directory */
451 if (unveil(vhost->dir, "rx") == -1)
452 err(1, "unveil %s for domain %s",
453 vhost->dir, vhost->domain);
456 /* rpath to chdir into the correct directory */
457 if (pledge("stdio rpath sendfd proc exec", NULL))
462 sandbox_logger_process(void)
464 if (pledge("stdio", NULL) == -1)
470 #warning "No sandbox method known for this OS"
473 sandbox_server_process(void)
479 sandbox_executor_process(void)
481 log_notice(NULL, "no sandbox method known for this OS");
485 sandbox_logger_process(void)