aboutgitcodelistschat:MatrixIRC
diff options
context:
space:
mode:
authorAlice Frosi <afrosi@redhat.com>2023-05-02 17:21:57 +0200
committerAlice Frosi <afrosi@redhat.com>2023-05-08 14:36:43 +0200
commitc29157e78df7fa335c56d0d7f2cca7dc50bfffd6 (patch)
tree6c7ce428c01a602f89c8897015e7428b84038871
parent82b77505f9420f11d614c2ae0f74153ca4ee3cb5 (diff)
downloadseitan-c29157e78df7fa335c56d0d7f2cca7dc50bfffd6.tar
seitan-c29157e78df7fa335c56d0d7f2cca7dc50bfffd6.tar.gz
seitan-c29157e78df7fa335c56d0d7f2cca7dc50bfffd6.tar.bz2
seitan-c29157e78df7fa335c56d0d7f2cca7dc50bfffd6.tar.lz
seitan-c29157e78df7fa335c56d0d7f2cca7dc50bfffd6.tar.xz
seitan-c29157e78df7fa335c56d0d7f2cca7dc50bfffd6.tar.zst
seitan-c29157e78df7fa335c56d0d7f2cca7dc50bfffd6.zip
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
-rw-r--r--common/gluten.h46
-rw-r--r--operations.c320
-rw-r--r--operations.h38
-rw-r--r--seitan.c15
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 <afrosi@redhat.com>
- * Stefano Brivio <sbrivio@redhat.com>
- */
+* Copyright 2023 Red Hat GmbH
+* Authors: Alice Frosi <afrosi@redhat.com>
+* Stefano Brivio <sbrivio@redhat.com>
+*/
#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 <linux/audit.h>
#include <errno.h>
-#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 <errno.h>
#include <linux/seccomp.h>
+#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);
}
}
}