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 --- common/gluten.h | 46 ++++---- operations.c | 320 ++++++++++++++++++++++++++++++-------------------------- operations.h | 38 ++++++- seitan.c | 15 +-- 4 files changed, 231 insertions(+), 188 deletions(-) diff --git a/common/gluten.h b/common/gluten.h index 61270d8..b1723ca 100644 --- a/common/gluten.h +++ b/common/gluten.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * Copyright 2023 Red Hat GmbH - * Authors: Alice Frosi - * Stefano Brivio - */ +* Copyright 2023 Red Hat GmbH +* Authors: Alice Frosi +* Stefano Brivio +*/ #ifndef COMMON_GLUTEN_H #define COMMON_GLUTEN_H @@ -22,25 +22,27 @@ extern struct seccomp_data anonymous_seccomp_data; #define DATA_SIZE 4096 #define INST_MAX 16 -#define OFFSET_MAX MAX(MAX(MAX(DATA_SIZE, RO_DATA_SIZE), \ - INST_MAX), \ - ARRAY_SIZE(anonymous_seccomp_data.args)) +#define OFFSET_MAX \ + MAX(MAX(MAX(DATA_SIZE, RO_DATA_SIZE), INST_MAX), \ + ARRAY_SIZE(anonymous_seccomp_data.args)) + +#define seccomp_offset_args(x) (sizeof(uint64_t) / sizeof(uint16_t)) * (x) enum gluten_offset_type { - OFFSET_RO_DATA = 0, - OFFSET_DATA = 1, - OFFSET_SECCOMP_DATA = 2, - OFFSET_INSTRUCTION = 3, - OFFSET_TYPE_MAX = OFFSET_INSTRUCTION, + OFFSET_RO_DATA = 0, + OFFSET_DATA = 1, + OFFSET_SECCOMP_DATA = 2, + OFFSET_INSTRUCTION = 3, + OFFSET_TYPE_MAX = OFFSET_INSTRUCTION, }; struct gluten_offset { #ifdef __GNUC__ - enum gluten_offset_type type:BITS_PER_NUM(OFFSET_TYPE_MAX); + enum gluten_offset_type type : BITS_PER_NUM(OFFSET_TYPE_MAX); #else - uint16_t type:BITS_PER_NUM(OFFSET_TYPE_MAX); + uint16_t type : BITS_PER_NUM(OFFSET_TYPE_MAX); #endif - uint16_t offset:BITS_PER_NUM(OFFSET_MAX); + uint16_t offset : BITS_PER_NUM(OFFSET_MAX); }; BUILD_BUG_ON(BITS_PER_NUM(OFFSET_TYPE_MAX) + BITS_PER_NUM(OFFSET_MAX) > 16) @@ -90,9 +92,9 @@ enum op_type { OP_INJECT_A, OP_RETURN, OP_LOAD, - OP_END, OP_CMP, OP_RESOLVEDFD, + OP_END, }; enum value_type { @@ -130,12 +132,6 @@ struct op_inject { struct gluten_offset old_fd; }; -struct copy_arg { - uint16_t args_off; - enum value_type type; - size_t size; -}; - struct op_load { struct gluten_offset src; struct gluten_offset dst; @@ -160,8 +156,8 @@ struct op_cmp { }; struct op_resolvedfd { - uint16_t fd_off; - uint16_t path_off; + struct gluten_offset fd; + struct gluten_offset path; size_t path_size; unsigned int jmp; }; @@ -171,8 +167,8 @@ struct op { union { struct op_nr nr; struct op_call call; - struct op_block block; struct op_continue cont; + struct op_block block; struct op_return ret; struct op_inject inject; struct op_load load; 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; } diff --git a/operations.h b/operations.h index ecb6414..011369a 100644 --- a/operations.h +++ b/operations.h @@ -9,8 +9,23 @@ #include #include +#include "common/gluten.h" +#include "common/util.h" + #define STACK_SIZE (1024 * 1024 / 8) #define NS_NUM (sizeof(enum ns_type)) +#define HANDLE_OP(code, call, type) \ + case code: \ + do { \ + int res = call(req, notifier, g, &op->op.type); \ + if (res == 0) \ + (op)++; \ + else if (res == -1) \ + (op) = NULL; \ + else \ + (op) += res; \ + } while (0); \ + break struct arg_clone { const struct op_call *args; @@ -20,7 +35,24 @@ struct arg_clone { }; int do_call(struct arg_clone *c); -int do_operations(struct gluten *g, struct op operations[], - struct seccomp_notif *req, - unsigned int n_operations, int notifyfd); +void eval(struct gluten *g, struct op *ops, const struct seccomp_notif *req, + int notifier); +int op_call(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_call *op); +int op_block(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_block *op); +int op_return(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_return *op); +int op_continue(const struct seccomp_notif *req, int notifier, struct gluten *g, + void *); +int op_inject(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_inject *op); +int op_inject_a(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_inject *op); +int op_cmp(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_cmp *op); +int op_resolve_fd(const struct seccomp_notif *req, int notifier, + struct gluten *g, struct op_resolvedfd *op); +int op_load(const struct seccomp_notif *req, int notifier, struct gluten *g, + struct op_load *load); #endif /* ACTIONS_H */ diff --git a/seitan.c b/seitan.c index e2e5347..4a4cc86 100644 --- a/seitan.c +++ b/seitan.c @@ -184,6 +184,7 @@ int main(int argc, char **argv) struct epoll_event ev, events[EPOLL_EVENTS]; struct seccomp_notif *req = (struct seccomp_notif *)req_b; struct arguments arguments; + struct op operations[INST_MAX]; char path[PATH_MAX + 1]; bool running = true; int pidfd, notifier; @@ -236,19 +237,7 @@ int main(int argc, char **argv) /* The notifier fd was closed by the target */ running = false; } else if (notifier == events[i].data.fd) { - /* - * TODO: remove until we parse correctly the - * operations from the bytecode - */ - struct op operations[] = { - { .type = OP_CONT }, - }; - if (do_operations(NULL, operations, req, - sizeof(operations) / - sizeof(operations[0]), - notifier) == -1) - die(" failed executing operation"); - + eval(NULL, &operations[0], req, notifier); } } } -- cgit v1.2.3