💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Vgmi › files › f9acdd9cf41bb5b837be9d4373da0… captured on 2023-09-08 at 16:24:01. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-04-19)

🚧 View Differences

-=-=-=-=-=-=-

Go Back

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