Seccomp.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include "util/Seccomp.h"
  16. // SIG_UNBLOCK
  17. #define _POSIX_SOURCE
  18. #include <signal.h>
  19. // getpriority()
  20. #include <sys/resource.h>
  21. #include <errno.h>
  22. #include <seccomp.h>
  23. #include <stddef.h>
  24. void Seccomp_dropPermissions(struct Except* eh)
  25. {
  26. scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_TRAP);
  27. if (!ctx) {
  28. seccomp_release(ctx);
  29. Except_throw(eh, "Failed to initialize SECCOMP");
  30. }
  31. int rc = 0;
  32. // Adding exceptions to the syscall filter:
  33. //
  34. // echo '#include <seccomp.h>' | gcc -E -dM - | grep 'define __NR_' | sort
  35. // for the full list of system calls with syscall numbers (different per ABI)
  36. //
  37. // If gdb traps out it will look like this:
  38. //
  39. // Program received signal SIGSYS, Bad system call.
  40. // [Switching to Thread 0x7ffff7fdd740 (LWP 14673)]
  41. // 0x00007ffff74d1caa in mmap64 () at ../sysdeps/unix/syscall-template.S:81
  42. // 81 ../sysdeps/unix/syscall-template.S: No such file or directory.
  43. //
  44. // %eax should contain the system call number (on different ABIs YMMV)
  45. //
  46. // (gdb) print $eax
  47. // $1 = 9
  48. // (gdb)
  49. //
  50. // Consult your syscall table from the above gcc command...
  51. //
  52. // #define __NR_mmap 9
  53. //
  54. // Then add:
  55. //
  56. // rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0);
  57. //
  58. // And add a comment documenting where you needed that syscall :)
  59. // see seccomp.h:307 and "man seccomp_rule_add" for docs on this function
  60. // libuv
  61. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl), 0);
  62. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_wait), 0);
  63. // logging to stdout/stderr, tun and eth0
  64. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
  65. // tun device and eth0
  66. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
  67. // malloc()
  68. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0);
  69. // udp
  70. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendmsg), 0);
  71. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(recvmsg), 0);
  72. // ETHInterface
  73. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendto), 0);
  74. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(recvfrom), 0);
  75. // abort()
  76. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(gettid), 0);
  77. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(tgkill), 0);
  78. rc |= seccomp_rule_add(ctx,
  79. SCMP_ACT_ALLOW,
  80. SCMP_SYS(rt_sigprocmask),
  81. 1,
  82. SCMP_CMP(0, SCMP_CMP_EQ, SIG_UNBLOCK, 0));
  83. // exit()
  84. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
  85. // Seccomp_isWorking()
  86. rc |= seccomp_rule_add(ctx, SCMP_ACT_ERRNO(9000), SCMP_SYS(getpriority), 0);
  87. // Securiy_checkPermissions() -> canOpenFiles()
  88. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(dup), 0);
  89. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);
  90. // Security_checkPermissions() -> getMaxMem()
  91. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getrlimit), 0);
  92. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0);
  93. // printf
  94. rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0);
  95. /////
  96. char* err = NULL;
  97. if (rc) {
  98. err = "Failed to add SECCOMP filters";
  99. } else if (seccomp_load(ctx)) {
  100. err = "Failed to load SECCOMP";
  101. }
  102. seccomp_release(ctx);
  103. if (err) {
  104. Except_throw(eh, "%s", err);
  105. } else if (!Seccomp_isWorking()) {
  106. Except_throw(eh, "SECCOMP is not working correctly");
  107. }
  108. }
  109. int Seccomp_isWorking()
  110. {
  111. errno = 0;
  112. // If seccomp is not working, this will fail setting errno to EINVAL
  113. long ret = getpriority(1000, 1);
  114. // Inside of the kernel, it seems to check whether the errno return is sane
  115. // and if it is not, it treates it as a return value, 9000 is very unique so
  116. // we'll check for either case just in case this changes.
  117. return (ret == -1 && errno == 9000) || (ret == -9000 && errno == 0);
  118. }