💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Vgmi › files › ca6311df99c0df2e5231e36b3e152… captured on 2022-07-16 at 17:12:36. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
0 /* See LICENSE file for copyright and license details. */
1 #ifndef DISABLE_XDG
2 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__)
3
4 int xdg_pipe[2];
5 int xdg_open(char*);
6
7 #include <string.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <signal.h>
12 #include <sys/wait.h>
13 #include <errno.h>
14 #ifdef __linux__
15 #include <sys/prctl.h>
16 #endif
17 #include <termbox.h>
18
19 int xdg_request(char* str) {
20 int len = strnlen(str, 1024)+1;
21 return write(xdg_pipe[1], str, len) != len;
22 }
23
24 void xdg_listener() {
25 char buf[4096];
26 while (1) {
27 int len = read(xdg_pipe[0], buf, sizeof(buf));
28 if (len <= 0)
29 break;
30 xdg_open(buf);
31 }
32 }
33
34 int xdg_init() {
35 if (pipe(xdg_pipe)) {
36 printf("pipe failed\n");
37 return -1;
38 }
39 int pid = fork();
40 if (pid != 0) {
41 close(xdg_pipe[0]);
42 return 0;
43 }
44 close(xdg_pipe[1]);
45 #ifdef __OpenBSD__
46 if (unveil("/bin/sh", "x") ||
47 unveil("/usr/bin/which", "x") ||
48 unveil("/usr/local/bin/xdg-open", "x") ||
49 unveil(NULL, NULL)) {
50 close(xdg_pipe[1]);
51 exit(0);
52 }
53 if (pledge("stdio rpath exec proc", NULL)) {
54 close(xdg_pipe[1]);
55 exit(0);
56 }
57 #endif
58 #ifdef __linux__
59 prctl(PR_SET_NAME, "vgmi [xdg]", 0, 0, 0);
60 #endif
61 xdg_listener();
62 exit(0);
63 }
64
65 int sandbox_close() {
66 close(xdg_pipe[0]);
67 close(xdg_pipe[1]);
68 return 0;
69 }
70
71 #endif
72 #endif
73
74 #ifdef __FreeBSD__
75 #include <stdio.h>
76 #include <sys/capsicum.h>
77 #include <sys/socket.h>
78 #include <netinet/in.h>
79 #include <netdb.h>
80 #include <strings.h>
81 #define WITH_CASPER
82 #include <sys/nv.h>
83 #include <libcasper.h>
84 #include <casper/cap_net.h>
85 #include <capsicum_helpers.h>
86
87 cap_channel_t *_capnet;
88 cap_net_limit_t* limit;
89
90 int sandbox_connect(int s, const struct sockaddr *name, socklen_t namelen) {
91 return cap_connect(_capnet, s, name, namelen);
92 }
93
94 int sandbox_getaddrinfo(const char *hostname, const char *servname,
95 const struct addrinfo *hints, struct addrinfo **res) {
96 return cap_getaddrinfo(_capnet, hostname, servname, hints, res);
97 }
98
99 #include "cert.h"
100 int sandbox_init() {
101 #ifndef DISABLE_XDG
102 if (xdg_init()) {
103 printf("xdg failure\n");
104 return -1;
105 }
106 #endif
107 if (getconfigfd() < 0) {
108 printf("Unable to open/create config folder\n");
109 return -1;
110 }
111 if (chdir("/var/empty")) {
112 printf("chdir failure\n");
113 return -1;
114 }
115
116 cap_rights_t rights;
117 cap_rights_init(&rights, CAP_WRITE, CAP_LOOKUP, CAP_READ,
118 CAP_SEEK, CAP_CREATE, CAP_FCNTL);
119 if (cap_rights_limit(config_fd, &rights)) {
120 printf("cap_rights_limit failed\n");
121 return -1;
122 }
123
124 cap_channel_t *capcas;
125 capcas = cap_init();
126 if (capcas == NULL) {
127 printf("cap_init failed\n");
128 return -1;
129 }
130 caph_cache_catpages();
131 if (caph_enter()) {
132 printf("cap_enter failed\n");
133 return -1;
134 }
135 _capnet = cap_service_open(capcas, "system.net");
136 cap_close(capcas);
137 if (_capnet == NULL) {
138 printf("failed to open system.net service\n");
139 return -1;
140 }
141 limit = cap_net_limit_init(_capnet,
142 CAPNET_NAME2ADDR | CAPNET_CONNECTDNS | CAPNET_CONNECT);
143 if (limit == NULL) {
144 printf("Unable to create limits.\n");
145 return -1;
146 }
147 int families[] = {AF_INET, AF_INET6};
148 cap_net_limit_name2addr_family(limit, families, 2);
149 if (cap_net_limit(limit) < 0) {
150 printf("Unable to apply limits.\n");
151 return -1;
152 }
153 return 0;
154 }
155
156 int makefd_readonly(int fd) {
157 cap_rights_t rights;
158 cap_rights_init(&rights, CAP_SEEK, CAP_READ);
159 if (cap_rights_limit(fd, &rights))
160 return -1;
161 return 0;
162 }
163
164 int make_readonly(FILE* f) {
165 return makefd_readonly(fileno(f));
166 }
167
168 int makefd_writeonly(int fd) {
169 cap_rights_t rights;
170 cap_rights_init(&rights, CAP_WRITE);
171 if (cap_rights_limit(fd, &rights))
172 return -1;
173 return 0;
174 }
175
176 int makefd_writeseek(int fd) {
177 cap_rights_t rights;
178 cap_rights_init(&rights, CAP_WRITE, CAP_SEEK);
179 if (cap_rights_limit(fd, &rights))
180 return -1;
181 return 0;
182 }
183
184 int make_writeonly(FILE* f) {
185 return makefd_writeonly(fileno(f));
186 }
187 #elif __OpenBSD__
188 #include <stdio.h>
189 #include <stdlib.h>
190 #include <unistd.h>
191 #include "cert.h"
192
193 extern char home_path[1024];
194 extern char config_path[1024];
195
196 int sandbox_init() {
197 #ifndef DISABLE_XDG
198 if (xdg_init()) {
199 printf("xdg failure\n");
200 return -1;
201 }
202 #endif
203 #ifndef HIDE_HOME
204 if (gethomefd() < 1) {
205 printf("Failed to get home folder\n");
206 return -1;
207 }
208 #endif
209 if (getconfigfd() < 0) {
210 printf("Failed to get cache folder\n");
211 return -1;
212 }
213 if (getdownloadfd() < 0) {
214 printf("Failed to get download folder\n");
215 return -1;
216 }
217 if (
218 #ifndef HIDE_HOME
219 unveil(home_path, "r") ||
220 #endif
221 unveil(config_path, "rwc") ||
222 unveil(download_path, "rwc") ||
223 unveil("/etc/resolv.conf", "r") ||
224 unveil(NULL, NULL)) {
225 printf("Failed to unveil\n");
226 return -1;
227 }
228 if (pledge("stdio rpath wpath cpath inet dns tty", NULL)) {
229 printf("Failed to pledge\n");
230 return -1;
231 }
232 return 0;
233 }
234
235 #elif __linux__
236 #include <stdio.h>
237 #include <fcntl.h>
238 #include <unistd.h>
239 #include <stddef.h>
240 #include <linux/seccomp.h>
241 #include <linux/filter.h>
242 #include <linux/unistd.h>
243 #if ENABLE_LANDLOCK || (!defined(DISABLE_LANDLOCK) && __has_include(<linux/landlock.h>))
244 #include <linux/landlock.h>
245 #define ENABLE_LANDLOCK
246 #endif
247 #include "cert.h"
248
249 // --------------
250 // copied from : https://roy.marples.name/git/dhcpcd/blob/HEAD:/src/privsep-linux.c
251 #define SC_ALLOW_(nr) \
252 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, nr, 0, 1), \
253 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)
254
255 #define SC_ALLOW(nr) \
256 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_##nr, 0, 1), \
257 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)
258
259 #define SC_ALLOW_ARG(_nr, _arg, _val) \
260 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (_nr), 0, 6), \
261 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
262 offsetof(struct seccomp_data, args[(_arg)]) + SC_ARG_LO), \
263 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, \
264 ((_val) & 0xffffffff), 0, 3), \
265 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
266 offsetof(struct seccomp_data, args[(_arg)]) + SC_ARG_HI), \
267 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, \
268 (((uint32_t)((uint64_t)(_val) >> 32)) & 0xffffffff), 0, 1), \
269 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW), \
270 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
271 offsetof(struct seccomp_data, nr))
272 // --------------
273
274 struct sock_filter filter[] = {
275 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
276 (offsetof(struct seccomp_data, arch))),
277 BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))),
278 //#ifdef __MUSL__
279 SC_ALLOW(readv),
280 SC_ALLOW(writev),
281 SC_ALLOW(open),
282 SC_ALLOW(dup2), // required by getaddrinfo
283 //#else
284 SC_ALLOW(pipe2), // tb_init
285 SC_ALLOW(recvmsg), // getaddrinfo_a
286 SC_ALLOW(getsockname), // getaddrinfo_a
287 //#endif
288 SC_ALLOW(fstat), // older glibc and musl
289 SC_ALLOW(stat), // older glibc
290 SC_ALLOW(pipe), // older glibc and musl
291 SC_ALLOW(setsockopt),
292 SC_ALLOW(read),
293 SC_ALLOW(write),
294 SC_ALLOW(openat),
295 SC_ALLOW(close),
296 SC_ALLOW(exit),
297 SC_ALLOW(ioctl),
298 SC_ALLOW(exit_group),
299 SC_ALLOW(futex),
300 SC_ALLOW(sysinfo),
301 SC_ALLOW(brk),
302 SC_ALLOW(newfstatat),
303 SC_ALLOW(getpid),
304 SC_ALLOW(getrandom),
305 SC_ALLOW(mmap),
306 SC_ALLOW(fcntl),
307 SC_ALLOW(lseek),
308 SC_ALLOW(rt_sigaction),
309 SC_ALLOW(rt_sigprocmask),
310 SC_ALLOW(rt_sigreturn), // resizing
311 SC_ALLOW(mprotect),
312 SC_ALLOW(pread64),
313 SC_ALLOW(uname), // getaddrinfo
314 SC_ALLOW(ppoll), // getaddrinfo
315 SC_ALLOW(bind), // getaddrinfo
316 SC_ALLOW(sendto),
317 SC_ALLOW(recvfrom),
318 SC_ALLOW(socket),
319 SC_ALLOW(socketpair),
320 SC_ALLOW(connect),
321 SC_ALLOW(getsockopt),
322 SC_ALLOW(poll),
323 SC_ALLOW(clone),
324 #ifdef __NR_clone3
325 SC_ALLOW(clone3),
326 #endif
327 SC_ALLOW(clock_nanosleep),
328 SC_ALLOW(nanosleep),
329 SC_ALLOW(rseq), // pthread_create
330 SC_ALLOW(set_robust_list), // pthread_create
331 SC_ALLOW(munmap), // pthread_create
332 SC_ALLOW(madvise), // thread exit
333 SC_ALLOW(mremap), // realloc
334 SC_ALLOW(select), // on old version of linux
335 SC_ALLOW(membarrier),
336 SC_ALLOW(sendmmsg),
337 #ifdef __NR_pselect6
338 SC_ALLOW(pselect6),
339 #endif
340 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
341 };
342
343 #ifdef ENABLE_LANDLOCK
344 static inline int landlock_create_ruleset(const struct landlock_ruleset_attr *attr,
345 size_t size, uint32_t flags)
346 {
347 return syscall(__NR_landlock_create_ruleset, attr, size, flags);
348 }
349
350 static inline int landlock_add_rule(int ruleset_fd, enum landlock_rule_type type,
351 const void *attr, uint32_t flags)
352 {
353 return syscall(__NR_landlock_add_rule, ruleset_fd, type, attr, flags);
354 }
355
356 static inline int landlock_restrict_self(int ruleset_fd, __u32 flags)
357 {
358 return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
359 }
360
361 int landlock_unveil(int landlock_fd, int fd, int perms)
362 {
363 struct landlock_path_beneath_attr attr = {
364 .allowed_access = perms,
365 .parent_fd = fd
366 };
367
368 int ret = landlock_add_rule(landlock_fd, LANDLOCK_RULE_PATH_BENEATH, &attr, 0);
369 int err = errno;
370 close(attr.parent_fd);
371 errno = err;
372 return ret;
373 }
374
375 #include <fcntl.h>
376 int landlock_unveil_path(int landlock_fd, const char* path, int perms) {
377 int fd = open(path, 0);
378 if (fd < 0) return -1;
379 int ret = landlock_unveil(landlock_fd, fd, perms);
380 return ret;
381 }
382
383 int landlock_init() {
384 struct landlock_ruleset_attr attr = {
385 .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE |
386 LANDLOCK_ACCESS_FS_READ_FILE |
387 LANDLOCK_ACCESS_FS_READ_DIR |
388 LANDLOCK_ACCESS_FS_WRITE_FILE |
389 LANDLOCK_ACCESS_FS_REMOVE_DIR |
390 LANDLOCK_ACCESS_FS_REMOVE_FILE |
391 LANDLOCK_ACCESS_FS_MAKE_CHAR |
392 LANDLOCK_ACCESS_FS_MAKE_DIR |
393 LANDLOCK_ACCESS_FS_MAKE_REG |
394 LANDLOCK_ACCESS_FS_MAKE_SOCK |
395 LANDLOCK_ACCESS_FS_MAKE_FIFO |
396 LANDLOCK_ACCESS_FS_MAKE_BLOCK |
397 LANDLOCK_ACCESS_FS_MAKE_SYM,
398 };
399 return landlock_create_ruleset(&attr, sizeof(attr), 0);
400 }
401
402 int landlock_apply(int fd)
403 {
404 int ret = landlock_restrict_self(fd, 0);
405 int err = errno;
406 close(fd);
407 errno = err;
408 return ret;
409 }
410
411 extern char config_path[1024];
412 extern char download_path[1024];
413 #endif
414
415 int sandbox_init() {
416 #ifndef DISABLE_XDG
417 if (xdg_init()) {
418 printf("xdg failure\n");
419 return -1;
420 }
421 #endif
422 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
423 printf("PR_SET_NO_NEW_PRIVS failed\n");
424 return -1;
425 }
426
427 int dfd = getdownloadfd();
428 int cfd = getconfigfd();
429 if (cfd < 0 || dfd < 0) {
430 printf("Failed to access folders\n");
431 return -1;
432 }
433 #ifdef ENABLE_LANDLOCK
434 int llfd = landlock_init();
435 if (llfd < 0) {
436 printf("[WARNING] Failed to initialize landlock : %!s(MISSING)\n", strerror(errno));
437 printf("[WARNING] The filesystem won't be hidden from the program\n");
438 goto skip_landlock;
439 }
440 #ifndef HIDE_HOME
441 #include <pwd.h>
442 struct passwd *pw = getpwuid(geteuid());
443 if (!pw) {
444 printf("failed to get home folder: %!s(MISSING)\n", strerror(errno));
445 return -1;
446 }
447 int home = landlock_unveil_path(llfd, pw->pw_dir,
448 LANDLOCK_ACCESS_FS_READ_FILE);
449 #endif
450 int cfg = landlock_unveil_path(llfd, config_path,
451 LANDLOCK_ACCESS_FS_READ_FILE |
452 LANDLOCK_ACCESS_FS_WRITE_FILE |
453 LANDLOCK_ACCESS_FS_MAKE_REG);
454 int dl = landlock_unveil_path(llfd, download_path,
455 LANDLOCK_ACCESS_FS_WRITE_FILE |
456 LANDLOCK_ACCESS_FS_MAKE_REG);
457 int hosts = landlock_unveil_path(llfd, "/etc/hosts",
458 LANDLOCK_ACCESS_FS_READ_FILE);
459 int run = landlock_unveil_path(llfd, "/run",
460 LANDLOCK_ACCESS_FS_READ_FILE);
461
462 int resolv = landlock_unveil_path(llfd, "/etc/resolv.conf",
463 LANDLOCK_ACCESS_FS_READ_FILE);
464
465 if (dl || cfg || hosts || run || home || resolv) {
466 printf("landlock, failed to unveil : %!s(MISSING)\n", strerror(errno));
467 return -1;
468 }
469
470 #ifndef __MUSL__
471 // load dynamic library before restricting process
472 struct addrinfo hints, *result;
473 bzero(&hints, sizeof(hints));
474 hints.ai_family = AF_INET;
475 hints.ai_socktype = SOCK_STREAM;
476 hints.ai_flags |= AI_CANONNAME;
477
478 if (getaddrinfo("example.com", NULL, &hints, &result)) {
479 printf("getaddrinfo failed\n");
480 return -1;
481 }
482 #endif
483 if (landlock_apply(llfd)) {
484 printf("landlock, failed to restrict process : %!s(MISSING)\n", strerror(errno));
485 return -1;
486 }
487 skip_landlock:;
488 #endif
489 struct sock_fprog prog = {
490 .len = (unsigned short)(sizeof(filter) / sizeof (filter[0])),
491 .filter = filter,
492 };
493 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0)) {
494 printf("Failed to enable seccomp\n");
495 return -1;
496 }
497 return 0;
498 }
499
500 #else
501 #define NOSANDBOX
502 int sandbox_init() {
503 return 0;
504 }
505
506 int sandbox_close() {
507 return 0;
508 }
509 #endif
510
511 #if !defined(NOSANDBOX) && defined(DISABLE_XDG)
512 int sandbox_close() {
513 return 0;
514 }
515 #endif
516