// SPDX-License-Identifier: AGPL-3.0-or-later /* SEITAN - Syscall Expressive Interpreter, Transformer and Notifier * * eater.c - Load BPF program and execute binary * * Copyright (c) 2022 Red Hat GmbH * Author: Stefano Brivio */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern char **environ; static char doc[] = "Usage: seitan-eater: setain-eater -i -- program args1 args2..."; /* Eater options */ static struct argp_option options[] = { { "input", 'i', "FILE", 0, "BPF filter input file", 0 }, { 0 } }; struct arguments { char *input_file; unsigned int program_index; }; static error_t parse_opt(int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; if (state->quoted == 0) arguments->program_index = state->next + 1; switch (key) { case 'i': if (state->quoted == 0) arguments->input_file = arg; break; case ARGP_KEY_END: if (arguments->input_file == NULL) argp_error(state, "missing input file"); if (state->argv[arguments->program_index] == NULL) argp_error(state, "missing program"); break; } return 0; } static struct argp argp = { .options = options, .parser = parse_opt, .args_doc = NULL, .doc = doc, .children = NULL, .help_filter = NULL, .argp_domain = NULL }; static int seccomp(unsigned int operation, unsigned int flags, void *args) { return syscall(__NR_seccomp, operation, flags, args); } /** * main() - Entry point * @argc: Argument count * @argv: Seitan-eater and program arguments * * Return: 0 once interrupted, non-zero on failure */ int main(int argc, char **argv) { struct sock_filter filter[1024]; struct arguments arguments; struct sock_fprog prog; size_t n; int fd; argp_parse(&argp, argc, argv, 0, 0, &arguments); fd = open(arguments.input_file, O_CLOEXEC | O_RDONLY); n = read(fd, filter, sizeof(filter)); close(fd); prog.filter = filter; prog.len = (unsigned short)(n / sizeof(filter[0])); prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); fd = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_NEW_LISTENER, &prog); connect(0, NULL, 0); /* Wait for seitan to unblock this */ execvpe(argv[arguments.program_index], &argv[arguments.program_index], environ); if (errno != ENOENT) { perror("execvpe"); exit(EXIT_FAILURE); } return EXIT_FAILURE; }