#define _GNU_SOURCE #include #include #include #include #include #include #include /* Layered on an empty mount tree, fresh PID/user/network namespaces, no caps, * no inherited descriptors and an immutable runtime closure. Deny kernel and * process escape surfaces; retain V8's ordinary memory/thread syscalls. */ static void checked(int result) { if (result < 0) { fprintf(stderr, "seccomp rule: %d\n", result); exit(1); } } int main(void) { scmp_filter_ctx filter = seccomp_init(SCMP_ACT_ALLOW); if (!filter) return 1; const char *denied[] = { "fork", "vfork", "execveat", "ptrace", "process_vm_readv", "process_vm_writev", "pidfd_getfd", "kcmp", "bpf", "perf_event_open", "userfaultfd", "io_uring_setup", "mount", "umount2", "pivot_root", "chroot", "move_mount", "open_tree", "fsopen", "fsconfig", "fsmount", "fspick", "mount_setattr", "open_by_handle_at", "name_to_handle_at", "setns", "unshare", "keyctl", "add_key", "request_key", "reboot", "kexec_load", "kexec_file_load", "init_module", "finit_module", "delete_module", "swapon", "swapoff", "syslog", "acct", "sethostname", "setdomainname", "iopl", "ioperm", "lookup_dcookie", NULL }; for (size_t i = 0; denied[i]; i++) { int syscall = seccomp_syscall_resolve_name(denied[i]); if (syscall != __NR_SCMP_ERROR) checked(seccomp_rule_add(filter, SCMP_ACT_ERRNO(EPERM), syscall, 0)); } /* glibc falls back to clone when clone3 is unavailable. Only thread creation * is admitted; subprocesses and new namespaces cannot be manufactured. */ checked(seccomp_rule_add(filter, SCMP_ACT_ERRNO(ENOSYS), SCMP_SYS(clone3), 0)); checked(seccomp_rule_add(filter, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(clone), 1, SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_THREAD, 0))); const unsigned long namespaces[] = {CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWNET, CLONE_NEWPID, CLONE_NEWIPC, CLONE_NEWUTS, CLONE_NEWCGROUP}; for (size_t i = 0; i < sizeof(namespaces) / sizeof(namespaces[0]); i++) checked(seccomp_rule_add(filter, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(clone), 1, SCMP_A0(SCMP_CMP_MASKED_EQ, namespaces[i], namespaces[i]))); checked(seccomp_rule_add(filter, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(socket), 1, SCMP_A0(SCMP_CMP_NE, AF_UNIX))); checked(seccomp_rule_add(filter, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(ioctl), 1, SCMP_A1(SCMP_CMP_EQ, 0x5412))); /* TIOCSTI */ checked(seccomp_export_bpf(filter, STDOUT_FILENO)); seccomp_release(filter); return 0; }