/* vim: set expandtab ts=4 sw=4: */ /* * You may redistribute this program and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "util/Seccomp.h" // SIG_UNBLOCK #define _POSIX_SOURCE #include // getpriority() #include #include #include #include void Seccomp_dropPermissions(struct Except* eh) { scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_TRAP); if (!ctx) { seccomp_release(ctx); Except_throw(eh, "Failed to initialize SECCOMP"); } int rc = 0; // Adding exceptions to the syscall filter: // // echo '#include ' | gcc -E -dM - | grep 'define __NR_' | sort // for the full list of system calls with syscall numbers (different per ABI) // // If gdb traps out it will look like this: // // Program received signal SIGSYS, Bad system call. // [Switching to Thread 0x7ffff7fdd740 (LWP 14673)] // 0x00007ffff74d1caa in mmap64 () at ../sysdeps/unix/syscall-template.S:81 // 81 ../sysdeps/unix/syscall-template.S: No such file or directory. // // %eax should contain the system call number (on different ABIs YMMV) // // (gdb) print $eax // $1 = 9 // (gdb) // // Consult your syscall table from the above gcc command... // // #define __NR_mmap 9 // // Then add: // // rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0); // // And add a comment documenting where you needed that syscall :) // see seccomp.h:307 and "man seccomp_rule_add" for docs on this function // libuv rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_wait), 0); // logging to stdout/stderr, tun and eth0 rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); // tun device and eth0 rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); // malloc() rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0); // udp rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendmsg), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(recvmsg), 0); // ETHInterface rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendto), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(recvfrom), 0); // abort() rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(gettid), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(tgkill), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), 1, SCMP_CMP(0, SCMP_CMP_EQ, SIG_UNBLOCK, 0)); // exit() rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); // Seccomp_isWorking() rc |= seccomp_rule_add(ctx, SCMP_ACT_ERRNO(9000), SCMP_SYS(getpriority), 0); // Securiy_checkPermissions() -> canOpenFiles() rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(dup), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); // Security_checkPermissions() -> getMaxMem() rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getrlimit), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0); // printf rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0); ///// char* err = NULL; if (rc) { err = "Failed to add SECCOMP filters"; } else if (seccomp_load(ctx)) { err = "Failed to load SECCOMP"; } seccomp_release(ctx); if (err) { Except_throw(eh, "%s", err); } else if (!Seccomp_isWorking()) { Except_throw(eh, "SECCOMP is not working correctly"); } } int Seccomp_isWorking() { errno = 0; // If seccomp is not working, this will fail setting errno to EINVAL long ret = getpriority(1000, 1); // Inside of the kernel, it seems to check whether the errno return is sane // and if it is not, it treates it as a return value, 9000 is very unique so // we'll check for either case just in case this changes. return (ret == -1 && errno == 9000) || (ret == -9000 && errno == 0); }