From 2a0e9e1d8ebabf71299c7027d4577b5c709d6ea5 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Tue, 24 Jan 2023 17:05:11 +0100 Subject: seitan: action for the call Perform the action action with the context. The action call executes a syscall in the given namespaces or in caller context if non is specified. Signed-off-by: Alice Frosi --- actions.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 actions.c (limited to 'actions.c') diff --git a/actions.c b/actions.c new file mode 100644 index 0000000..edd7a8a --- /dev/null +++ b/actions.c @@ -0,0 +1,193 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gluten.h" +#include "actions.h" + +static bool is_cookie_valid(int notifyFd, uint64_t id) +{ + return ioctl(notifyFd, SECCOMP_IOCTL_NOTIF_ID_VALID, &id) == 0; +} + +static int send_target(const struct seccomp_notif_resp *resp, int notifyfd) +{ + if (!is_cookie_valid(notifyfd, resp->id)) { + fprintf(stderr, "the response id isn't valid\ncheck if the targets has already terminated\n"); + return -1; + } + if (ioctl(notifyfd, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0) { + if (errno != EINPROGRESS) { + perror("sending the response"); + return -1; + } + } + return 0; +} + +static int send_inject_target(const struct seccomp_notif_addfd *resp, + int notifyfd) +{ + if (!is_cookie_valid(notifyfd, resp->id)) { + fprintf(stderr, "the response id isn't valid\ncheck if the targets has already terminated\n"); + return -1; + } + if (ioctl(notifyfd, SECCOMP_IOCTL_NOTIF_ADDFD, resp) < 0) { + if (errno != EINPROGRESS) { + perror("sending the response"); + return -1; + } + } + return 0; +} + +static void proc_ns_name(unsigned i, char *ns) +{ + switch (i) { + case NS_CGROUP: + snprintf(ns, PATH_MAX + 1, "cgroup"); + break; + case NS_IPC: + snprintf(ns, PATH_MAX + 1, "ipc"); + break; + case NS_NET: + snprintf(ns, PATH_MAX + 1, "net"); + break; + case NS_MOUNT: + snprintf(ns, PATH_MAX + 1, "mnt"); + break; + case NS_PID: + snprintf(ns, PATH_MAX + 1, "pid"); + break; + case NS_USER: + snprintf(ns, PATH_MAX + 1, "user"); + break; + case NS_UTS: + snprintf(ns, PATH_MAX + 1, "uts"); + break; + case NS_TIME: + snprintf(ns, PATH_MAX + 1, "time"); + break; + default: + fprintf(stderr, "unrecognized namespace index %d\n", i); + } +} + +static int set_namespaces(const struct act_call *a, int tpid) +{ + char path[PATH_MAX + 1]; + char ns_name[PATH_MAX / 2]; + struct ns_spec ns; + int fd; + unsigned int i; + + for (i = 0, ns = (a->context).ns[i]; i < sizeof(enum ns_type); + i++, ns = (a->context).ns[i]) { + proc_ns_name(i, ns_name); + switch (ns.type) { + case NS_NONE: + continue; + case NS_SPEC_TARGET: + snprintf(path, sizeof(path), "/proc/%d/ns/%s", tpid, + ns_name); + break; + case NS_SPEC_PID: + snprintf(path, sizeof(path), "/proc/%d/ns/%s", ns.pid, + ns_name); + break; + case NS_SPEC_PATH: + snprintf(path, sizeof(path), "%s", ns.path); + break; + } + + if ((fd = open(path, O_CLOEXEC)) < 0) { + fprintf(stderr, "open for file %s: %s", path, + strerror(errno)); + return -1; + } + + if (setns(fd, 0) != 0) { + perror("setns"); + return -1; + } + } + return 0; +} + +static int execute_syscall(void *args) +{ + struct arg_clone *a = (struct arg_clone *)args; + const struct act_call *c = a->args; + + if (set_namespaces(a->args, a->pid) < 0) { + exit(EXIT_FAILURE); + } + /* execute syscall */ + a->ret = syscall(c->nr, c->args[0], c->args[1], c->args[2], c->args[3], + c->args[4], c->args[5]); + a->err = errno; + if (a->ret < 0) { + perror("syscall"); + exit(EXIT_FAILURE); + } + exit(0); +} + +int do_call(struct arg_clone *c) +{ + char stack[STACK_SIZE]; + pid_t child; + + c->ret = -1; + c->err = 0; + + /* Create a process that will be moved to the namespace */ + child = clone(execute_syscall, stack + sizeof(stack), + CLONE_FILES | CLONE_VM | SIGCHLD, (void *)c); + if (child == -1) { + perror("clone"); + return -1; + } + wait(NULL); + return 0; +} + +int do_actions(struct action actions[], unsigned int n_actions, int pid, + int notifyfd, uint64_t id) +{ + struct seccomp_notif_resp resp; + struct arg_clone c; + unsigned int i; + + for (i = 0; i < n_actions; i++) { + switch (actions[i].type) { + case A_CALL: + resp.id = id; + resp.val = 0; + resp.flags = 0; + c.args = &actions[i].call; + c.pid = pid; + if (do_call(&c) == -1) { + resp.error = c.err; + if (send_target(&resp, notifyfd) == -1) + return -1; + } + break; + default: + fprintf(stderr, "unknow action %d \n", actions[i].type); + } + } + return 0; +} -- cgit v1.2.3