aboutgitcodelistschat:MatrixIRC
diff options
context:
space:
mode:
authorAlice Frosi <afrosi@redhat.com>2023-06-08 17:43:56 +0200
committerStefano Brivio <sbrivio@redhat.com>2023-06-09 10:31:35 +0200
commitf1f136577a52b1588da5f74683f41d14df410300 (patch)
tree10a66b9f78cc87182e9aac12db7b02dd6834bd6b
parent15b54482241083d52b6e9857a66fecbf915d467d (diff)
downloadseitan-f1f136577a52b1588da5f74683f41d14df410300.tar
seitan-f1f136577a52b1588da5f74683f41d14df410300.tar.gz
seitan-f1f136577a52b1588da5f74683f41d14df410300.tar.bz2
seitan-f1f136577a52b1588da5f74683f41d14df410300.tar.lz
seitan-f1f136577a52b1588da5f74683f41d14df410300.tar.xz
seitan-f1f136577a52b1588da5f74683f41d14df410300.tar.zst
seitan-f1f136577a52b1588da5f74683f41d14df410300.zip
seitan,cooker: add wd to change work directory and mknod
./seitan-cooker demo/mknod.hjson demo/mknod.gluten demo/mknod.bpf Start seitan with the socket option: ./seitan -s /tmp/seitan.sock -i demo/mknod.gluten Start the container: sudo rm -f /dev/lol sudo chown $USER:$USER /tmp/seitan.sock podman run -ti --runtime /usr/bin/crun \ --security-opt label=disable \ -v $(pwd)/test:/test \ --annotation run.oci.seccomp_bpf_data="$(base64 -w0 demo/mknod.bpf)" \ --annotation run.oci.seccomp.receiver=/tmp/seitan.sock fedora \ sh -c 'mknod /dev/lol c 1 7 && ls -l /dev/lol'
-rw-r--r--common/gluten.h72
-rw-r--r--common/util.c8
-rw-r--r--cooker/call.c47
-rw-r--r--cooker/emit.c18
-rw-r--r--cooker/emit.h2
-rw-r--r--demo/mknod.hjson5
-rw-r--r--operations.c79
-rw-r--r--operations.h1
-rw-r--r--seitan.c2
9 files changed, 132 insertions, 102 deletions
diff --git a/common/gluten.h b/common/gluten.h
index a90cf4a..794b50f 100644
--- a/common/gluten.h
+++ b/common/gluten.h
@@ -74,52 +74,55 @@ enum op_type {
};
/**
- * enum ns_spec_type - Type of reference to target namespace
+ * enum context_spec_type - Type of reference to target namespace and directory
*/
-enum ns_spec_type {
- NS_SPEC_NONE = 0,
+enum context_spec_type {
+ CONTEXT_SPEC_NONE = 0,
/* PID from seccomp_data */
- NS_SPEC_CALLER = 1,
+ CONTEXT_SPEC_CALLER = 1,
/* PID/path from gluten, resolved in seitan */
- NS_SPEC_PID = 2,
- NS_SPEC_PATH = 3,
+ CONTEXT_SPEC_PID = 2,
+ CONTEXT_SPEC_PATH = 3,
- NS_SPEC_TYPE_MAX = NS_SPEC_PATH,
+ CONTEXT_SPEC_TYPE_MAX = CONTEXT_SPEC_PATH,
};
/**
- * enum ns_type - Namespace types: see <linux/sched.h>
+ * enum context_type - Working directory, and namespaces (see <linux/sched.h>)
*/
-enum ns_type {
- NS_MOUNT = 0,
- NS_CGROUP = 1,
- NS_UTS = 2,
- NS_IPC = 3,
- NS_USER = 4,
- NS_PID = 5,
- NS_NET = 6,
- NS_TIME = 7,
- NS_TYPE_MAX = NS_TIME,
+enum context_type {
+ NS_MOUNT = 0,
+ NS_CGROUP = 1,
+ NS_UTS = 2,
+ NS_IPC = 3,
+ NS_USER = 4,
+ NS_PID = 5,
+ NS_NET = 6,
+ NS_TIME = 7,
+ NS_TYPE_MAX = NS_TIME,
+ CWD = 8,
+ CONTEXT_TYPE_MAX = CWD,
};
-extern const char *ns_type_name[NS_TYPE_MAX + 1];
+extern const char *context_type_name[CONTEXT_TYPE_MAX + 1];
+extern const char *context_spec_type_name[CONTEXT_SPEC_TYPE_MAX + 1];
/**
- * struct ns_spec - Identification of one type of target namespace
- * @ns: Namespace type
+ * struct context_desc - Identification of one type of context information
+ * @context: Type of context (namespace types, or working directory)
* @spec: Reference type
* @target.pid: PID in procfs reference
* @target.path: Filesystem-bound (nsfs) reference
*/
-struct ns_spec {
+struct context_desc {
#ifdef __GNUC__
- enum ns_type ns :BITS_PER_NUM(NS_TYPE_MAX);
- enum ns_spec_type spec :BITS_PER_NUM(NS_SPEC_TYPE_MAX);
+ enum context_type type :BITS_PER_NUM(CONTEXT_TYPE_MAX);
+ enum context_spec_type spec :BITS_PER_NUM(CONTEXT_SPEC_TYPE_MAX);
#else
- uint8_t ns :BITS_PER_NUM(NS_TYPE_MAX);
- uint8_t spec :BITS_PER_NUM(NS_SPEC_TYPE_MAX);
+ uint8_t type :BITS_PER_NUM(CONTEXT_TYPE_MAX);
+ uint8_t spec :BITS_PER_NUM(CONTEXT_SPEC_TYPE_MAX);
#endif
union {
pid_t pid;
@@ -127,17 +130,8 @@ struct ns_spec {
} target;
};
-BUILD_BUG_ON(BITS_PER_NUM(NS_TYPE_MAX) + BITS_PER_NUM(NS_SPEC_TYPE_MAX) > 8)
-
-/**
- * struct context_desc - Description of context where the call is executed
- * @count: Number of namespace specifications
- * @ns: Namespace specifications
- */
-struct context_desc {
- uint8_t count;
- struct ns_spec ns[];
-};
+BUILD_BUG_ON(BITS_PER_NUM(CONTEXT_TYPE_MAX) + \
+ BITS_PER_NUM(CONTEXT_SPEC_TYPE_MAX) > 8)
struct syscall_desc {
uint32_t nr :9;
@@ -145,8 +139,8 @@ struct syscall_desc {
uint32_t has_ret :1;
uint32_t arg_deref :6;
- struct gluten_offset context; /* struct ns_spec [] */
- struct gluten_offset args[];
+ struct gluten_offset context; /* struct context_desc [] */
+ struct gluten_offset args[];
};
struct fd_desc {
diff --git a/common/util.c b/common/util.c
index a03b73e..f7fc288 100644
--- a/common/util.c
+++ b/common/util.c
@@ -34,8 +34,12 @@ const char *gluten_offset_name[OFFSET_TYPE_MAX + 1] = {
"read-only data", "temporary data", "seccomp data", "instruction area",
};
-const char *ns_type_name[NS_TYPE_MAX + 1] = {
- "mnt", "cgroup", "uts", "ipc", "user", "pid", "net", "time",
+const char *context_type_name[CONTEXT_TYPE_MAX + 1] = {
+ "mnt", "cgroup", "uts", "ipc", "user", "pid", "net", "time", "cwd",
+};
+
+const char *context_spec_type_name[CONTEXT_SPEC_TYPE_MAX + 1] = {
+ "none", "caller", "pid", "path",
};
const char *bitwise_type_str[BITWISE_MAX + 1] = { "&", "|" };
diff --git a/cooker/call.c b/cooker/call.c
index e2a5777..4e9cb9c 100644
--- a/cooker/call.c
+++ b/cooker/call.c
@@ -340,8 +340,9 @@ static struct gluten_offset parse_arg(struct gluten_ctx *g, struct arg *args,
return offset;
}
-static void parse_call(struct gluten_ctx *g, struct ns_spec *ns, long nr,
- JSON_Object *obj, const char *ret, struct arg *args)
+static void parse_call(struct gluten_ctx *g, struct context_desc *cdesc,
+ long nr, JSON_Object *obj, const char *ret,
+ struct arg *args)
{
struct gluten_offset offset[6] = { 0 }, ret_offset = { 0 };
bool is_ptr[6] = { false };
@@ -421,49 +422,49 @@ static void parse_call(struct gluten_ctx *g, struct ns_spec *ns, long nr,
if (count != json_object_get_count(obj))
die(" Stray elements in call");
- emit_call(g, ns, nr, arg_max_pos + 1, is_ptr, offset, ret_offset);
+ emit_call(g, cdesc, nr, arg_max_pos + 1, is_ptr, offset, ret_offset);
}
-static void parse_context(struct ns_spec *ns, JSON_Object *obj)
+static void parse_context(struct context_desc *cdesc, JSON_Object *obj)
{
unsigned i, n = 0;
/* Key order gives setns() order */
for (i = 0; i < json_object_get_count(obj); i++) {
const char *name = json_object_get_name(obj, i);
- const char **ns_name = ns_type_name, *str;
- enum ns_type type;
+ const char **ctx_name, *str;
+ enum context_type type;
double num;
- for (ns_name = ns_type_name; *ns_name; ns_name++) {
- if (!strcmp(name, *ns_name))
+ for (ctx_name = context_type_name; *ctx_name; ctx_name++) {
+ if (!strcmp(name, *ctx_name))
break;
}
- if (!*ns_name)
- die("invalid namespace type \"%s\"", name);
+ if (!*ctx_name)
+ die("invalid context type \"%s\"", name);
- type = ns_name - ns_type_name;
- ns[n].ns = type;
+ type = ctx_name - context_type_name;
+ cdesc[n].type = type;
if ((str = json_object_get_string(obj, name))) {
if (!strcmp(str, "init"))
continue;
- debug(" '%s' namespace: %s", name, str);
+ debug(" '%s' context: %s", name, str);
if (!strcmp(str, "caller")) {
- ns[n].spec = NS_SPEC_CALLER;
+ cdesc[n].spec = CONTEXT_SPEC_CALLER;
} else {
- ns[n].spec = NS_SPEC_PATH;
- strncpy(ns[n].target.path, str, PATH_MAX);
+ cdesc[n].spec = CONTEXT_SPEC_PATH;
+ strncpy(cdesc[n].target.path, str, PATH_MAX);
}
} else if ((num = json_object_get_number(obj, name))) {
- debug(" '%s' namespace: %lli", name, num);
+ debug(" '%s' context: %lli", name, num);
- ns[n].spec = NS_SPEC_PID;
- ns[n].target.pid = num;
+ cdesc[n].spec = CONTEXT_SPEC_PID;
+ cdesc[n].target.pid = num;
} else {
- die("invalid namespace specification");
+ die("invalid context specification");
}
n++;
}
@@ -481,7 +482,7 @@ void handle_calls(struct gluten_ctx *g, JSON_Value *value)
count = 1;
for (i = 0; i < count; i++) {
- struct ns_spec ns[NS_TYPE_MAX + 1] = { 0 };
+ struct context_desc cdesc[CONTEXT_TYPE_MAX + 1] = { 0 };
JSON_Object *obj, *args, *ctx;
struct call **set, *call;
const char *name, *ret;
@@ -509,7 +510,7 @@ void handle_calls(struct gluten_ctx *g, JSON_Value *value)
ret = json_object_get_string(obj, "ret");
ctx = json_object_get_object(obj, "context");
- parse_context(ns, ctx);
+ parse_context(cdesc, ctx);
/* TODO: Factor this out into a function in calls.c */
for (set = call_sets, call = set[0]; *set; ) {
@@ -522,7 +523,7 @@ void handle_calls(struct gluten_ctx *g, JSON_Value *value)
if (!strcmp(name, call->name)) {
debug(" Found description for %s",
name);
- parse_call(g, ns, call->number,
+ parse_call(g, cdesc, call->number,
args, ret, call->args);
break;
}
diff --git a/cooker/emit.c b/cooker/emit.c
index d4ca97b..41b64a6 100644
--- a/cooker/emit.c
+++ b/cooker/emit.c
@@ -81,31 +81,31 @@ void emit_fd(struct gluten_ctx *g, struct fd_desc *desc)
/**
* emit_call() - Emit OP_CALL instruction: execute a system call
* @g: gluten context
- * @ns: NS_SPEC_NONE-terminated array of namespaces references
+ * @context: CONTEXT_SPEC_NONE-terminated array of context references
* @nr: System call number
* @count: Argument count
* @is_ptr: Array indicating whether arguments need to be dereferenced
* @args: Offsets of arguments
* @ret_offset: Offset where return value must be saved, can be OFFSET_NULL
*/
-void emit_call(struct gluten_ctx *g, struct ns_spec *ns, long nr,
+void emit_call(struct gluten_ctx *g, struct context_desc *cdesc, long nr,
unsigned count, bool is_ptr[6],
struct gluten_offset offset[6], struct gluten_offset ret_offset)
{
struct op *op = (struct op *)gluten_ptr(&g->g, g->ip);
struct gluten_offset o1 = { 0 }, o2 = { 0 };
struct op_call *call = &op->op.call;
+ struct context_desc *c = cdesc;
struct syscall_desc *desc;
- unsigned ns_count, i;
- struct ns_spec *ctx;
+ unsigned i;
op->type = OP_CALL;
- for (ns_count = 0; ns[ns_count].spec != NS_SPEC_NONE; ns_count++);
- if (ns_count) {
- o1 = gluten_ro_alloc(g, sizeof(struct ns_spec) * ns_count);
- ctx = (struct ns_spec *)gluten_ptr(&g->g, o1);
- memcpy(ctx, ns, sizeof(struct ns_spec) * ns_count);
+ for (i = 0; c[i].spec != CONTEXT_SPEC_NONE; i++);
+ if (i) {
+ o1 = gluten_ro_alloc(g, sizeof(struct context_desc) * i);
+ c = (struct context_desc *)gluten_ptr(&g->g, o1);
+ memcpy(c, cdesc, sizeof(struct context_desc) * i);
}
o2 = gluten_ro_alloc(g, sizeof(struct syscall_desc) +
diff --git a/cooker/emit.h b/cooker/emit.h
index 978c9e0..b9d326f 100644
--- a/cooker/emit.h
+++ b/cooker/emit.h
@@ -8,7 +8,7 @@
void emit_nr(struct gluten_ctx *g, struct gluten_offset number);
void emit_fd(struct gluten_ctx *g, struct fd_desc *desc);
-void emit_call(struct gluten_ctx *g, struct ns_spec *ns, long nr,
+void emit_call(struct gluten_ctx *g, struct context_desc *cdesc, long nr,
unsigned count, bool is_ptr[6],
struct gluten_offset offset[6], struct gluten_offset ret_offset);
void emit_load(struct gluten_ctx *g, struct gluten_offset dst,
diff --git a/demo/mknod.hjson b/demo/mknod.hjson
index 9660e0d..01f3c07 100644
--- a/demo/mknod.hjson
+++ b/demo/mknod.hjson
@@ -26,10 +26,9 @@
"major": 1,
"minor": { "tag": { "get": "minor" } }
},
- "ret": "x"/*,
- "context": { "user": "init", "mnt": "caller" }*/
+ "context": { "cwd": "caller" }
},
- "return": { "tag": "x" }
+ "return": { "value": 0 }
}
]
diff --git a/operations.c b/operations.c
index b08d837..e1132d5 100644
--- a/operations.c
+++ b/operations.c
@@ -80,10 +80,11 @@ static int write_syscall_ret(struct gluten *g, struct syscall_desc *s,
}
static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g,
- struct syscall_desc *s, struct ns_spec *ctx,
+ struct syscall_desc *s, struct context_desc *cdesc,
struct arg_clone *c)
{
- unsigned int i, n = 0;
+ char (*dst)[PATH_MAX];
+ unsigned int i;
long arg;
c->err = 0;
@@ -109,32 +110,56 @@ static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g,
}
/* TODO: add proper check when there is no context */
- if (ctx == NULL)
+ if (cdesc == NULL) {
+ debug(" op_call: no context provided");
return 0;
+ }
+
+ for (dst = c->ns_path; cdesc->spec != CONTEXT_SPEC_NONE; cdesc++) {
+ enum context_spec_type spec = cdesc->spec;
+ enum context_type type = cdesc->type;
- for (; ctx->spec != NS_SPEC_NONE; ctx++) {
- enum ns_spec_type spec = ctx->spec;
- enum ns_type ns = ctx->ns;
+ debug(" op_call: adding context for %s, type: %s",
+ context_type_name[type], context_spec_type_name[spec]);
+
+ if (spec == CONTEXT_SPEC_NONE)
+ break;
switch (spec) {
- case NS_SPEC_NONE:
+ case CONTEXT_SPEC_CALLER:
+ if (type == CWD) {
+ snprintf(c->cwd, PATH_MAX, "/proc/%d/root",
+ req->pid);
+ } else {
+ snprintf(c->cwd, PATH_MAX, "/proc/%d/ns/%s",
+ req->pid, context_type_name[type]);
+ }
break;
- case NS_SPEC_CALLER:
- snprintf(c->ns_path[n++], PATH_MAX, "/proc/%d/ns/%s",
- req->pid, ns_type_name[ns]);
+ case CONTEXT_SPEC_PID:
+ if (type == CWD) {
+ snprintf(c->cwd, PATH_MAX, "/proc/%d/root",
+ cdesc->target.pid);
+ } else {
+ snprintf(*dst, PATH_MAX, "/proc/%d/ns/%s",
+ cdesc->target.pid,
+ context_type_name[type]);
+ }
break;
- case NS_SPEC_PID:
- snprintf(c->ns_path[n++], PATH_MAX, "/proc/%d/ns/%s",
- ctx->target.pid, ns_type_name[ns]);
+ case CONTEXT_SPEC_PATH:
+ if (type == CWD)
+ strncpy(c->cwd, cdesc->target.path, PATH_MAX);
+ else
+ strncpy(*dst, cdesc->target.path, PATH_MAX);
break;
- case NS_SPEC_PATH:
- strncpy(c->ns_path[n++], ctx->target.path,
- PATH_MAX);
+ default:
break;
}
+
+ if (type != CWD)
+ dst++;
}
- *c->ns_path[n] = 0;
+ **dst = 0;
return 0;
}
@@ -146,10 +171,10 @@ static int set_namespaces(struct arg_clone *c)
for (path = c->ns_path; **path; *path++) {
if ((fd = open(*path, O_CLOEXEC)) < 0)
- ;//ret_err(-1, "open for file %s", *path);
+ ret_err(-1, "open for file %s", *path);
if (setns(fd, 0) != 0)
- ;//ret_err(-1, "setns");
+ ret_err(-1, "setns");
}
return 0;
}
@@ -158,13 +183,19 @@ static int execute_syscall(void *args)
{
struct arg_clone *c = (struct arg_clone *)args;
- if (set_namespaces(c) < 0) {
+ if (*c->cwd && chdir(c->cwd) < 0)
exit(EXIT_FAILURE);
- }
+
+ if (set_namespaces(c) < 0)
+ exit(EXIT_FAILURE);
+
+ errno = 0;
/* execute syscall */
c->ret = syscall(c->nr, c->args[0], c->args[1], c->args[2], c->args[3],
c->args[4], c->args[5]);
c->err = errno;
+ debug(" execute syscall: ret=%ld errno=%d%s%s", c->ret, c->err,
+ *c->cwd ? " cwd=" : "", *c->cwd ? c->cwd : "");
if (c->ret < 0) {
perror(" syscall");
exit(EXIT_FAILURE);
@@ -191,7 +222,7 @@ int op_call(const struct seccomp_notif *req, int notifier, struct gluten *g,
struct seccomp_notif_resp resp;
struct arg_clone c = { 0 };
struct syscall_desc *s;
- struct ns_spec *ctx;
+ struct context_desc *cdesc;
resp.id = req->id;
resp.val = 0;
@@ -199,9 +230,9 @@ int op_call(const struct seccomp_notif *req, int notifier, struct gluten *g,
resp.error = 0;
s = (struct syscall_desc *)gluten_ptr(NULL, g, op->desc);
- ctx = (struct ns_spec *)gluten_ptr(NULL, g, s->context);
+ cdesc = (struct context_desc *)gluten_ptr(NULL, g, s->context);
- if (prepare_arg_clone(req, g, s, ctx, &c) == -1)
+ if (prepare_arg_clone(req, g, s, cdesc, &c) == -1)
return -1;
debug(" op_call: execute syscall nr=%ld", c.nr);
diff --git a/operations.h b/operations.h
index ec06a15..9f2e2d6 100644
--- a/operations.h
+++ b/operations.h
@@ -36,6 +36,7 @@ struct arg_clone {
long nr;
const void *args[6];
char ns_path[NS_TYPE_MAX + 1][PATH_MAX];
+ char cwd[PATH_MAX];
long ret;
int err;
};
diff --git a/seitan.c b/seitan.c
index 4005a9b..a18e3ea 100644
--- a/seitan.c
+++ b/seitan.c
@@ -184,7 +184,7 @@ int main(int argc, char **argv)
char req_b[BUFSIZ];
struct epoll_event ev, events[EPOLL_EVENTS];
struct seccomp_notif *req = (struct seccomp_notif *)req_b;
- struct arguments arguments;
+ struct arguments arguments = { 0 };
char path[PATH_MAX + 1];
int fd = -1, epollfd;
int pidfd, notifier;