aboutgitcodelistschat:MatrixIRC
diff options
context:
space:
mode:
-rw-r--r--actions.c193
-rw-r--r--actions.h20
-rw-r--r--gluten.h94
3 files changed, 307 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sched.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <linux/seccomp.h>
+#include <linux/filter.h>
+#include <linux/audit.h>
+#include <errno.h>
+
+#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 <errno.h>
+
+#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 <stdint.h>
+#include <stdbool.h>
+
+#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 */