Blob


1 #include "gmid.h"
3 #if defined(__FreeBSD__)
5 #include <sys/capsicum.h>
6 #include <err.h>
8 void
9 sandbox()
10 {
11 if (cap_enter() == -1)
12 err(1, "cap_enter");
13 }
15 #elif defined(__linux__)
17 #include <sys/prctl.h>
18 #include <sys/syscall.h>
19 #include <sys/syscall.h>
20 #include <sys/types.h>
22 #include <linux/audit.h>
23 #include <linux/filter.h>
24 #include <linux/seccomp.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stddef.h>
29 #include <stdio.h>
30 #include <seccomp.h>
31 #include <string.h>
33 /* thanks chromium' src/seccomp.c */
34 #if defined(__i386__)
35 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_I386
36 #elif defined(__x86_64__)
37 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_X86_64
38 #elif defined(__arm__)
39 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM
40 #elif defined(__aarch64__)
41 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_AARCH64
42 #elif defined(__mips__)
43 # if defined(__mips64)
44 # if defined(__MIPSEB__)
45 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPS64
46 # else
47 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPSEL64
48 # endif
49 # else
50 # if defined(__MIPSEB__)
51 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPS
52 # else
53 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPSEL
54 # endif
55 # endif
56 #else
57 # error "Platform does not support seccomp filter yet"
58 #endif
60 /* uncomment to enable debugging. ONLY FOR DEVELOPMENT */
61 /* #define SC_DEBUG */
63 #ifdef SC_DEBUG
64 # define SC_FAIL SECCOMP_RET_TRAP
65 #else
66 # define SC_FAIL SECCOMP_RET_KILL
67 #endif
69 /* make the filter more readable */
70 #define SC_ALLOW(nr) \
71 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_##nr, 0, 1), \
72 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)
74 #ifdef SC_DEBUG
76 #include <signal.h>
77 #include <unistd.h>
79 static void
80 sandbox_seccomp_violation(int signum, siginfo_t *info, void *ctx)
81 {
82 (void)signum;
83 (void)ctx;
85 fprintf(stderr, "%s: unexpected system call (arch:0x%x,syscall:%d @ %p)\n",
86 __func__, info->si_arch, info->si_syscall, info->si_call_addr);
87 _exit(1);
88 }
90 static void
91 sandbox_seccomp_catch_sigsys(void)
92 {
93 struct sigaction act;
94 sigset_t mask;
96 memset(&act, 0, sizeof(act));
97 sigemptyset(&mask);
98 sigaddset(&mask, SIGSYS);
100 act.sa_sigaction = &sandbox_seccomp_violation;
101 act.sa_flags = SA_SIGINFO;
102 if (sigaction(SIGSYS, &act, NULL) == -1) {
103 fprintf(stderr, "%s: sigaction(SIGSYS): %s\n",
104 __func__, strerror(errno));
105 exit(1);
107 if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) {
108 fprintf(stderr, "%s: sigprocmask(SIGSYS): %s\n",
109 __func__, strerror(errno));
110 exit(1);
113 #endif /* SC_DEBUG */
115 void
116 sandbox()
118 struct sock_filter filter[] = {
119 /* load the *current* architecture */
120 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
121 (offsetof(struct seccomp_data, arch))),
122 /* ensure it's the same that we've been compiled on */
123 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,
124 SECCOMP_AUDIT_ARCH, 1, 0),
125 /* if not, kill the program */
126 BPF_STMT(BPF_RET | BPF_K, SC_FAIL),
128 /* load the syscall number */
129 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
130 (offsetof(struct seccomp_data, nr))),
132 /* allow logging on stdout */
133 SC_ALLOW(write),
134 SC_ALLOW(writev),
135 SC_ALLOW(readv),
137 /* these are used to serve the files. note how we
138 * allow openat but not open. */
140 #ifdef __aarch64__
141 /* it seems that on aarch64 there isn't a poll(2)
142 * syscall, but instead it's implemented on top of
143 * ppoll(2). */
144 SC_ALLOW(ppoll),
145 #else
146 SC_ALLOW(poll),
147 #endif
148 SC_ALLOW(accept),
149 SC_ALLOW(read),
150 SC_ALLOW(openat),
151 SC_ALLOW(fstat),
152 SC_ALLOW(close),
153 SC_ALLOW(lseek),
154 SC_ALLOW(brk),
155 SC_ALLOW(mmap),
156 SC_ALLOW(munmap),
158 /* we need recvmsg to receive fd */
159 SC_ALLOW(recvmsg),
161 /* XXX: ??? */
162 SC_ALLOW(getpid),
164 /* alpine on amd64 does a clock_gettime(2) */
165 SC_ALLOW(clock_gettime),
167 SC_ALLOW(exit),
168 SC_ALLOW(exit_group),
170 /* allow only F_GETFL and F_SETFL fcntl */
171 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_fcntl, 0, 6),
172 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
173 (offsetof(struct seccomp_data, args[1]))),
174 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, F_GETFL, 0, 1),
175 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
176 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, F_SETFL, 0, 1),
177 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
178 BPF_STMT(BPF_RET | BPF_K, SC_FAIL),
180 /* re-load the syscall number */
181 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
182 (offsetof(struct seccomp_data, nr))),
184 /* allow ioctl but only on fd 1, glibc doing stuff? */
185 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ioctl, 0, 3),
186 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
187 (offsetof(struct seccomp_data, args[0]))),
188 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 1, 0, 1),
189 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
191 /* disallow enything else */
192 BPF_STMT(BPF_RET | BPF_K, SC_FAIL),
193 };
195 struct sock_fprog prog = {
196 .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])),
197 .filter = filter,
198 };
200 #ifdef SC_DEBUG
201 sandbox_seccomp_catch_sigsys();
202 #endif
204 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
205 fprintf(stderr, "%s: prctl(PR_SET_NO_NEW_PRIVS): %s\n",
206 __func__, strerror(errno));
207 exit(1);
210 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) == -1) {
211 fprintf(stderr, "%s: prctl(PR_SET_SECCOMP): %s\n",
212 __func__, strerror(errno));
213 exit(1);
217 #elif defined(__OpenBSD__)
219 #include <err.h>
220 #include <unistd.h>
222 void
223 sandbox()
225 struct vhost *h;
227 for (h = hosts; h->domain != NULL; ++h) {
228 if (unveil(h->dir, "rx") == -1)
229 err(1, "unveil %s for domain %s", h->dir, h->domain);
232 if (pledge("stdio recvfd rpath inet", NULL) == -1)
233 err(1, "pledge");
236 #else
238 void
239 sandbox()
241 LOGN(NULL, "%s", "no sandbox method known for this OS");
244 #endif