sandbox.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #include "xs.h"
  2. #include "snac.h"
  3. #include <unistd.h>
  4. #if defined (__linux__)
  5. # define __USE_GNU
  6. # include <linux/landlock.h>
  7. # include <linux/prctl.h>
  8. # include <sys/syscall.h>
  9. # include <sys/prctl.h>
  10. # include <fcntl.h>
  11. # include <arpa/inet.h>
  12. #endif
  13. void sbox_enter(const char *basedir)
  14. {
  15. if (xs_is_true(xs_dict_get(srv_config, "disable_openbsd_security"))) {
  16. srv_log(xs_dup("disable_openbsd_security is deprecated. Use disable_sandbox instead."));
  17. return;
  18. }
  19. if (xs_is_true(xs_dict_get(srv_config, "disable_sandbox"))) {
  20. srv_debug(0, xs_dup("Sandbox disabled by admin"));
  21. return;
  22. }
  23. const char *address = xs_dict_get(srv_config, "address");
  24. #if defined (__OpenBSD__)
  25. int smail = !xs_is_true(xs_dict_get(srv_config, "disable_email_notifications"));
  26. srv_debug(1, xs_fmt("Calling unveil()"));
  27. unveil(basedir, "rwc");
  28. unveil("/tmp", "rwc");
  29. unveil("/etc/resolv.conf", "r");
  30. unveil("/etc/hosts", "r");
  31. unveil("/etc/ssl/openssl.cnf", "r");
  32. unveil("/etc/ssl/cert.pem", "r");
  33. unveil("/usr/share/zoneinfo", "r");
  34. if (smail)
  35. unveil("/usr/sbin/sendmail", "x");
  36. if (*address == '/')
  37. unveil(address, "rwc");
  38. unveil(NULL, NULL);
  39. srv_debug(1, xs_fmt("Calling pledge()"));
  40. xs *p = xs_str_new("stdio rpath wpath cpath flock inet proc dns fattr");
  41. if (smail)
  42. p = xs_str_cat(p, " exec");
  43. if (*address == '/')
  44. p = xs_str_cat(p, " unix");
  45. pledge(p, NULL);
  46. xs_free(p);
  47. #elif defined (__linux__)
  48. int error, ruleset_fd, abi;
  49. struct landlock_ruleset_attr rules = {0};
  50. struct landlock_path_beneath_attr path = {0};
  51. struct landlock_net_port_attr net = {0};
  52. rules.handled_access_fs =
  53. LANDLOCK_ACCESS_FS_EXECUTE |
  54. LANDLOCK_ACCESS_FS_WRITE_FILE |
  55. LANDLOCK_ACCESS_FS_READ_FILE |
  56. LANDLOCK_ACCESS_FS_REMOVE_DIR |
  57. LANDLOCK_ACCESS_FS_REMOVE_FILE |
  58. LANDLOCK_ACCESS_FS_MAKE_CHAR |
  59. LANDLOCK_ACCESS_FS_MAKE_DIR |
  60. LANDLOCK_ACCESS_FS_MAKE_REG |
  61. LANDLOCK_ACCESS_FS_MAKE_SOCK |
  62. LANDLOCK_ACCESS_FS_MAKE_FIFO |
  63. LANDLOCK_ACCESS_FS_MAKE_BLOCK |
  64. LANDLOCK_ACCESS_FS_MAKE_SYM |
  65. LANDLOCK_ACCESS_FS_REFER |
  66. LANDLOCK_ACCESS_FS_TRUNCATE |
  67. LANDLOCK_ACCESS_FS_IOCTL_DEV;
  68. rules.handled_access_net =
  69. LANDLOCK_ACCESS_NET_BIND_TCP |
  70. LANDLOCK_ACCESS_NET_CONNECT_TCP;
  71. abi = syscall(SYS_landlock_create_ruleset, NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
  72. switch (abi) {
  73. case -1:
  74. srv_debug(0, xs_dup("Kernel without landlock support"));
  75. return;
  76. case 1:
  77. rules.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;
  78. __attribute__((fallthrough));
  79. case 2:
  80. rules.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE;
  81. __attribute__((fallthrough));
  82. case 3:
  83. rules.handled_access_net &= ~(LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP);
  84. __attribute__((fallthrough));
  85. case 4:
  86. rules.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;
  87. }
  88. srv_debug(1, xs_fmt("lanlock abi: %d", abi));
  89. ruleset_fd = syscall(SYS_landlock_create_ruleset, &rules, sizeof(struct landlock_ruleset_attr), 0);
  90. if (ruleset_fd == -1) {
  91. srv_debug(0, xs_fmt("landlock_create_ruleset failed: %s", strerror(errno)));
  92. return;
  93. }
  94. #define LL_R LANDLOCK_ACCESS_FS_READ_FILE
  95. #define LL_X LANDLOCK_ACCESS_FS_EXECUTE
  96. #define LL_RWC (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_TRUNCATE)
  97. #define LL_UNX (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_SOCK)
  98. #define LL_CON LANDLOCK_ACCESS_NET_CONNECT_TCP
  99. #define LL_BND LANDLOCK_ACCESS_NET_BIND_TCP
  100. #define LANDLOCK_PATH(p, r) do {\
  101. path.allowed_access = r;\
  102. if (abi < 3)\
  103. path.allowed_access &= ~LANDLOCK_ACCESS_FS_TRUNCATE;\
  104. path.parent_fd = open(p, O_PATH | O_CLOEXEC);\
  105. if (path.parent_fd == -1) {\
  106. srv_debug(2, xs_fmt("open %s: %s", p, strerror(errno)));\
  107. goto close;\
  108. }\
  109. error = syscall(SYS_landlock_add_rule, ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path, 0); \
  110. if (error) {\
  111. srv_debug(0, xs_fmt("LANDLOCK_PATH(%s): %s", p, strerror(errno)));\
  112. goto close;\
  113. }\
  114. } while (0)
  115. #define LANDLOCK_PORT(p, r) do {\
  116. uint16_t _p = p;\
  117. net.port = _p;\
  118. net.allowed_access = r;\
  119. error = syscall(SYS_landlock_add_rule, ruleset_fd, LANDLOCK_RULE_NET_PORT, &net, 0);\
  120. if (error) {\
  121. srv_debug(0, xs_fmt("LANDLOCK_PORT(%d): %s", _p, strerror(errno)));\
  122. goto close;\
  123. }\
  124. } while (0)
  125. LANDLOCK_PATH(basedir, LL_RWC);
  126. LANDLOCK_PATH("/tmp", LL_RWC);
  127. LANDLOCK_PATH("/dev/shm", LL_RWC);
  128. LANDLOCK_PATH("/etc/resolv.conf", LL_R );
  129. LANDLOCK_PATH("/etc/hosts", LL_R );
  130. LANDLOCK_PATH("/etc/ssl/openssl.cnf", LL_R );
  131. LANDLOCK_PATH("/etc/ssl/cert.pem", LL_R );
  132. LANDLOCK_PATH("/usr/share/zoneinfo", LL_R );
  133. if (*address == '/')
  134. LANDLOCK_PATH(address, LL_UNX);
  135. if (abi > 3) {
  136. if (*address != '/') {
  137. LANDLOCK_PORT(
  138. (uint16_t)xs_number_get(xs_dict_get(srv_config, "port")), LL_BND);
  139. }
  140. LANDLOCK_PORT(80, LL_CON);
  141. LANDLOCK_PORT(443, LL_CON);
  142. }
  143. if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
  144. srv_debug(0, xs_fmt("prctl SET_NO_NEW_PRIVS: %s", strerror(errno)));
  145. goto close;
  146. }
  147. if (syscall(SYS_landlock_restrict_self, ruleset_fd, 0))
  148. srv_debug(0, xs_fmt("landlock_restrict_self: %s", strerror(errno)));
  149. srv_log(xs_dup("landlocked"));
  150. close:
  151. close(ruleset_fd);
  152. #endif
  153. }