From c29157e78df7fa335c56d0d7f2cca7dc50bfffd6 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Tue, 2 May 2023 17:21:57 +0200 Subject: seitan: refactor operations Refactoring: - rename do_operations to eval and reduce the number of arguments - create macro HANDLE_OP - rename all functions with op_*(operation name) - exposed the op_* functions in the operations.h Fixes: - use pread for op_load --- operations.c | 320 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 173 insertions(+), 147 deletions(-) (limited to 'operations.c') diff --git a/operations.c b/operations.c index 23d571c..870ecf1 100644 --- a/operations.c +++ b/operations.c @@ -23,7 +23,7 @@ #include #include -#include "gluten.h" +#include "common/gluten.h" #include "operations.h" static bool is_cookie_valid(int notifyFd, uint64_t id) @@ -31,14 +31,14 @@ 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) +static int send_target(const struct seccomp_notif_resp *resp, int notifier) { - if (!is_cookie_valid(notifyfd, resp->id)) { + if (!is_cookie_valid(notifier, resp->id)) { fprintf(stderr, "the response id isn't valid\ncheck if the targets has already terminated\n"); - return -1; + exit(0); } - if (ioctl(notifyfd, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0) { + if (ioctl(notifier, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0) { if (errno != EINPROGRESS) { perror("sending the response"); return -1; @@ -48,14 +48,14 @@ static int send_target(const struct seccomp_notif_resp *resp, int notifyfd) } static int send_inject_target(const struct seccomp_notif_addfd *resp, - int notifyfd) + int notifier) { - if (!is_cookie_valid(notifyfd, resp->id)) { + if (!is_cookie_valid(notifier, 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 (ioctl(notifier, SECCOMP_IOCTL_NOTIF_ADDFD, resp) < 0) { if (errno != EINPROGRESS) { perror("sending the response"); return -1; @@ -156,9 +156,10 @@ static int execute_syscall(void *args) exit(0); } -static int op_load(struct seccomp_notif *req, int notifier, struct gluten *g, - struct op_load *load) +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; @@ -176,43 +177,21 @@ static int op_load(struct seccomp_notif *req, int notifier, struct gluten *g, ret = -1; goto out; } - - memcpy(gluten_write_ptr(g, load->dst), - gluten_ptr(&req->data, g, load->src), - load->size); + if (pread(fd, gluten_write_ptr(g, load->dst), load->size, *src) < 0) { + perror("pread"); + return -1; + } out: close(fd); return ret; } -static int resolve_fd(void *data, struct op_resolvedfd *resfd, pid_t pid) -{ - char fdpath[PATH_MAX], buf[PATH_MAX]; - char *path = (char *)((uint16_t *)data + resfd->path_off); - int *fd = (int *)((uint16_t *)data + resfd->fd_off); - ssize_t nbytes; - - snprintf(fdpath, PATH_MAX, "/proc/%d/fd/%d", pid, *fd); - if ((nbytes = readlink(fdpath, buf, resfd->path_size)) < 0) { - fprintf(stderr, "error reading %s\n", fdpath); - perror("readlink"); - return -1; - } - if (strcmp(path, buf) == 0) - return 0; - else - return 1; -} - 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); @@ -224,23 +203,129 @@ int do_call(struct arg_clone *c) return 0; } -static void set_inject_fields(uint64_t id, struct gluten *g, - const struct op_inject *a, - struct seccomp_notif_addfd *resp) +int op_call(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_call *op) +{ + struct seccomp_notif_resp resp; + struct arg_clone c; + + resp.id = req->id; + resp.val = 0; + resp.flags = 0; + resp.error = 0; + c.args = op; + c.pid = req->pid; + c.err = 0; + + if (do_call(&c) == -1) { + resp.error = -1; + if (send_target(&resp, notifier) == -1) + return -1; + } + if (c.err != 0) { + resp.error = -1; + if (send_target(&resp, notifier) == -1) + return -1; + } + /* + * The result of the call needs to be save as + * reference + */ + if (op->has_ret) + memcpy(gluten_write_ptr(g, op->ret), &c.ret, sizeof(c.ret)); + + return 0; +} + +int op_block(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_block *op) +{ + struct seccomp_notif_resp resp; + + (void)g; + resp.id = req->id; + resp.val = 0; + resp.flags = 0; + resp.error = op->error; + + if (send_target(&resp, notifier) == -1) + return -1; + + return 0; +} + +int op_return(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_return *op) +{ + struct seccomp_notif_resp resp; + + resp.id = req->id; + resp.flags = 0; + resp.error = 0; + + memcpy(&resp.val, gluten_ptr(NULL, g, op->val), sizeof(resp.val)); + + if (send_target(&resp, notifier) == -1) + return -1; + + return 0; +} + +int op_continue(const struct seccomp_notif *req, int notifier, struct gluten *g, + void *op) +{ + struct seccomp_notif_resp resp; + + (void)g; + (void)op; + + resp.id = req->id; + resp.flags = SECCOMP_USER_NOTIF_FLAG_CONTINUE; + resp.error = 0; + resp.val = 0; + + if (send_target(&resp, notifier) == -1) + return -1; + + return 0; +} + +static int do_inject(const struct seccomp_notif *req, int notifier, + struct gluten *g, struct op_inject *op, bool atomic) { - resp->flags = SECCOMP_ADDFD_FLAG_SETFD; - resp->id = id; + struct seccomp_notif_addfd resp; + + resp.flags = SECCOMP_ADDFD_FLAG_SETFD; + resp.newfd_flags = 0; + resp.id = req->id; + + memcpy(&resp.newfd, gluten_ptr(NULL, g, op->new_fd), + sizeof(resp.newfd)); + memcpy(&resp.srcfd, gluten_ptr(NULL, g, op->new_fd), + sizeof(resp.srcfd)); + + if (atomic) + resp.flags |= SECCOMP_ADDFD_FLAG_SEND; + if (send_inject_target(&resp, notifier) == -1) + return -1; + + return 0; +} - memcpy(&resp->newfd, gluten_ptr(NULL, g, a->new_fd), - sizeof(resp->newfd)); - memcpy(&resp->srcfd, gluten_ptr(NULL, g, a->new_fd), - sizeof(resp->srcfd)); +int op_inject(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_inject *op) +{ + return do_inject(req, notifier, g, op, false); +} - resp->newfd_flags = 0; +int op_inject_a(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_inject *op) +{ + return do_inject(req, notifier, g, op, true); } -static int op_cmp(struct seccomp_notif *req, int notifier, struct gluten *g, - struct op_cmp *op) +int op_cmp(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_cmp *op) { int res = memcmp(gluten_ptr(&req->data, g, op->x), gluten_ptr(&req->data, g, op->y), op->size); @@ -249,116 +334,57 @@ static int op_cmp(struct seccomp_notif *req, int notifier, struct gluten *g, (void)notifier; if ((res == 0 && (cmp == CMP_EQ || cmp == CMP_LE || cmp == CMP_GE)) || - (res < 0 && (cmp == CMP_LT || cmp == CMP_LE)) || - (res > 0 && (cmp == CMP_GT || cmp == CMP_GE))) + (res < 0 && (cmp == CMP_LT || cmp == CMP_LE)) || + (res > 0 && (cmp == CMP_GT || cmp == CMP_GE)) || + (res != 0 && (cmp == CMP_NE))) return op->jmp; - return -1; + return 0; } -int do_operations(struct gluten *g, struct op *ops, struct seccomp_notif *req, - unsigned int n_ops, int notifyfd) +int op_resolve_fd(const struct seccomp_notif *req, int notifier, + struct gluten *g, struct op_resolvedfd *op) { - struct seccomp_notif_addfd resp_fd; - struct seccomp_notif_resp resp; - struct arg_clone c; - unsigned int i; - struct op *op; - int ret; + char fdpath[PATH_MAX], buf[PATH_MAX], path[PATH_MAX]; + ssize_t nbytes; + int fd; - for (i = 0, op = ops; i < n_ops; i++, op++) { - switch (op->type) { - case OP_CALL: - resp.id = req->id; - resp.val = 0; - resp.flags = 0; - c.args = &ops[i].op.call; - c.pid = req->pid; - if (do_call(&c) == -1) { - resp.error = -1; - if (send_target(&resp, notifyfd) == -1) - return -1; - } - if (c.err != 0) { - resp.error = -1; - if (send_target(&resp, notifyfd) == -1) - return c.err; - } - /* - * The result of the call needs to be save as - * reference - */ - if (ops[i].op.call.has_ret) { - memcpy(gluten_write_ptr(g, op->op.call.ret), - &c.ret, sizeof(c.ret)); - } - break; - case OP_BLOCK: - resp.id = req->id; - resp.val = 0; - resp.flags = 0; - resp.error = ops[i].op.block.error; - if (send_target(&resp, notifyfd) == -1) - return -1; - break; - case OP_RETURN: - resp.id = req->id; - resp.flags = 0; - resp.error = 0; + (void)notifier; - memcpy(&resp.val, - gluten_ptr(&req->data, g, op->op.ret.val), - sizeof(resp.val)); + memcpy(&path, gluten_ptr(NULL, g, op->path), op->path_size); + memcpy(&fd, gluten_ptr(NULL, g, op->fd), sizeof(fd)); - if (send_target(&resp, notifyfd) == -1) - return -1; - break; + snprintf(fdpath, PATH_MAX, "/proc/%d/fd/%d", req->pid, fd); + if ((nbytes = readlink(fdpath, buf, op->path_size)) < 0) { + fprintf(stderr, "error reading %s\n", fdpath); + perror("readlink"); + return -1; + } + if (strcmp(path, buf) == 0) + return op->jmp; - case OP_CONT: - resp.id = req->id; - resp.flags = SECCOMP_USER_NOTIF_FLAG_CONTINUE; - resp.error = 0; - resp.val = 0; - if (send_target(&resp, notifyfd) == -1) - return -1; - break; - case OP_INJECT_A: - set_inject_fields(req->id, g, &ops[i].op.inject, - &resp_fd); - resp_fd.flags |= SECCOMP_ADDFD_FLAG_SEND; - if (send_inject_target(&resp_fd, notifyfd) == -1) - return -1; - break; - case OP_INJECT: - set_inject_fields(req->id, g, &ops[i].op.inject, - &resp_fd); - if (send_inject_target(&resp_fd, notifyfd) == -1) - return -1; - break; - case OP_LOAD: - if (op_load(req, notifyfd, g, &op->op.load)) - return -1; + return 0; +} - break; - case OP_END: - return 0; - case OP_CMP: - ret = op_cmp(req, notifyfd, g, (struct op_cmp *)op); - if (ret == -1) - return -1; - - i = ret; - break; - case OP_RESOLVEDFD: - ret = resolve_fd(g->data, &ops[i].op.resfd, req->pid); - if (ret == -1) - return -1; - else if (ret == 1) - i = ops[i].op.resfd.jmp; - break; +void eval(struct gluten *g, struct op *ops, const struct seccomp_notif *req, + int notifier) +{ + struct op *op = ops; + + while (op->type != OP_END && op != NULL) { + switch (op->type) { + HANDLE_OP(OP_CALL, op_call, call); + HANDLE_OP(OP_BLOCK, op_block, block); + HANDLE_OP(OP_RETURN, op_return, ret); + HANDLE_OP(OP_CONT, op_continue, cont); + HANDLE_OP(OP_INJECT_A, op_inject_a, inject); + HANDLE_OP(OP_INJECT, op_inject, inject); + HANDLE_OP(OP_LOAD, op_load, load); + HANDLE_OP(OP_CMP, op_cmp, cmp); + HANDLE_OP(OP_RESOLVEDFD, op_resolve_fd, resfd); default: - fprintf(stderr, "unknown operation %d \n", ops[i].type); + fprintf(stderr, "unknown operation %d \n", op->type); + return; } } - return 0; } -- cgit v1.2.3