Blob


1 #include "gmid.h"
3 #if defined(__FreeBSD__)
5 #include <sys/capsicum.h>
6 #include <err.h>
8 void
9 sandbox()
10 {
11 struct vhost *h;
12 int has_cgi = 0;
14 for (h = hosts; h->domain != NULL; ++h)
15 if (h->cgi != NULL)
16 has_cgi = 1;
18 if (cap_enter() == -1)
19 err(1, "cap_enter");
20 }
22 #elif defined(__linux__)
24 #include <sys/prctl.h>
25 #include <sys/syscall.h>
26 #include <sys/syscall.h>
27 #include <sys/types.h>
29 #include <linux/audit.h>
30 #include <linux/filter.h>
31 #include <linux/seccomp.h>
33 #include <errno.h>
34 #include <stddef.h>
35 #include <stdio.h>
36 #include <seccomp.h>
37 #include <string.h>
39 /* thanks chromium' src/seccomp.c */
40 #if defined(__i386__)
41 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_I386
42 #elif defined(__x86_64__)
43 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_X86_64
44 #elif defined(__arm__)
45 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM
46 #elif defined(__aarch64__)
47 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_AARCH64
48 #elif defined(__mips__)
49 # if defined(__mips64)
50 # if defined(__MIPSEB__)
51 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPS64
52 # else
53 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPSEL64
54 # endif
55 # else
56 # if defined(__MIPSEB__)
57 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPS
58 # else
59 # define SECCOMP_AUDIT_ARCH AUDIT_ARCH_MIPSEL
60 # endif
61 # endif
62 #else
63 # error "Platform does not support seccomp filter yet"
64 #endif
66 /* uncomment to enable debugging. ONLY FOR DEVELOPMENT */
67 /* #define SC_DEBUG */
69 #ifdef SC_DEBUG
70 # define SC_FAIL SECCOMP_RET_TRAP
71 #else
72 # define SC_FAIL SECCOMP_RET_KILL
73 #endif
75 /* make the filter more readable */
76 #define SC_ALLOW(nr) \
77 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_##nr, 0, 1), \
78 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)
80 #ifdef SC_DEBUG
82 #include <signal.h>
83 #include <unistd.h>
85 static void
86 sandbox_seccomp_violation(int signum, siginfo_t *info, void *ctx)
87 {
88 (void)signum;
89 (void)ctx;
91 fprintf(stderr, "%s: unexpected system call (arch:0x%x,syscall:%d @ %p)\n",
92 __func__, info->si_arch, info->si_syscall, info->si_call_addr);
93 _exit(1);
94 }
96 static void
97 sandbox_seccomp_catch_sigsys(void)
98 {
99 struct sigaction act;
100 sigset_t mask;
102 memset(&act, 0, sizeof(act));
103 sigemptyset(&mask);
104 sigaddset(&mask, SIGSYS);
106 act.sa_sigaction = &sandbox_seccomp_violation;
107 act.sa_flags = SA_SIGINFO;
108 if (sigaction(SIGSYS, &act, NULL) == -1) {
109 fprintf(stderr, "%s: sigaction(SIGSYS): %s\n",
110 __func__, strerror(errno));
111 exit(1);
113 if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) {
114 fprintf(stderr, "%s: sigprocmask(SIGSYS): %s\n",
115 __func__, strerror(errno));
116 exit(1);
119 #endif /* SC_DEBUG */
121 void
122 sandbox()
124 struct sock_filter filter[] = {
125 /* load the *current* architecture */
126 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
127 (offsetof(struct seccomp_data, arch))),
128 /* ensure it's the same that we've been compiled on */
129 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,
130 SECCOMP_AUDIT_ARCH, 1, 0),
131 /* if not, kill the program */
132 BPF_STMT(BPF_RET | BPF_K, SC_FAIL),
134 /* load the syscall number */
135 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
136 (offsetof(struct seccomp_data, nr))),
138 /* allow logging on stdout */
139 SC_ALLOW(write),
140 SC_ALLOW(writev),
141 SC_ALLOW(readv),
143 /* these are used to serve the files. note how we
144 * allow openat but not open. */
145 SC_ALLOW(ppoll),
146 SC_ALLOW(accept),
147 SC_ALLOW(fcntl),
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 SC_ALLOW(exit),
164 SC_ALLOW(exit_group),
166 /* allow ioctl but only on fd 1, glibc doing stuff? */
167 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ioctl, 0, 3),
168 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
169 (offsetof(struct seccomp_data, args[0]))),
170 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 1, 0, 1),
171 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
173 /* disallow enything else */
174 BPF_STMT(BPF_RET | BPF_K, SC_FAIL),
175 };
177 struct sock_fprog prog = {
178 .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])),
179 .filter = filter,
180 };
182 #ifdef SC_DEBUG
183 sandbox_seccomp_catch_sigsys();
184 #endif
186 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
187 fprintf(stderr, "%s: prctl(PR_SET_NO_NEW_PRIVS): %s\n",
188 __func__, strerror(errno));
189 exit(1);
192 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) == -1) {
193 fprintf(stderr, "%s: prctl(PR_SET_SECCOMP): %s\n",
194 __func__, strerror(errno));
195 exit(1);
199 #elif defined(__OpenBSD__)
201 #include <err.h>
202 #include <unistd.h>
204 void
205 sandbox()
207 struct vhost *h;
209 for (h = hosts; h->domain != NULL; ++h) {
210 if (unveil(h->dir, "rx") == -1)
211 err(1, "unveil %s for domain %s", h->dir, h->domain);
214 if (pledge("stdio recvfd rpath inet", NULL) == -1)
215 err(1, "pledge");
218 #else
220 void
221 sandbox()
223 LOGN(NULL, "%s", "no sandbox method known for this OS");
226 #endif