diff options
Diffstat (limited to 'eater')
-rw-r--r-- | eater/Makefile | 22 | ||||
-rw-r--r-- | eater/eater.c | 143 |
2 files changed, 165 insertions, 0 deletions
diff --git a/eater/Makefile b/eater/Makefile new file mode 100644 index 0000000..2e3db3f --- /dev/null +++ b/eater/Makefile @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-3.0-or-later +# +# seitan - Syscall Expressive Interpreter, Transformer and Notifier +# +# eater/Makefile - Makefile for seitan-eater +# +# Copyright 2023 Red Hat GmbH +# Author: Alice Frosi <afrosi@redhat.com> + +COMMON_DIR :=../common +SRCS := $(COMMON_DIR)/common.c eater.c +HEADERS := $(COMMON_DIR)/common.h +BIN := $(OUTDIR)seitan-eater +CFLAGS += -Wall -Wextra -pedantic -I$(COMMON_DIR) + +eater: $(SRCS) $(HEADERS) + $(CC) $(CFLAGS) -o $(BIN) $(SRCS) + +all: eater + +clean: + rm -f $(BIN) diff --git a/eater/eater.c b/eater/eater.c new file mode 100644 index 0000000..96a7b61 --- /dev/null +++ b/eater/eater.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +/* SEITAN - Syscall Expressive Interpreter, Transformer and Notifier + * + * src/eater/eater.c - Load BPF program and execute binary + * + * Copyright (c) 2022 Red Hat GmbH + * Authors: Stefano Brivio <sbrivio@redhat.com>, Alice Frosi <afrosi@redhat.com> + */ + +#define _GNU_SOURCE +#include <errno.h> +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <argp.h> +#include <sys/prctl.h> +#include <sys/syscall.h> +#include <sys/socket.h> +#include <signal.h> + +#include <linux/audit.h> +#include <linux/filter.h> +#include <linux/seccomp.h> + +#include <dirent.h> +#include <sys/stat.h> + +#include "common.h" + +extern char **environ; + +static char doc[] = + "Usage: seitan-eater: setain-eater -i <input file> -- 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); +} + +static void signal_handler(__attribute__((unused)) int s) +{ +} + +/** + * 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; + struct sigaction act; + size_t n; + int fd, flags; + + 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])); + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) { + perror("prctl"); + exit(EXIT_FAILURE); + } + if (seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_NEW_LISTENER, + &prog) < 0) { + perror("seccomp"); + exit(EXIT_FAILURE); + } + /* + * close-on-exec flag is set for the file descriptor by seccomp. + * We want to preserve the fd on the exec in this way we are able + * to easly find the notifier fd if seitan restarts. + */ + fd = find_fd_seccomp_notifier("/proc/self/fd"); + flags = fcntl(fd, F_GETFD); + if (fcntl(fd, F_SETFD, flags & !FD_CLOEXEC) < 0) { + perror("fcntl"); + exit(EXIT_FAILURE); + } + act.sa_handler = signal_handler; + sigaction(SIGCONT, &act, NULL); + pause(); + + execvpe(argv[arguments.program_index], &argv[arguments.program_index], + environ); + if (errno != ENOENT) { + perror("execvpe"); + exit(EXIT_FAILURE); + } + close(fd); + return EXIT_FAILURE; +} |