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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ actions.h | 20 +++++++ gluten.h | 94 ++++++++++++++++++++++++++++++ 3 files changed, 307 insertions(+) create mode 100644 actions.c create mode 100644 actions.h create mode 100644 gluten.h 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; +} diff --git a/actions.h b/actions.h new file mode 100644 index 0000000..3636f04 --- /dev/null +++ b/actions.h @@ -0,0 +1,20 @@ +#ifndef ACIONS_H +#define ACTIONS_H + +#include + +#define STACK_SIZE (1024 * 1024 / 8) +#define NS_NUM (sizeof(enum ns_type)) + +struct arg_clone { + const struct act_call *args; + pid_t pid; + long ret; + int err; +}; + +int do_call(struct arg_clone *c); +int do_actions(struct action actions[], unsigned int n_actions, int tpid, + int notifyfd, uint64_t id); +#endif /* ACTIONS_H */ + diff --git a/gluten.h b/gluten.h new file mode 100644 index 0000000..b20cab6 --- /dev/null +++ b/gluten.h @@ -0,0 +1,94 @@ +#ifndef GLUTEN_H +#define GLUTEN_H + +#include +#include + +#define MAX_FD_INJECTED 10 + +enum ns_spec_type { + NS_NONE, + NS_SPEC_TARGET, + NS_SPEC_PID, + NS_SPEC_PATH, +}; + +struct ns_spec { + enum ns_spec_type type; + union { + pid_t pid; + char *path; + }; +}; + +/* + * enum ns_type - Type of namespaces + */ +enum ns_type { + NS_CGROUP, + NS_IPC, + NS_NET, + NS_MOUNT, + NS_PID, + NS_TIME, + NS_USER, + NS_UTS, +}; + +/* + * struct act_context - Description of the context where the call needs to be executed + * @ns: Descrption of the each namespace where the call needs to be executed + */ +struct act_context { + struct ns_spec ns[sizeof(enum ns_type)]; +}; + +enum action_type { + A_CALL, + A_BLOCK, + A_CONT, + A_INJECT, + A_INJECT_A, +}; + +struct act_call { + long nr; + void *args[6]; + struct act_context context; +}; + +struct act_block { + int32_t error; +}; + +struct act_continue { + bool cont; +}; + +struct act_return { + int64_t value; +}; + +struct act_inject { + uint32_t newfd; + uint32_t old; +}; + +struct act_inject_a { + uint32_t newfd; + uint32_t old; + int64_t value; +}; + +struct action { + enum action_type type; + union { + struct act_call call; + struct act_block block; + struct act_continue cont; + struct act_return ret; + struct act_inject inj; + struct act_inject_a inj_a; + }; +}; +#endif /* GLUTEN_H */ -- cgit v1.2.3