💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Vgmi › files › f9acdd9cf41bb5b837be9d4373da0… captured on 2023-04-19 at 23:05:40. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
0 /* See LICENSE file for copyright and license details. */
1 #define SB_IGNORE
2 #include "sandbox.h"
3 #include "xdg.h"
4 #include <string.h>
5 #include <errno.h>
6 #if defined(__linux__) && !defined(__MUSL__)
7 #include <dlfcn.h>
8 #include <stdlib.h>
9 void* libgcc_s = NULL;
10 #endif
11 #ifdef __linux__
12 #include <sys/prctl.h>
13 #endif
14
15 #ifndef NO_SANDBOX
16
17 #ifdef __FreeBSD__
18
19 #include <stdio.h>
20 #include <sys/capsicum.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <netdb.h>
24 #include <strings.h>
25 #define WITH_CASPER
26 #include <sys/nv.h>
27 #include <libcasper.h>
28 #include <casper/cap_net.h>
29 #include <capsicum_helpers.h>
30
31 cap_channel_t *_capnet;
32 cap_net_limit_t* limit;
33
34 int sandbox_connect(int s, const struct sockaddr *name, socklen_t namelen) {
35 return cap_connect(_capnet, s, name, namelen);
36 }
37
38 int sandbox_getaddrinfo(const char *hostname, const char *servname,
39 const struct addrinfo *hints, struct addrinfo **res) {
40 return cap_getaddrinfo(_capnet, hostname, servname, hints, res);
41 }
42
43 #include "cert.h"
44 int sandbox_init() {
45 #ifndef DISABLE_XDG
46 if (xdg_init()) {
47 printf("xdg failure\n");
48 return -1;
49 }
50 #endif
51 if (getconfigfd() < 0) {
52 printf("Unable to open/create config folder\n");
53 return -1;
54 }
55 if (chdir("/var/empty")) {
56 printf("chdir failure\n");
57 return -1;
58 }
59
60 cap_rights_t rights;
61 cap_rights_init(&rights, CAP_WRITE, CAP_LOOKUP, CAP_READ,
62 CAP_SEEK, CAP_CREATE, CAP_FCNTL, CAP_FTRUNCATE);
63 if (cap_rights_limit(config_fd, &rights)) {
64 printf("cap_rights_limit failed\n");
65 return -1;
66 }
67
68 cap_channel_t *capcas;
69 capcas = cap_init();
70 if (capcas == NULL) {
71 printf("cap_init failed\n");
72 return -1;
73 }
74 caph_cache_catpages();
75 if (caph_enter()) {
76 printf("cap_enter failed\n");
77 return -1;
78 }
79 _capnet = cap_service_open(capcas, "system.net");
80 cap_close(capcas);
81 if (_capnet == NULL) {
82 printf("failed to open system.net service\n");
83 return -1;
84 }
85 limit = cap_net_limit_init(_capnet,
86 CAPNET_NAME2ADDR |
87 CAPNET_CONNECTDNS |
88 CAPNET_CONNECT);
89 if (limit == NULL) {
90 printf("Unable to create limits.\n");
91 return -1;
92 }
93 int families[] = {AF_INET, AF_INET6};
94 cap_net_limit_name2addr_family(limit, families, 2);
95 if (cap_net_limit(limit) < 0) {
96 printf("Unable to apply limits.\n");
97 return -1;
98 }
99 return 0;
100 }
101
102 int sandbox_close() {
103 #ifndef DISABLE_XDG
104 xdg_close();
105 #endif
106 return 0;
107 }
108
109 int makefd_readonly(int fd) {
110 cap_rights_t rights;
111 cap_rights_init(&rights, CAP_SEEK, CAP_READ);
112 if (cap_rights_limit(fd, &rights))
113 return -1;
114 return 0;
115 }
116
117 int make_readonly(FILE* f) {
118 return makefd_readonly(fileno(f));
119 }
120
121 int makefd_writeonly(int fd) {
122 cap_rights_t rights;
123 cap_rights_init(&rights, CAP_WRITE);
124 if (cap_rights_limit(fd, &rights))
125 return -1;
126 return 0;
127 }
128
129 int makefd_writeseek(int fd) {
130 cap_rights_t rights;
131 cap_rights_init(&rights, CAP_WRITE, CAP_SEEK);
132 if (cap_rights_limit(fd, &rights))
133 return -1;
134 return 0;
135 }
136
137 int make_writeonly(FILE* f) {
138 return makefd_writeonly(fileno(f));
139 }
140
141 #elif __OpenBSD__
142
143 #include <stdio.h>
144 #include <stdlib.h>
145 #include <unistd.h>
146 #include "cert.h"
147
148 extern char home_path[1024];
149 extern char config_path[1024];
150
151 int sandbox_init() {
152 #ifndef DISABLE_XDG
153 if (xdg_init()) {
154 printf("xdg failure\n");
155 return -1;
156 }
157 #endif
158 #ifndef HIDE_HOME
159 if (gethomefd() < 1) {
160 printf("Failed to get home folder\n");
161 return -1;
162 }
163 #endif
164 if (getconfigfd() < 0) {
165 printf("Failed to get cache folder\n");
166 return -1;
167 }
168 if (getdownloadfd() < 0) {
169 printf("Failed to get download folder\n");
170 return -1;
171 }
172 if (
173 #ifndef HIDE_HOME
174 unveil(home_path, "r") ||
175 #endif
176 unveil(config_path, "rwc") ||
177 unveil(download_path, "rwc") ||
178 unveil("/etc/resolv.conf", "r") ||
179 unveil(NULL, NULL)) {
180 printf("Failed to unveil\n");
181 return -1;
182 }
183 if (pledge("stdio rpath wpath cpath inet dns tty", NULL)) {
184 printf("Failed to pledge\n");
185 return -1;
186 }
187 return 0;
188 }
189
190 int sandbox_close() {
191 #ifndef DISABLE_XDG
192 xdg_close();
193 #endif
194 return 0;
195 }
196
197 #elif __linux__
198
199 #include <stdio.h>
200 #include <fcntl.h>
201 #include <unistd.h>
202 #include <stddef.h>
203 #include <linux/seccomp.h>
204 #include <linux/filter.h>
205 #include <linux/unistd.h>
206 #if ENABLE_LANDLOCK || (!defined(DISABLE_LANDLOCK) && \
207 __has_include(<linux/landlock.h>))
208 #include <linux/landlock.h>
209 #define ENABLE_LANDLOCK
210 #endif
211 #include "cert.h"
212
213 // --------------
214 #define SC_ALLOW_(nr) \
215 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, nr, 0, 1), \
216 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)
217
218 #define SC_ALLOW(nr) \
219 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_##nr, 0, 1), \
220 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)
221
222 #define SC_ALLOW_ARG(_nr, _arg, _val) \
223 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (_nr), 0, 6), \
224 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
225 offsetof(struct seccomp_data, args[(_arg)]) + SC_ARG_LO), \
226 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, \
227 ((_val) & 0xffffffff), 0, 3), \
228 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
229 offsetof(struct seccomp_data, args[(_arg)]) + SC_ARG_HI), \
230 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, \
231 (((uint32_t)((uint64_t)(_val) >> 32)) & 0xffffffff), 0, 1), \
232 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW), \
233 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
234 offsetof(struct seccomp_data, nr))
235 // --------------
236
237 struct sock_filter filter[] = {
238 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
239 (offsetof(struct seccomp_data, arch))),
240 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
241 (offsetof(struct seccomp_data, nr))),
242 SC_ALLOW(readv),
243 SC_ALLOW(writev),
244 #ifdef __NR_open
245 SC_ALLOW(open),
246 #endif
247 #ifdef __NR_dup2
248 SC_ALLOW(dup2), // required by getaddrinfo
249 #endif
250 SC_ALLOW(pipe2), // tb_init
251 SC_ALLOW(recvmsg), // getaddrinfo_a
252 SC_ALLOW(getsockname), // getaddrinfo_a
253 SC_ALLOW(fstat), // older glibc and musl
254 #ifdef __NR_stat
255 SC_ALLOW(stat), // older glibc
256 #endif
257 #ifdef __NR_pipe
258 SC_ALLOW(pipe), // older glibc and musl
259 #endif
260 SC_ALLOW(setsockopt),
261 SC_ALLOW(read),
262 SC_ALLOW(write),
263 SC_ALLOW(openat),
264 SC_ALLOW(close),
265 SC_ALLOW(exit),
266 SC_ALLOW(ioctl),
267 SC_ALLOW(exit_group),
268 SC_ALLOW(futex),
269 SC_ALLOW(sysinfo),
270 SC_ALLOW(brk),
271 SC_ALLOW(newfstatat),
272 SC_ALLOW(getpid),
273 SC_ALLOW(getrandom),
274 SC_ALLOW(mmap),
275 SC_ALLOW(fcntl),
276 SC_ALLOW(lseek),
277 SC_ALLOW(rt_sigaction),
278 SC_ALLOW(rt_sigprocmask),
279 SC_ALLOW(rt_sigreturn), // resizing
280 SC_ALLOW(mprotect),
281 SC_ALLOW(pread64),
282 SC_ALLOW(uname), // getaddrinfo
283 SC_ALLOW(ppoll), // getaddrinfo
284 SC_ALLOW(bind), // getaddrinfo
285 SC_ALLOW(sendto),
286 SC_ALLOW(recvfrom),
287 SC_ALLOW(socket),
288 SC_ALLOW(socketpair),
289 SC_ALLOW(connect),
290 SC_ALLOW(getsockopt),
291 #ifdef __NR_poll
292 SC_ALLOW(poll),
293 #endif
294 SC_ALLOW(clone),
295 #ifdef __NR_clone3
296 SC_ALLOW(clone3),
297 #endif
298 SC_ALLOW(clock_nanosleep),
299 SC_ALLOW(nanosleep),
300 SC_ALLOW(rseq), // pthread_create
301 SC_ALLOW(set_robust_list), // pthread_create
302 SC_ALLOW(munmap), // pthread_create
303 SC_ALLOW(madvise), // thread exit
304 SC_ALLOW(mremap), // realloc
305 #ifdef __NR_select
306 SC_ALLOW(select), // on old version of linux
307 #endif
308 SC_ALLOW(membarrier),
309 SC_ALLOW(sendmmsg),
310 #ifdef __NR_pselect6
311 SC_ALLOW(pselect6),
312 #endif
313 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
314 };
315
316 #ifdef ENABLE_LANDLOCK
317 static inline int landlock_create_ruleset(
318 const struct landlock_ruleset_attr *attr, size_t size, uint32_t flags)
319 {
320 return syscall(__NR_landlock_create_ruleset, attr, size, flags);
321 }
322
323 static inline int landlock_add_rule(int ruleset_fd,
324 enum landlock_rule_type type,
325 const void *attr, uint32_t flags)
326 {
327 return syscall(__NR_landlock_add_rule, ruleset_fd, type, attr, flags);
328 }
329
330 static inline int landlock_restrict_self(int ruleset_fd, __u32 flags)
331 {
332 return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
333 }
334
335 int landlock_unveil(int landlock_fd, int fd, int perms)
336 {
337 struct landlock_path_beneath_attr attr = {
338 .allowed_access = perms,
339 .parent_fd = fd
340 };
341
342 int ret = landlock_add_rule(landlock_fd, LANDLOCK_RULE_PATH_BENEATH,
343 &attr, 0);
344 int err = errno;
345 close(attr.parent_fd);
346 errno = err;
347 return ret;
348 }
349
350 #include <fcntl.h>
351 int landlock_unveil_path(int landlock_fd, const char* path, int perms) {
352 int fd = open(path, 0);
353 if (fd < 0) return -1;
354 int ret = landlock_unveil(landlock_fd, fd, perms);
355 return ret;
356 }
357
358 int landlock_init() {
359 struct landlock_ruleset_attr attr = {
360 .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE |
361 LANDLOCK_ACCESS_FS_READ_FILE |
362 LANDLOCK_ACCESS_FS_READ_DIR |
363 LANDLOCK_ACCESS_FS_WRITE_FILE |
364 LANDLOCK_ACCESS_FS_REMOVE_DIR |
365 LANDLOCK_ACCESS_FS_REMOVE_FILE |
366 LANDLOCK_ACCESS_FS_MAKE_CHAR |
367 LANDLOCK_ACCESS_FS_MAKE_DIR |
368 LANDLOCK_ACCESS_FS_MAKE_REG |
369 LANDLOCK_ACCESS_FS_MAKE_SOCK |
370 LANDLOCK_ACCESS_FS_MAKE_FIFO |
371 LANDLOCK_ACCESS_FS_MAKE_BLOCK |
372 LANDLOCK_ACCESS_FS_MAKE_SYM,
373 };
374 return landlock_create_ruleset(&attr, sizeof(attr), 0);
375 }
376
377 int landlock_apply(int fd)
378 {
379 int ret = landlock_restrict_self(fd, 0);
380 int err = errno;
381 close(fd);
382 errno = err;
383 return ret;
384 }
385
386 extern char config_path[1024];
387 extern char download_path[1024];
388 #endif
389
390 int sandbox_init() {
391 #ifndef DISABLE_XDG
392 if (xdg_init()) {
393 printf("xdg failure\n");
394 return -1;
395 }
396 #endif
397 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
398 printf("PR_SET_NO_NEW_PRIVS failed\n");
399 return -1;
400 }
401
402 int dfd = getdownloadfd();
403 int cfd = getconfigfd();
404 if (cfd < 0 || dfd < 0) {
405 printf("Failed to access folders\n");
406 return -1;
407 }
408 #ifdef ENABLE_LANDLOCK
409 int llfd = landlock_init();
410 if (llfd < 0) {
411 printf("[WARNING] Failed to initialize landlock : %s\n",
412 strerror(errno));
413 printf("[WARNING] The filesystem won't " \
414 "be hidden from the program\n");
415 goto skip_landlock;
416 }
417 int home = 0;
418 #ifndef HIDE_HOME
419 #include <pwd.h>
420 struct passwd *pw = getpwuid(geteuid());
421 if (!pw) {
422 printf("failed to get home folder: %s\n", strerror(errno));
423 return -1;
424 }
425 home = landlock_unveil_path(llfd, pw->pw_dir,
426 LANDLOCK_ACCESS_FS_READ_FILE);
427 #endif
428 int cfg = landlock_unveil_path(llfd, config_path,
429 LANDLOCK_ACCESS_FS_READ_FILE |
430 LANDLOCK_ACCESS_FS_WRITE_FILE |
431 LANDLOCK_ACCESS_FS_MAKE_REG);
432 int dl = landlock_unveil_path(llfd, download_path,
433 LANDLOCK_ACCESS_FS_WRITE_FILE |
434 LANDLOCK_ACCESS_FS_MAKE_REG);
435 int hosts = landlock_unveil_path(llfd, "/etc/hosts",
436 LANDLOCK_ACCESS_FS_READ_FILE);
437 int run = landlock_unveil_path(llfd, "/run",
438 LANDLOCK_ACCESS_FS_READ_FILE);
439
440 int resolv = landlock_unveil_path(llfd, "/etc/resolv.conf",
441 LANDLOCK_ACCESS_FS_READ_FILE);
442
443 if (dl || cfg || hosts || run || home || resolv) {
444 printf("landlock, failed to unveil : %s\n", strerror(errno));
445 return -1;
446 }
447
448 #ifndef __MUSL__
449 // with glibc, load dynamic library before restricting process
450 libgcc_s = dlopen("/lib64/libgcc_s.so.1", RTLD_LAZY);
451 if (!libgcc_s)
452 printf("failed to load libgcc_s.so.1, " \
453 "unexpected behaviors may occur\n");
454 #endif
455 if (landlock_apply(llfd)) {
456 printf("landlock, failed to restrict process : %s\n",
457 strerror(errno));
458 return -1;
459 }
460 skip_landlock:;
461 #endif
462 struct sock_fprog prog = {
463 .len = (unsigned short)(sizeof(filter) / sizeof (filter[0])),
464 .filter = filter,
465 };
466 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0)) {
467 printf("Failed to enable seccomp\n");
468 return -1;
469 }
470 return 0;
471 }
472
473 int sandbox_close() {
474 #if defined(__linux__) && !defined(__MUSL__)
475 if (libgcc_s)
476 dlclose(libgcc_s);
477 #endif
478 #ifndef DISABLE_XDG
479 xdg_close();
480 #endif
481 return 0;
482 }
483
484 #elif sun
485
486 #include <stdio.h>
487 #include <string.h>
488 #include <priv.h>
489 #include <errno.h>
490 #include <strings.h>
491 #include <fcntl.h>
492 #include "cert.h"
493 #include "gemini.h"
494
495 int init_privs(const char **privs) {
496 priv_set_t *pset;
497 if ((pset = priv_allocset()) == NULL) {
498 printf("priv_allocset: %s\n", strerror(errno));
499 return -1;
500 }
501 priv_emptyset(pset);
502 for (int i = 0; privs[i]; i++) {
503 if (priv_addset(pset, privs[i]) != 0) {
504 printf("priv_addset: %s\n", strerror(errno));
505 return -1;
506 }
507 }
508 if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) != 0 ||
509 setppriv(PRIV_SET, PRIV_LIMIT, pset) != 0 ||
510 setppriv(PRIV_SET, PRIV_INHERITABLE, pset) != 0) {
511 printf("setppriv: %s\n", strerror(errno));
512 return -1;
513 }
514 priv_freeset(pset);
515 return 0;
516 }
517
518 // write request
519 #define _WR_BOOKMARKS 0xFFFFFFFF
520 #define _WR_KNOWNHOSTS 0xEEEEEEEE
521 #define _WR_KNOWNHOST_ADD 0xEEEEFFFF
522 #define _WR_DOWNLOAD 0xDDDDDDDD
523 #define _WR_CERTIFICATE 0xCCCCCCCC
524 #define _WR_END 0xBBBBBBBB
525 // read request
526 #define _RD_CERTIFICATE 0xFFFFFFFF
527
528 unsigned int WR_BOOKMARKS = _WR_BOOKMARKS;
529 unsigned int WR_KNOWNHOSTS = _WR_KNOWNHOSTS;
530 unsigned int WR_KNOWNHOST_ADD = _WR_KNOWNHOST_ADD;
531 unsigned int WR_DOWNLOAD = _WR_DOWNLOAD;
532 unsigned int WR_CERTIFICATE = _WR_CERTIFICATE;
533 unsigned int WR_END = _WR_END;
534 unsigned int RD_CERTIFICATE = _RD_CERTIFICATE;
535
536 int wr_pair[2];
537 int rd_pair[2];
538
539 int sandbox_download(struct gmi_tab* tab, const char* path) {
540 if (send(wr_pair[1], &WR_DOWNLOAD, sizeof(WR_DOWNLOAD), 0) !=
541 sizeof(WR_DOWNLOAD)) {
542 sandbox_error:
543 tab->show_error = -1;
544 snprintf(tab->error, sizeof(tab->error),
545 "Sandbox error");
546 return -1;
547 }
548 int path_len = strlen(path);
549 if (send(wr_pair[1], path, path_len, 0) != path_len)
550 goto sandbox_error;
551 int res;
552 if (recv(wr_pair[1], &res, sizeof(res), 0) != sizeof(res))
553 goto sandbox_error;
554 if (res) {
555 tab->show_error = -1;
556 snprintf(tab->error, sizeof(tab->error),
557 "Failed to write file : %s",
558 strerror(res));
559 return -1;
560 }
561 return 0;
562 }
563
564 int sandbox_dl_length(size_t length) {
565 return send(wr_pair[1], &length, sizeof(length), 0);
566 }
567
568 int sandbox_cert_create(char* host, char* error, int errlen) {
569 if (send(wr_pair[1], &WR_CERTIFICATE, sizeof(SBC), 0) != sizeof(SBC)) {
570 sandbox_error:
571 snprintf(error, errlen, "Sandbox error : %s", strerror(errno));
572 return -1;
573 }
574 int len = strlen(host);
575 if (send(wr_pair[1], host, len, 0) != len)
576 goto sandbox_error;
577 int err;
578 if (recv(wr_pair[1], &err, sizeof(err), 0) != sizeof(err))
579 goto sandbox_error;
580 if (err) { // error
581 len = recv(wr_pair[1], error, errlen - 1, 0);
582 if (len < 0) len = 0;
583 error[len] = '\0';
584 }
585 return err;
586 }
587
588 int sandbox_listen_rd() {
589 if (socketpair(AF_UNIX, SOCK_STREAM, 0, rd_pair)) {
590 printf("socketpair: %s\n", strerror(errno));
591 return -1;
592 }
593 int pid = fork();
594 if (pid != 0) {
595 close(rd_pair[0]);
596 return 0;
597 }
598 close(rd_pair[1]);
599 const char* privs[] = {PRIV_FILE_READ, NULL};
600 if (init_privs(privs)) exit(-1);
601 char buf[1024];
602 while (1) {
603 uint16_t dlen; // domain name length
604 int len = recv(rd_pair[0], buf, sizeof(SBC), 0);
605 if (len != sizeof(SBC) || *(SBC*)buf != RD_CERTIFICATE)
606 break;
607 len = recv(rd_pair[0], &dlen, sizeof(dlen), 0);
608 if (len != sizeof(dlen) || dlen >= sizeof(buf))
609 break;
610 if (recv(rd_pair[0], buf, dlen, 0) != dlen)
611 break;
612 struct cert_cache cert;
613 buf[dlen] = 0;
614 if (cert_loadcert(buf, &cert)) {
615 buf[0] = -1;
616 send(rd_pair[0], buf, 1, 0);
617 continue;
618 }
619 len = 0;
620 send(rd_pair[0], &len, 1, 0);
621 send(rd_pair[0], &cert.crt_len, sizeof(size_t), 0);
622 send(rd_pair[0], &cert.key_len, sizeof(size_t), 0);
623 send(rd_pair[0], cert.crt, cert.crt_len, 0);
624 send(rd_pair[0], cert.key, cert.key_len, 0);
625 free(cert.crt);
626 free(cert.key);
627 }
628 close(wr_pair[0]);
629 exit(-1);
630 }
631
632 int sandbox_listen() {
633 if (socketpair(AF_UNIX, SOCK_STREAM, 0, wr_pair)) {
634 printf("socketpair: %s\n", strerror(errno));
635 return -1;
636 }
637 int pid = fork();
638 if (pid != 0) {
639 close(wr_pair[0]);
640 return 0;
641 }
642 close(wr_pair[1]);
643 const char* privs[] = {PRIV_FILE_WRITE, NULL};
644 if (init_privs(privs)) exit(-1);
645 char buf[1024];
646 int fd = -1;
647 uint64_t length = 0;
648 while (1) {
649 int l = fd == -1 ?
650 4 : (length > 0 && length < sizeof(buf) ?
651 length : sizeof(buf));
652 int len = recv(wr_pair[0], buf, l, 0);
653 if (len <= 0)
654 break;
655 if (fd > -1) {
656 write(fd, buf, len);
657 int sync = 0;
658 if (length) {
659 if (length < (unsigned)len) len = length;
660 length -= len;
661 if (length > 0) continue;
662 sync = 1;
663 }
664 if (*(SBC*)&buf[len - 4] == WR_END || sync) {
665 fsync(fd);
666 close(fd);
667 fd = -1;
668 }
669 }
670
671 if (len != 4) continue;
672 switch (*(SBC*)buf) {
673 case _WR_DOWNLOAD:
674 // recv file name
675 len = recv(wr_pair[0], buf, sizeof(buf) - 1, 0);
676 if (len < 1) {
677 len = -1;
678 send(wr_pair[0], &len, sizeof(len), 0);
679 continue;
680 }
681 // clean file name from slash
682 for (int i = 0; i < len; i++) {
683 if (buf[i] == '/')
684 buf[i] = '_';
685 }
686 buf[len] = '\0';
687 fd = openat(download_fd, buf,
688 O_CREAT|O_WRONLY|O_EXCL, 0600);
689 // send back errno if failed to open file, 0 if sucess
690 len = (fd < 0) ? errno : 0;
691 send(wr_pair[0], &len, sizeof(len), 0);
692 if (fd < 0) // exit here on error
693 continue;
694 // recv file length
695 len = recv(wr_pair[0], buf, sizeof(length), 0);
696 if (len != sizeof(length)) {
697 close(fd);
698 fd = -1;
699 }
700 length = *(uint64_t*)buf;
701 break;
702 case _WR_CERTIFICATE:
703 len = recv(wr_pair[0], buf, sizeof(buf) - 1, 0);
704 if (len < 1) {
705 len = -1;
706 send(wr_pair[0], &len, sizeof(len), 0);
707 continue;
708 }
709 buf[len] = '\0';
710 char err[1024];
711 int ret = cert_create(buf, err, sizeof(err));
712 send(wr_pair[0], &ret, sizeof(ret), 0);
713 if (ret)
714 send(wr_pair[0], err, strlen(err), 0);
715 break;
716 case _WR_BOOKMARKS:
717 fd = openat(config_fd, "bookmarks.txt",
718 O_CREAT|O_WRONLY|O_CLOEXEC|O_TRUNC, 0600);
719 if (fd < 0) exit(-1);
720 break;
721 case _WR_KNOWNHOSTS:
722 fd = openat(config_fd, "known_hosts",
723 O_CREAT|O_WRONLY|O_CLOEXEC|O_TRUNC, 0600);
724 if (fd < 0) exit(-1);
725 break;
726 case _WR_KNOWNHOST_ADD:
727 fd = openat(config_fd, "known_hosts",
728 O_CREAT|O_APPEND|O_WRONLY, 0600);
729 if (fd < 0) exit(-1);
730 break;
731 }
732 }
733 if (fd > -1) close(fd);
734 close(wr_pair[0]);
735 exit(-1);
736 }
737
738 int sandbox_init() {
739 #ifndef DISABLE_XDG
740 if (xdg_init()) {
741 printf("xdg failure\n");
742 return -1;
743 }
744 #endif
745 if (getconfigfd() < 0) {
746 printf("Failed to get cache folder\n");
747 return -1;
748 }
749 if (getdownloadfd() < 0) {
750 printf("Failed to get download folder\n");
751 return -1;
752 }
753 if (cert_load()) {
754 printf("Failed to load known host\n");
755 return -1;
756 }
757 if (gmi_loadbookmarks()) {
758 gmi_newbookmarks();
759 }
760 if (sandbox_listen()) {
761 printf("Failed to initialize sandbox\n");
762 return -1;
763 }
764 if (sandbox_listen_rd()) {
765 printf("Failed to initialize sandbox\n");
766 return -1;
767 }
768
769 struct addrinfo hints, *result;
770 bzero(&hints, sizeof(hints));
771 hints.ai_family = AF_INET;
772 hints.ai_socktype = SOCK_STREAM;
773 hints.ai_flags |= AI_CANONNAME;
774
775 getaddrinfo("example.com", NULL, &hints, &result);
776
777 const char* privs[] = {PRIV_NET_ACCESS, NULL};
778 if (init_privs(privs)) return -1;
779
780 return 0;
781 }
782
783 int sandbox_close() {
784 #ifndef DISABLE_XDG
785 xdg_close();
786 #endif
787 close(wr_pair[1]);
788 close(wr_pair[0]);
789 return 0;
790 }
791
792 #else
793 #warning No sandbox found for the current operating system
794 #define NO_SANDBOX
795 #endif
796
797 #endif // #ifndef NO_SANDBOX
798
799 #ifdef NO_SANDBOX
800 int sandbox_init() {
801 return 0;
802 }
803
804 int sandbox_close() {
805 return 0;
806 }
807 #endif
808