From 36b8eb3ce55602bcf36199330e98f2e154225cf7 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Tue, 25 Oct 2022 15:19:55 +0200 Subject: seitan: Initial import Signed-off-by: Stefano Brivio --- seitan.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 seitan.c (limited to 'seitan.c') diff --git a/seitan.c b/seitan.c new file mode 100644 index 0000000..bc98aed --- /dev/null +++ b/seitan.c @@ -0,0 +1,215 @@ +// 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 + +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; + while (NLMSG_OK(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) + return -EAGAIN; + + 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-loader") || + !strcmp(exe, "/usr/bin/seitan-loader")) + return ev->event_data.exec.process_pid; + + if (nlh->nlmsg_type == NLMSG_DONE) + break; + + nlh = NLMSG_NEXT(nlh, n); + } + + 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]; + +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; +} + +int main(int argc, char **argv) +{ + int s = nl_init(), ret, pidfd, notifier; + char resp_b[BUFSIZ], req_b[BUFSIZ]; + struct seccomp_notif_resp *resp = (struct seccomp_notif_resp *)resp_b; + struct seccomp_notif *req = (struct seccomp_notif *)req_b; + int fd; + + fd = open("t.out", O_CLOEXEC | O_RDONLY); + read(fd, t, sizeof(t)); + close(fd); + + if (argc < 2) + while ((ret = event(s)) == -EAGAIN); + else + ret = atoi(argv[1]); + + if (ret < 0) + exit(EXIT_FAILURE); + + if ((pidfd = syscall(SYS_pidfd_open, ret, 0)) < 0) { + perror("pidfd_open"); + exit(EXIT_FAILURE); + } + + sleep(1); + + if ((notifier = syscall(SYS_pidfd_getfd, pidfd, 3, 0)) < 0) { + perror("pidfd_getfd"); + exit(EXIT_FAILURE); + } + + while (1) { + /* TODO: Open syscall transformation table blob, actually handle + * syscalls actions as parsed + */ + memset(req, 0, sizeof(*req)); + ioctl(notifier, SECCOMP_IOCTL_NOTIF_RECV, req); + + if (!handle(req, notifier)) + continue; + + resp->flags = SECCOMP_USER_NOTIF_FLAG_CONTINUE; + resp->id = req->id; + resp->error = 0; + resp->val = 0; + + ioctl(notifier, SECCOMP_IOCTL_NOTIF_SEND, resp); + } +} -- cgit v1.2.3