From 069009f8e39238ec1a67fba6cfb287b9a0cac83e Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Fri, 24 Mar 2023 10:07:48 +0100 Subject: Re-organize project and add license header --- seitan.c | 435 --------------------------------------------------------------- 1 file changed, 435 deletions(-) delete mode 100644 seitan.c (limited to 'seitan.c') diff --git a/seitan.c b/seitan.c deleted file mode 100644 index 5d2df21..0000000 --- a/seitan.c +++ /dev/null @@ -1,435 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -/* SEITAN - Syscall Expressive Interpreter, Transformer and Notifier - * - * seitan.c - Wait for processes, listen for syscalls, handle them - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "common.h" -#include "gluten.h" -#include "operations.h" - -#define EPOLL_EVENTS 8 -#define errExit(msg) \ - do { \ - perror(msg); \ - exit(EXIT_FAILURE); \ - } while (0) - -static char doc[] = "Usage: seitan: setain -pid -i "; - -/* Seitan options */ -static struct argp_option options[] = { - { "input", 'i', "FILE", 0, "Action input file", 0 }, - { "output", 'o', "FILE", 0, "Log filtered syscall in the file", 0 }, - { "pid", 'p', "pid", 0, - "Pid of process to monitor (cannot be used together with -socket)", - 0 }, - { "socket", 's', "/tmp/seitan.sock", 0, - "Socket to pass the seccomp notifier fd (cannot be used together with -pid)", - 0 }, - { 0 } -}; - -struct arguments { - char *input_file; - char *output_file; - char *socket; - int pid; -}; - -static error_t parse_opt(int key, char *arg, struct argp_state *state) -{ - struct arguments *arguments = state->input; - - switch (key) { - case 'p': - arguments->pid = atoi(arg); - break; - case 'i': - arguments->input_file = arg; - break; - case 'o': - arguments->output_file = arg; - break; - case 's': - arguments->socket = arg; - break; - case ARGP_KEY_END: - if (arguments->input_file == NULL) - argp_error(state, "missing input file"); - if (strcmp(arguments->socket, "") > 0 && arguments->pid > 0) - argp_error( - state, - "the -socket and -pid options cannot be used together"); - break; - default: - return ARGP_ERR_UNKNOWN; - } - - 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 nl_init(void) -{ - int s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); - struct sockaddr_nl sa = { - .nl_family = AF_NETLINK, - .nl_groups = CN_IDX_PROC, - .nl_pid = getpid(), - }; - struct req_t { - struct nlmsghdr nlh; - struct cn_msg cnm; - enum proc_cn_mcast_op mop; - } __attribute__((packed, aligned(NLMSG_ALIGNTO))) req = { - .nlh.nlmsg_type = NLMSG_DONE, - .nlh.nlmsg_pid = getpid(), - - .cnm.id.idx = CN_IDX_PROC, - .cnm.id.val = CN_VAL_PROC, - .cnm.len = sizeof(enum proc_cn_mcast_op), - - .mop = PROC_CN_MCAST_LISTEN, - }; - - bind(s, (struct sockaddr *)&sa, sizeof(sa)); - - req.nlh.nlmsg_len = sizeof(req); - send(s, &req, sizeof(req), 0); - - return s; -} - -static int event(int s) -{ - char path[PATH_MAX + 1], exe[PATH_MAX + 1]; - struct proc_event *ev; - struct nlmsghdr *nlh; - struct cn_msg *cnh; - char buf[BUFSIZ]; - ssize_t n; - - if ((n = recv(s, &buf, sizeof(buf), 0)) <= 0) - return -EIO; - - nlh = (struct nlmsghdr *)buf; - for (; NLMSG_OK(nlh, n); nlh = NLMSG_NEXT(nlh, n)) { - if (nlh->nlmsg_type == NLMSG_NOOP) - continue; - - if ((nlh->nlmsg_type == NLMSG_ERROR) || - (nlh->nlmsg_type == NLMSG_OVERRUN)) - break; - - cnh = NLMSG_DATA(nlh); - ev = (struct proc_event *)cnh->data; - - if (ev->what != PROC_EVENT_EXEC) - continue; - - snprintf(path, PATH_MAX, "/proc/%i/exe", - ev->event_data.exec.process_pid); - - readlink(path, exe, PATH_MAX); - if (!strcmp(exe, "/usr/local/bin/seitan-eater") || - !strcmp(exe, "/usr/bin/seitan-eater")) - return ev->event_data.exec.process_pid; - - if (nlh->nlmsg_type == NLMSG_DONE) - break; - } - - return -EAGAIN; -} - -enum transform { - NONE, - FD1_UNIX, - FDRET_SRC, - DEV_CHECK, -}; - -struct table { - enum transform type; - long number; - - char arg[6][1024]; -}; - -static struct table t[16]; - -static int pidfd_send_signal(int pidfd, int sig, siginfo_t *info, - unsigned int flags) -{ - return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); -} - -static void unblock_eater(int pidfd) -{ - if (pidfd_send_signal(pidfd, SIGCONT, NULL, 0) == -1) { - perror("pidfd_send_signal"); - exit(EXIT_FAILURE); - } -} - -int handle(struct seccomp_notif *req, int notifyfd) -{ - char path[PATH_MAX + 1]; - struct sockaddr_un s_un; - int fd_unix; - unsigned i; - int mem; - - for (i = 0; i < sizeof(t) / sizeof(t[0]); i++) { - if (t[i].number == req->data.nr) - break; - } - - if (i == sizeof(t) / sizeof(t[0])) /* Not found */ - return 1; - - if (t[i].type != FD1_UNIX) /* Not implemented yet */ - return 1; - - /* FD1_UNIX here */ - snprintf(path, sizeof(path), "/proc/%i/mem", req->pid); - fd_unix = req->data.args[0]; - - mem = open(path, O_RDONLY); - lseek(mem, req->data.args[1], SEEK_SET); - read(mem, &s_un, sizeof(s_un)); - close(mem); - - if (!strcmp(s_un.sun_path, t[i].arg[0])) { - int own_fd = socket(AF_UNIX, SOCK_STREAM, 0); - - struct seccomp_notif_addfd addfd = { - .id = req->id, - .flags = SECCOMP_ADDFD_FLAG_SEND | - SECCOMP_ADDFD_FLAG_SETFD, - .srcfd = own_fd, - .newfd = fd_unix, - }; - - connect(own_fd, &s_un, sizeof(s_un)); - ioctl(notifyfd, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd); - return 0; - } - - return 1; -} - -static int create_socket(const char *path) -{ - struct sockaddr_un addr; - int ret, conn; - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) - errExit("error creating UNIX socket"); - - strcpy(addr.sun_path, path); - addr.sun_family = AF_UNIX; - ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); - if (ret < 0) - errExit("bind"); - - ret = listen(fd, 1); - if (ret < 0) - errExit("listen"); - conn = accept(fd, NULL, NULL); - if (conn < 0) - errExit("accept"); - - return conn; -} - -static int recvfd(int sockfd) -{ - struct msghdr msgh; - struct iovec iov; - int data, fd; - ssize_t nr; - - union { - char buf[CMSG_SPACE(sizeof(int))]; - struct cmsghdr align; - } controlMsg; - struct cmsghdr *cmsgp; - - msgh.msg_name = NULL; - msgh.msg_namelen = 0; - - msgh.msg_iov = &iov; - msgh.msg_iovlen = 1; - iov.iov_base = &data; - iov.iov_len = sizeof(int); - - msgh.msg_control = controlMsg.buf; - msgh.msg_controllen = sizeof(controlMsg.buf); - - nr = recvmsg(sockfd, &msgh, 0); - if (nr == -1) - errExit("recvmsg"); - - cmsgp = CMSG_FIRSTHDR(&msgh); - - if (cmsgp == NULL || cmsgp->cmsg_len != CMSG_LEN(sizeof(int)) || - cmsgp->cmsg_level != SOL_SOCKET || cmsgp->cmsg_type != SCM_RIGHTS) { - errno = EINVAL; - return -1; - } - - memcpy(&fd, CMSG_DATA(cmsgp), sizeof(int)); - return fd; -} - -static int write_syscall(int fd, struct seccomp_notif *req) -{ - char buf[1000]; - - /* TODO: Define format and print syscall with the right arguments */ - snprintf(buf, sizeof(buf), "nr_syscall=%d\n", req->data.nr); - write(fd, buf, strlen(buf)); - return 0; -} - -int main(int argc, char **argv) -{ - int s = nl_init(), ret, pidfd, notifier; - char req_b[BUFSIZ]; - struct epoll_event ev, events[EPOLL_EVENTS]; - struct seccomp_notif *req = (struct seccomp_notif *)req_b; - struct arguments arguments; - char path[PATH_MAX + 1]; - bool running = true; - bool output = false; - int fd, epollfd; - int notifierfd; - int nevents, i; - int fdout; - - arguments.pid = -1; - argp_parse(&argp, argc, argv, 0, 0, &arguments); - fd = open(arguments.input_file, O_CLOEXEC | O_RDONLY); - read(fd, t, sizeof(t)); - close(fd); - - if (strcmp(arguments.output_file, "") > 0) { - output = true; - unlink(arguments.output_file); - if ((fdout = open(arguments.output_file, - O_CREAT | O_RDWR | O_TRUNC)) < 0) - errExit("open"); - } - - if (arguments.pid > 0) { - if ((pidfd = syscall(SYS_pidfd_open, arguments.pid, 0)) < 0) - errExit("pidfd_open"); - snprintf(path, sizeof(path), "/proc/%d/fd", arguments.pid); - if ((notifierfd = find_fd_seccomp_notifier(path)) < 0) - errExit("failed getting fd of the notifier"); - if ((notifier = syscall(SYS_pidfd_getfd, pidfd, notifierfd, - 0)) < 0) - errExit("pidfd_getfd"); - /* Unblock seitan-loader */ - unblock_eater(pidfd); - } else if (strcmp(arguments.socket, "") > 0) { - unlink(arguments.socket); - if ((fd = create_socket(arguments.socket)) < 0) - exit(EXIT_FAILURE); - if ((notifier = recvfd(fd)) < 0) - exit(EXIT_FAILURE); - } else { - while ((ret = event(s)) == -EAGAIN) - ; - if (ret < 0) - exit(EXIT_FAILURE); - } - sleep(1); - - if ((epollfd = epoll_create1(0)) < 0) { - perror("epoll_create"); - exit(EXIT_FAILURE); - } - ev.events = EPOLLIN; - ev.data.fd = notifier; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, notifier, &ev) == -1) { - perror("epoll_ctl: notifier"); - exit(EXIT_FAILURE); - } - - while (running) { - nevents = epoll_wait(epollfd, events, EPOLL_EVENTS, -1); - if (nevents < 0) { - perror("epoll_wait"); - exit(EXIT_FAILURE); - } - memset(req, 0, sizeof(*req)); - if (ioctl(notifier, SECCOMP_IOCTL_NOTIF_RECV, req) < 0) - errExit("recieving seccomp notification"); - for (i = 0; i < nevents; ++i) { - if (events[i].events & EPOLLHUP) { - /* The notifier fd was closed by the target */ - running = false; - } else if (notifier == events[i].data.fd) { - /* - * TODO: remove until we parse correctly the - * operations from the bytecode - */ - struct op operations[] = { - { .type = OP_CONT }, - }; - if (do_operations(NULL, operations, req, - sizeof(operations) / - sizeof(operations[0]), - req->pid, notifier, - req->id) == -1) - errExit("failed executing operation"); - - if (output) - write_syscall(fdout, req); - } - } - } - if (strcmp(arguments.socket, "") > 0) - unlink(arguments.socket); -} -- cgit v1.2.3