static void install_seccomp_filter(const char *syscalls[]) { scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_TRAP); if (!ctx) { errx(EXIT_FAILURE, "Failed to init seccomp"); } for (int i = 0; ; i++) { const char *syscall = syscalls[i]; if (!syscall) break; check(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, get_syscall_nr(syscall), 0)); } check(seccomp_load(ctx)); }
int main(int argc, char **argv) { prevent_leaked_file_descriptors(); bool mount_proc = false; bool mount_dev = false; const char *username = "******"; const char *hostname = "playpen"; long timeout = 0; long memory_limit = 128; struct bind_list *binds = NULL, *binds_tail = NULL; char *devices = NULL; char *syscalls = NULL; const char *syscalls_file = NULL; const char *learn_name = NULL; static const struct option opts[] = { { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, { "mount-proc", no_argument, 0, 'p' }, { "mount-dev", no_argument, 0, 0x100 }, { "bind", required_argument, 0, 'b' }, { "bind-rw", required_argument, 0, 'B' }, { "user", required_argument, 0, 'u' }, { "hostname", required_argument, 0, 'n' }, { "timeout", required_argument, 0, 't' }, { "memory-limit", required_argument, 0, 'm' }, { "devices", required_argument, 0, 'd' }, { "syscalls", required_argument, 0, 's' }, { "syscalls-file", required_argument, 0, 'S' }, { "learn", required_argument, 0, 'l' }, { 0, 0, 0, 0 } }; for (;;) { int opt = getopt_long(argc, argv, "hvpb:B:u:n:t:m:d:s:S:l:", opts, NULL); if (opt == -1) break; switch (opt) { case 'h': usage(stdout); case 'v': printf("%s %s\n", program_invocation_short_name, VERSION); return 0; case 'p': mount_proc = true; break; case 0x100: mount_dev = true; break; case 'b': case 'B': if (binds) { binds_tail->next = bind_list_alloc(optarg, opt == 'b'); binds_tail = binds_tail->next; } else { binds = binds_tail = bind_list_alloc(optarg, opt == 'b'); } break; case 'u': username = optarg; break; case 'n': hostname = optarg; break; case 't': timeout = strtolx_positive(optarg, "timeout"); break; case 'm': memory_limit = strtolx_positive(optarg, "memory limit"); break; case 'd': devices = optarg; break; case 's': syscalls = optarg; break; case 'S': syscalls_file = optarg; break; case 'l': learn_name = optarg; break; default: usage(stderr); } } if (argc - optind < 2) { usage(stderr); } const char *root = argv[optind]; optind++; scmp_filter_ctx ctx = seccomp_init(learn_name ? SCMP_ACT_TRACE(0) : SCMP_ACT_KILL); if (!ctx) errx(EXIT_FAILURE, "seccomp_init"); if (syscalls_file) { char name[SYSCALL_NAME_MAX]; FILE *file = fopen(syscalls_file, "r"); if (!file) err(EXIT_FAILURE, "failed to open syscalls file: %s", syscalls_file); while (fgets(name, sizeof name, file)) { char *pos; if ((pos = strchr(name, '\n'))) *pos = '\0'; check(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, get_syscall_nr(name), 0)); } fclose(file); } check(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, __NR_execve, 0)); if (syscalls) { for (char *s_ptr = syscalls, *saveptr; ; s_ptr = NULL) { const char *syscall = strtok_r(s_ptr, ",", &saveptr); if (!syscall) break; check(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, get_syscall_nr(syscall), 0)); } } int epoll_fd = epoll_create1(EPOLL_CLOEXEC); check_posix(epoll_fd, "epoll_create1"); sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigaddset(&mask, SIGHUP); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTERM); check_posix(sigprocmask(SIG_BLOCK, &mask, NULL), "sigprocmask"); int sig_fd = signalfd(-1, &mask, SFD_CLOEXEC); check_posix(sig_fd, "signalfd"); epoll_add(epoll_fd, sig_fd, EPOLLIN); int pipe_in[2]; int pipe_out[2]; int pipe_err[2]; check_posix(pipe(pipe_in), "pipe"); check_posix(pipe(pipe_out), "pipe"); set_non_blocking(pipe_out[0]); check_posix(pipe(pipe_err), "pipe"); set_non_blocking(pipe_err[0]); int rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &(struct epoll_event){ .data.fd = STDIN_FILENO, .events = EPOLLIN });