sandbox.c 6.0 KB

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