From bb47d77d316137c9deddd46135b22dc144ae1ea9 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Mon, 22 May 2023 17:03:08 +0200 Subject: ops: adjust op_call --- Makefile | 2 +- common/common.c | 2 + common/gluten.h | 16 ++++--- operations.c | 137 ++++++++++++++++++++++++++++++++++++-------------------- 4 files changed, 102 insertions(+), 55 deletions(-) diff --git a/Makefile b/Makefile index 9edf4f2..591e734 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ HEADERS := $(COMMON_DIR)/common.h $(COMMON_DIR)/gluten.h \ $(COMMON_DIR)/numbers.h $(COMMON_DIR)/util.h operations.h CFLAGS += -DTMP_DATA_SIZE=1000 -CFLAGS += -Wall -Wextra -pedantic -I$(COMMON_DIR) +CFLAGS += -Wall -Wextra -pedantic -std=c99 -I$(COMMON_DIR) all: cooker eater seitan diff --git a/common/common.c b/common/common.c index cd792de..f67f175 100644 --- a/common/common.c +++ b/common/common.c @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include #include #include @@ -11,6 +12,7 @@ #include #include +#include #include "util.h" #include "common.h" diff --git a/common/gluten.h b/common/gluten.h index 9bd4689..6c0fc25 100644 --- a/common/gluten.h +++ b/common/gluten.h @@ -33,6 +33,7 @@ extern struct seccomp_data anonymous_seccomp_data; #define NO_FIELD block #define NS_NUM sizeof(enum ns_type) +#define GET_BIT(x, i) (((x) & (1UL << (i))) != 0) enum gluten_offset_type { OFFSET_RO_DATA = 0, @@ -113,12 +114,17 @@ struct op_nr { struct gluten_offset no_match; }; +struct syscall_desc { + unsigned nr : 9; + unsigned arg_count : 3; + unsigned has_ret : 1; + unsigned arg_deref : 6; + struct gluten_offset data[]; +}; + struct op_call { - struct gluten_offset nr; - struct gluten_offset args[6]; - struct op_context context; - struct gluten_offset ret; - bool has_ret; + struct gluten_offset syscall; + struct gluten_offset context; }; struct op_block { diff --git a/operations.c b/operations.c index c751919..d28c4b8 100644 --- a/operations.c +++ b/operations.c @@ -84,27 +84,70 @@ static void proc_ns_name(unsigned i, char *ns) } } +static struct gluten_offset *get_syscall_ret(struct syscall_desc *s) +{ + if (s == NULL) + return NULL; + if (s->has_ret == 0) + return NULL; + if (s->arg_count == 0) + return s->data; + return s->data + s->arg_count + 1; +} + +static int write_syscall_ret(struct gluten *g, struct syscall_desc *s, + const struct arg_clone *c) +{ + struct gluten_offset *p = get_syscall_ret(s); + + if (p != NULL) + return gluten_write(g, *p, &c->ret, sizeof(c->ret)); + + return 0; +} + static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g, - const struct op_call *op, struct arg_clone *c) + const struct op_call *op, struct syscall_desc *s, + struct arg_clone *c) { char ns_name[PATH_MAX / 2]; const struct ns_spec *ns; + struct op_context context; char p[PATH_MAX]; + struct gluten_offset x; unsigned int i; + long arg; pid_t pid; + if (gluten_read(NULL, g, s, op->syscall, sizeof(struct syscall_desc)) == -1) + return -1; + if (gluten_read(NULL, g, &context, op->context, sizeof(context)) == -1) + return -1; + c->err = 0; c->ret = -1; + c->nr = s-> nr; - if (gluten_read(NULL, g, &c->nr, op->nr, sizeof(c->nr)) == -1) - return -1; - for (i = 0; i < 6; i++) - if (gluten_read(NULL, g, &c->args[i], op->args[i], - sizeof(c->args[i])) == -1) + for (i = 0; i < s->arg_count; i++) { + if (gluten_read(NULL, g, &arg, s->data[i], sizeof(arg)) == -1) return -1; + /* If arg is a pointer then need to calculate the absolute + * address and the value of arg is the relative offset of the actual + * value. + */ + if (GET_BIT(s->arg_deref, i) == 1) { + x.type = s->data[i].type; + x.offset = arg; + if (gluten_read(NULL, g, &c->args[i], x, + sizeof(c->args[i])) == -1) + return -1; + } else { + c->args[i] = (void *)arg; + } + } - for (i = 0; i < sizeof(enum ns_type); i++) { - ns = &op->context.ns[i]; + for (i = 0; i < NS_NUM; i++) { + ns = &context.ns[i]; proc_ns_name(i, ns_name); switch (ns->type) { case NS_NONE: @@ -127,6 +170,7 @@ static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g, break; } } + return 0; } @@ -165,40 +209,6 @@ static int execute_syscall(void *args) exit(0); } -int op_load(const struct seccomp_notif *req, int notifier, struct gluten *g, - struct op_load *load) -{ - const long unsigned int *src = gluten_ptr(&req->data, g, load->src); - char path[PATH_MAX]; - int fd, ret = 0; - - snprintf(path, sizeof(path), "/proc/%d/mem", req->pid); - if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) - ret_err(-1, "error opening mem for %d", req->pid); - - /* - * Avoid the TOCTOU and check if the read mappings are still valid - */ - if (!is_cookie_valid(notifier, req->id)) { - err("the seccomp request isn't valid anymore"); - ret = -1; - goto out; - } - if (!check_gluten_limits(load->dst, load->size)) { - ret = -1; - goto out; - } - if (pread(fd, gluten_write_ptr(g, load->dst), load->size, *src) < 0) { - err("pread"); - ret = -1; - goto out; - } - -out: - close(fd); - return ret; -} - int do_call(struct arg_clone *c) { char stack[STACK_SIZE]; @@ -216,6 +226,7 @@ int op_call(const struct seccomp_notif *req, int notifier, struct gluten *g, struct op_call *op) { struct seccomp_notif_resp resp; + struct syscall_desc s; struct arg_clone c; resp.id = req->id; @@ -223,7 +234,7 @@ int op_call(const struct seccomp_notif *req, int notifier, struct gluten *g, resp.flags = 0; resp.error = 0; - if (prepare_arg_clone(req, g, op, &c) == -1) + if (prepare_arg_clone(req, g, op, &s, &c) == -1) return -1; debug(" op_call: execute syscall nr=%ld", c.nr); if (do_call(&c) == -1) { @@ -237,14 +248,42 @@ int op_call(const struct seccomp_notif *req, int notifier, struct gluten *g, if (send_target(&resp, notifier) == -1) return -1; } + + return write_syscall_ret(g, &s, &c); +} + +int op_load(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_load *load) +{ + const long unsigned int *src = gluten_ptr(&req->data, g, load->src); + char path[PATH_MAX]; + int fd, ret = 0; + + snprintf(path, sizeof(path), "/proc/%d/mem", req->pid); + if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) + ret_err(-1, "error opening mem for %d", req->pid); + /* - * The result of the call needs to be save as - * reference - */ - if (op->has_ret) - return gluten_write(g, op->ret, &c.ret, sizeof(c.ret)); + * Avoid the TOCTOU and check if the read mappings are still valid + */ + if (!is_cookie_valid(notifier, req->id)) { + err("the seccomp request isn't valid anymore"); + ret = -1; + goto out; + } + if (!check_gluten_limits(load->dst, load->size)) { + ret = -1; + goto out; + } + if (pread(fd, gluten_write_ptr(g, load->dst), load->size, *src) < 0) { + err("pread"); + ret = -1; + goto out; + } - return 0; +out: + close(fd); + return ret; } int op_block(const struct seccomp_notif *req, int notifier, struct gluten *g, -- cgit v1.2.3