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 <string.h>
32 /* thanks chromium' src/seccomp.c */
33 #if defined(__i386__)
34 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_I386
35 #elif defined(__x86_64__)
36 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_X86_64
37 #elif defined(__arm__)
38 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM
39 #elif defined(__aarch64__)
40 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_AARCH64
41 #elif defined(__mips__)
42 # if defined(__mips64)
43 # if defined(__MIPSEB__)
44 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPS64
45 # else
46 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPSEL64
47 # endif
48 # else
49 # if defined(__MIPSEB__)
50 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPS
51 # else
52 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPSEL
53 # endif
54 # endif
55 #else
56 # error "Platform does not support seccomp filter yet"
57 #endif
59 /* uncomment to enable debugging. ONLY FOR DEVELOPMENT */
60 /* #define SC_DEBUG */
62 #ifdef SC_DEBUG
63 # define SC_FAIL SECCOMP_RET_TRAP
64 #else
65 # define SC_FAIL SECCOMP_RET_KILL
66 #endif
68 /* make the filter more readable */
69 #define SC_ALLOW(nr) \
70 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_##nr, 0, 1), \
71 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)
73 #ifdef SC_DEBUG
75 #include <signal.h>
76 #include <unistd.h>
78 static void
79 sandbox_seccomp_violation(int signum, siginfo_t *info, void *ctx)
80 {
81 (void)signum;
82 (void)ctx;
84 fprintf(stderr, "%s: unexpected system call (arch:0x%x,syscall:%d @ %p)\n",
85 __func__, info->si_arch, info->si_syscall, info->si_call_addr);
86 _exit(1);
87 }
89 static void
90 sandbox_seccomp_catch_sigsys(void)
91 {
92 struct sigaction act;
93 sigset_t mask;
95 memset(&act, 0, sizeof(act));
96 sigemptyset(&mask);
97 sigaddset(&mask, SIGSYS);
99 act.sa_sigaction = &sandbox_seccomp_violation;
100 act.sa_flags = SA_SIGINFO;
101 if (sigaction(SIGSYS, &act, NULL) == -1) {
102 fprintf(stderr, "%s: sigaction(SIGSYS): %s\n",
103 __func__, strerror(errno));
104 exit(1);
106 if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) {
107 fprintf(stderr, "%s: sigprocmask(SIGSYS): %s\n",
108 __func__, strerror(errno));
109 exit(1);
112 #endif /* SC_DEBUG */
114 void
115 sandbox()
117 struct sock_filter filter[] = {
118 /* load the *current* architecture */
119 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
120 (offsetof(struct seccomp_data, arch))),
121 /* ensure it's the same that we've been compiled on */
122 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,
123 SECCOMP_AUDIT_ARCH, 1, 0),
124 /* if not, kill the program */
125 BPF_STMT(BPF_RET | BPF_K, SC_FAIL),
127 /* load the syscall number */
128 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
129 (offsetof(struct seccomp_data, nr))),
131 /* allow logging on stdout */
132 SC_ALLOW(write),
133 SC_ALLOW(writev),
134 SC_ALLOW(readv),
136 /* these are used to serve the files. note how we
137 * allow openat but not open. */
139 #ifdef __aarch64__
140 /* it seems that on aarch64 there isn't a poll(2)
141 * syscall, but instead it's implemented on top of
142 * ppoll(2). */
143 SC_ALLOW(ppoll),
144 #else
145 SC_ALLOW(poll),
146 #endif
147 SC_ALLOW(accept),
148 SC_ALLOW(read),
149 SC_ALLOW(openat),
150 SC_ALLOW(fstat),
151 SC_ALLOW(close),
152 SC_ALLOW(lseek),
153 SC_ALLOW(brk),
154 SC_ALLOW(mmap),
155 SC_ALLOW(munmap),
157 /* we need recvmsg to receive fd */
158 SC_ALLOW(recvmsg),
160 /* XXX: ??? */
161 SC_ALLOW(getpid),
163 /* alpine on amd64 does a clock_gettime(2) */
164 SC_ALLOW(clock_gettime),
166 SC_ALLOW(exit),
167 SC_ALLOW(exit_group),
169 /* allow only F_GETFL and F_SETFL fcntl */
170 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_fcntl, 0, 6),
171 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
172 (offsetof(struct seccomp_data, args[1]))),
173 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, F_GETFL, 0, 1),
174 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
175 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, F_SETFL, 0, 1),
176 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
177 BPF_STMT(BPF_RET | BPF_K, SC_FAIL),
179 /* re-load the syscall number */
180 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
181 (offsetof(struct seccomp_data, nr))),
183 /* allow ioctl but only on fd 1, glibc doing stuff? */
184 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ioctl, 0, 3),
185 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
186 (offsetof(struct seccomp_data, args[0]))),
187 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 1, 0, 1),
188 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
190 /* disallow enything else */
191 BPF_STMT(BPF_RET | BPF_K, SC_FAIL),
192 };
194 struct sock_fprog prog = {
195 .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])),
196 .filter = filter,
197 };
199 #ifdef SC_DEBUG
200 sandbox_seccomp_catch_sigsys();
201 #endif
203 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
204 fprintf(stderr, "%s: prctl(PR_SET_NO_NEW_PRIVS): %s\n",
205 __func__, strerror(errno));
206 exit(1);
209 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) == -1) {
210 fprintf(stderr, "%s: prctl(PR_SET_SECCOMP): %s\n",
211 __func__, strerror(errno));
212 exit(1);
216 #elif defined(__OpenBSD__)
218 #include <err.h>
219 #include <unistd.h>
221 void
222 sandbox()
224 struct vhost *h;
226 for (h = hosts; h->domain != NULL; ++h) {
227 if (unveil(h->dir, "rx") == -1)
228 err(1, "unveil %s for domain %s", h->dir, h->domain);
231 if (pledge("stdio recvfd rpath inet", NULL) == -1)
232 err(1, "pledge");
235 #else
237 void
238 sandbox()
240 LOGN(NULL, "%s", "no sandbox method known for this OS");
243 #endif