aboutgitcodelistschat:MatrixIRC
diff options
context:
space:
mode:
-rw-r--r--common/gluten.h137
-rw-r--r--common/util.c6
-rw-r--r--cooker/call.c156
-rw-r--r--cooker/calls/net.c1
-rw-r--r--cooker/emit.c55
-rw-r--r--cooker/emit.h3
-rw-r--r--cooker/example.hjson7
-rw-r--r--cooker/match.c35
-rw-r--r--operations.c110
-rw-r--r--operations.h2
10 files changed, 314 insertions, 198 deletions
diff --git a/common/gluten.h b/common/gluten.h
index 5409234..198e646 100644
--- a/common/gluten.h
+++ b/common/gluten.h
@@ -11,6 +11,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
+#include <linux/limits.h>
#include <linux/seccomp.h>
#include <stdio.h>
@@ -19,12 +20,12 @@
extern struct seccomp_data anonymous_seccomp_data;
-#define HEADER_SIZE 4096
-#define INST_SIZE 4096
-#define RO_DATA_SIZE 4096
-#define DATA_SIZE 4096
+#define HEADER_SIZE 65536
+#define INST_SIZE 65536
+#define RO_DATA_SIZE 65536
+#define DATA_SIZE 65536
-#define INST_MAX 16
+#define INST_MAX 256
#define OFFSET_MAX \
MAX(MAX(MAX(DATA_SIZE, RO_DATA_SIZE), INST_MAX), \
ARRAY_SIZE(anonymous_seccomp_data.args))
@@ -57,44 +58,6 @@ struct gluten_offset {
BUILD_BUG_ON(BITS_PER_NUM(OFFSET_TYPE_MAX) + BITS_PER_NUM(OFFSET_MAX) > 32)
-enum ns_spec_type {
- NS_NONE,
- /* Read the pid from seccomp_data */
- NS_SPEC_TARGET,
- /* Read the pid from gluten */
- NS_SPEC_PID,
- NS_SPEC_PATH,
-};
-
-struct ns_spec {
- enum ns_spec_type type;
- /* Pid or path based on the type */
- struct gluten_offset id;
- size_t size;
-};
-
-/*
- * 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 op_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 op_context {
- struct ns_spec ns[sizeof(enum ns_type)];
-};
-
enum op_type {
OP_END = 0,
OP_NR,
@@ -110,22 +73,90 @@ enum op_type {
OP_RESOLVEDFD,
};
-struct op_nr {
- struct gluten_offset nr;
- struct gluten_offset no_match;
+/**
+ * enum ns_spec_type - Type of reference to target namespace
+ */
+enum ns_spec_type {
+ NS_SPEC_NONE = 0,
+
+ /* PID from seccomp_data */
+ NS_SPEC_CALLER = 1,
+
+ /* PID/path from gluten, resolved in seitan */
+ NS_SPEC_PID = 2,
+ NS_SPEC_PATH = 3,
+
+ NS_SPEC_TYPE_MAX = NS_SPEC_PATH,
+};
+
+/**
+ * enum ns_type - Namespace types: 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,
+};
+
+extern const char *ns_type_name[NS_TYPE_MAX + 1];
+
+/**
+ * struct ns_spec - Identification of one type of target namespace
+ * @ns: Namespace type
+ * @spec: Reference type
+ * @target.pid: PID in procfs reference
+ * @target.path: Filesystem-bound (nsfs) reference
+ */
+struct ns_spec {
+#ifdef __GNUC__
+ enum ns_type ns :BITS_PER_NUM(NS_TYPE_MAX);
+ enum ns_spec_type spec :BITS_PER_NUM(NS_SPEC_TYPE_MAX);
+#else
+ uint8_t ns :BITS_PER_NUM(NS_TYPE_MAX);
+ uint8_t spec :BITS_PER_NUM(NS_SPEC_TYPE_MAX);
+#endif
+ union {
+ pid_t pid;
+ char path[PATH_MAX];
+ } 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[];
};
struct syscall_desc {
- unsigned nr : 9;
- unsigned arg_count : 3;
- unsigned has_ret : 1;
- unsigned arg_deref : 6;
- struct gluten_offset data[];
+ uint32_t nr :9;
+ uint32_t arg_count :3;
+ uint32_t has_ret :1;
+ uint32_t arg_deref :6;
+
+ struct gluten_offset context; /* struct ns_spec [] */
+ struct gluten_offset args[];
};
struct op_call {
- struct gluten_offset syscall;
- struct gluten_offset context;
+ struct gluten_offset desc;
+};
+
+
+struct op_nr {
+ struct gluten_offset nr;
+ struct gluten_offset no_match;
};
struct op_block {
diff --git a/common/util.c b/common/util.c
index 19d5c12..f9423a6 100644
--- a/common/util.c
+++ b/common/util.c
@@ -31,5 +31,9 @@ logfn(debug)
const char *gluten_offset_name[OFFSET_TYPE_MAX + 1] = {
"NULL",
- "read-only data", "temporary data", "seccomp data", "instruction area"
+ "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",
};
diff --git a/cooker/call.c b/cooker/call.c
index e1abb39..db2d6b8 100644
--- a/cooker/call.c
+++ b/cooker/call.c
@@ -71,7 +71,7 @@ Examples of arguments:
parse_arg() passes data offset
*/
-static union value parse_field(struct gluten_ctx *g,
+static union value parse_field(struct gluten_ctx *g, struct arg *args,
struct gluten_offset *base_offset,
int index, struct field *f, JSON_Value *jvalue,
bool dry_run, bool add)
@@ -83,7 +83,7 @@ static union value parse_field(struct gluten_ctx *g,
JSON_Value *sel;
if (f->name)
- debug(" parsing field name %s", f->name);
+ debug(" parsing field name %s", f->name);
if (offset.type != OFFSET_NULL)
offset.offset += f->offset;
@@ -96,7 +96,7 @@ static union value parse_field(struct gluten_ctx *g,
if ((tag_set = json_object_get_string(tmp2, "set"))) {
count++;
- debug(" setting tag reference (post) '%s'", tag_set);
+ debug(" setting tag reference (post) '%s'", tag_set);
if (!dry_run)
gluten_add_tag_post(g, tag_set, offset);
@@ -106,7 +106,7 @@ static union value parse_field(struct gluten_ctx *g,
struct gluten_offset tag_offset;
count++;
- debug(" getting tag reference '%s'", tag_get);
+ debug(" getting tag reference '%s'", tag_get);
/* TODO: Check type */
tag_offset = gluten_get_tag(g, tag_get);
@@ -135,23 +135,37 @@ static union value parse_field(struct gluten_ctx *g,
}
}
- if (!jvalue)
+ if (!jvalue && !(f->flags & SIZE))
return v;
switch (f->type) {
case INT:
case LONG:
case U32:
- if (f->flags == FLAGS) {
- /* fetch/combine expr algebra loop */
- ;
- }
- if (f->flags == MASK) {
- /* calculate mask first */
- ;
+ if (f->flags == SIZE && !dry_run) {
+ unsigned i;
+
+ for (i = 0; args[i].f.type; i++) {
+ if (args[i].pos == f->desc.d_arg_size)
+ break;
+ }
+ if (!args[i].f.type)
+ die("no argument found for SIZE field");
+
+ v.v_num = args[i].f.size;
+ } else {
+ if (f->flags == FLAGS) {
+ /* fetch/combine expr algebra loop */
+ ;
+ }
+ if (f->flags == MASK) {
+ /* calculate mask first */
+ ;
+ }
+
+ v.v_num = value_get_num(f->desc.d_num, jvalue);
}
- v.v_num = value_get_num(f->desc.d_num, jvalue);
if (dry_run)
break;
@@ -173,11 +187,14 @@ static union value parse_field(struct gluten_ctx *g,
sel = jvalue;
}
- v = parse_field(g, &offset, index, f_inner, sel, false, false);
+ v = parse_field(g, args, &offset, index, f_inner, sel,
+ false, false);
f = select_field(g, index, f->desc.d_select, v);
- if (f)
- parse_field(g, &offset, index, f, jvalue, false, add);
+ if (f) {
+ parse_field(g, args, &offset, index, f, jvalue,
+ false, add);
+ }
break;
case STRING:
v.v_str = json_value_get_string(jvalue);
@@ -198,8 +215,8 @@ static union value parse_field(struct gluten_ctx *g,
if (!f_value)
continue;
- parse_field(g, &offset, index, f_inner, f_value, false,
- add);
+ parse_field(g, args, &offset, index, f_inner, f_value,
+ false, add);
}
break;
default:
@@ -256,7 +273,8 @@ bool arg_needs_temp(struct field *f, int pos, JSON_Value *jvalue,
sel = jvalue;
}
- v = parse_field(NULL, &unused, pos, f_inner, sel, true, false);
+ v = parse_field(NULL, NULL, &unused, pos, f_inner, sel,
+ true, false);
f = select_field(NULL, pos, f->desc.d_select, v);
if (f)
@@ -286,16 +304,18 @@ bool arg_needs_temp(struct field *f, int pos, JSON_Value *jvalue,
return false;
}
-static struct gluten_offset parse_arg(struct gluten_ctx *g, struct arg *a,
+static struct gluten_offset parse_arg(struct gluten_ctx *g, struct arg *args,
+ struct arg *a,
struct gluten_offset offset,
JSON_Value *jvalue)
{
bool top_level_tag = false;
- debug(" Parsing call argument %s", a->f.name);
+ debug(" Parsing call argument %s", a->f.name);
if (offset.type != OFFSET_NULL) {
- parse_field(g, &offset, a->pos, &a->f, jvalue, false, true);
+ parse_field(g, args, &offset, a->pos, &a->f, jvalue,
+ false, true);
return offset;
}
@@ -304,15 +324,16 @@ static struct gluten_offset parse_arg(struct gluten_ctx *g, struct arg *a,
else if (a->f.size && !top_level_tag)
offset = gluten_ro_alloc(g, a->f.size);
- parse_field(g, &offset, a->pos, &a->f, jvalue, false, false);
+ parse_field(g, args, &offset, a->pos, &a->f, jvalue, false, false);
return offset;
}
-static void parse_call(struct gluten_ctx *g, JSON_Object *obj, const char *ret,
- struct arg *args)
+static void parse_call(struct gluten_ctx *g, struct ns_spec *ns, 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 };
/* Minimum requirements for argument specification:
* - if argument can be FDPATH, exactly one value for that position
* - if argument is a size field, value is optional
@@ -322,6 +343,7 @@ static void parse_call(struct gluten_ctx *g, JSON_Object *obj, const char *ret,
bool needs_fd;
bool has_fd;
} arg_check[6] = { 0 };
+ int arg_max_pos = -1;
unsigned count = 0;
struct arg *a;
@@ -335,6 +357,12 @@ static void parse_call(struct gluten_ctx *g, JSON_Object *obj, const char *ret,
if (a->f.type == FDPATH)
arg_check[a->pos].needs_fd = true;
+
+ if (a->f.size)
+ is_ptr[a->pos] = true;
+
+ if (a->pos > arg_max_pos)
+ arg_max_pos = a->pos;
}
/* TODO: Factor this out into a function in... parse.c? */
@@ -351,14 +379,14 @@ static void parse_call(struct gluten_ctx *g, JSON_Object *obj, const char *ret,
else if (arg_check[a->pos].needs_fd)
arg_check[a->pos].has_fd = true;
- offset[a->pos] = parse_arg(g, a, offset[a->pos],
+ offset[a->pos] = parse_arg(g, args, a, offset[a->pos],
jvalue);
count++;
} else if (arg_check[a->pos].needs_fd &&
arg_check[a->pos].has_fd) {
;
} else if (a->f.flags & SIZE) {
- offset[a->pos] = parse_arg(g, a, offset[a->pos],
+ offset[a->pos] = parse_arg(g, args, a, offset[a->pos],
jvalue);
} else {
die(" No specification for argument %s", a->f.name);
@@ -370,16 +398,62 @@ static void parse_call(struct gluten_ctx *g, JSON_Object *obj, const char *ret,
gluten_add_tag_post(g, ret, ret_offset);
}
- /* emit_call() */
-
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);
+}
+
+static void parse_context(struct ns_spec *ns, 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;
+ double num;
+
+ for (ns_name = ns_type_name; *ns_name; ns_name++) {
+ if (!strcmp(name, *ns_name))
+ break;
+ }
+
+ if (!*ns_name)
+ die("invalid namespace type \"%s\"", name);
+
+ type = ns_name - ns_type_name;
+ ns[n].ns = type;
+ if ((str = json_object_get_string(obj, name))) {
+ if (!strcmp(str, "init"))
+ continue;
+
+ debug(" '%s' namespace: %s", name, str);
+
+ if (!strcmp(str, "caller")) {
+ ns[n].spec = NS_SPEC_CALLER;
+ } else {
+ ns[n].spec = NS_SPEC_PATH;
+ strncpy(ns[n].target.path, str, PATH_MAX);
+ }
+ } else if ((num = json_object_get_number(obj, name))) {
+ debug(" '%s' namespace: %lli", name, num);
+
+ ns[n].spec = NS_SPEC_PID;
+ ns[n].target.pid = num;
+ } else {
+ die("invalid namespace specification");
+ }
+ n++;
+ }
}
void handle_calls(struct gluten_ctx *g, JSON_Value *value)
{
JSON_Array *calls = json_value_get_array(value);
- unsigned i, count;
+ unsigned i, j, count;
+ int n;
if (calls)
count = json_array_get_count(calls);
@@ -387,8 +461,9 @@ 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 };
+ JSON_Object *obj, *args, *ctx;
struct call **set, *call;
- JSON_Object *obj, *args;
const char *name, *ret;
if (calls)
@@ -396,14 +471,26 @@ void handle_calls(struct gluten_ctx *g, JSON_Value *value)
else
obj = json_value_get_object(value);
- name = json_object_get_name(obj, 0);
- value = json_object_get_value_at(obj, 0);
+ for (j = 0, n = -1; j < json_object_get_count(obj); j++) {
+ if (strcmp(json_object_get_name(obj, j), "ret") &&
+ strcmp(json_object_get_name(obj, j), "context")) {
+ if (n >= 0)
+ die("stray object in \"call\"");
+ n = j;
+ }
+ }
+
+ name = json_object_get_name(obj, n);
+ value = json_object_get_value_at(obj, n);
args = json_object_get_object(obj, name);
debug(" Parsing call %s", name);
ret = json_object_get_string(obj, "ret");
+ ctx = json_object_get_object(obj, "context");
+ parse_context(ns, ctx);
+
/* TODO: Factor this out into a function in calls.c */
for (set = call_sets, call = set[0]; *set; ) {
if (!call->name) {
@@ -415,7 +502,8 @@ void handle_calls(struct gluten_ctx *g, JSON_Value *value)
if (!strcmp(name, call->name)) {
debug(" Found description for %s",
name);
- parse_call(g, args, ret, call->args);
+ parse_call(g, ns, call->number,
+ args, ret, call->args);
break;
}
call++;
diff --git a/cooker/calls/net.c b/cooker/calls/net.c
index f5e2728..52ebc1e 100644
--- a/cooker/calls/net.c
+++ b/cooker/calls/net.c
@@ -240,6 +240,7 @@ static struct arg connect_args[] = {
{ .d_arg_size = 1 },
},
},
+ { 0 }
};
struct call syscalls_net[] = {
diff --git a/cooker/emit.c b/cooker/emit.c
index 403f1ba..705df4b 100644
--- a/cooker/emit.c
+++ b/cooker/emit.c
@@ -53,6 +53,60 @@ void emit_nr(struct gluten_ctx *g, struct gluten_offset number)
}
/**
+ * emit_call() - Emit OP_CALL instruction: execute a system call
+ * @g: gluten context
+ * @ns: NS_SPEC_NONE-terminated array of namespaces 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,
+ 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 syscall_desc *desc;
+ unsigned ns_count, i;
+ struct ns_spec *ctx;
+
+ 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);
+ }
+
+ o2 = gluten_ro_alloc(g, sizeof(struct syscall_desc) +
+ sizeof(struct gluten_offset) *
+ (count + (ret_offset.type != OFFSET_NULL)));
+ desc = (struct syscall_desc *)gluten_ptr(&g->g, o2);
+ desc->nr = nr;
+ desc->arg_count = count;
+ desc->has_ret = ret_offset.type != OFFSET_NULL;
+ for (i = 0; i < count; i++)
+ desc->arg_deref |= BIT(i) * is_ptr[i];
+ desc->context = o1;
+ memcpy(desc->args, offset, sizeof(struct gluten_offset) * count);
+ desc->args[count + 1] = ret_offset;
+
+ debug(" %i: OP_CALL: %i, arguments:", g->ip.offset, nr);
+ for (i = 0; i < count; i++) {
+ debug("\t%i: %s %s%i", i, gluten_offset_name[offset[i].type],
+ is_ptr[i] ? "*" : "", offset[i].offset);
+ }
+
+ call->desc = o2;
+
+ if (++g->ip.offset > INST_MAX)
+ die("Too many instructions");
+}
+
+/**
* emit_load() - Emit OP_LOAD instruction: dereference and copy syscall argument
* @g: gluten context
* @dst: gluten destination to copy dereferenced data
@@ -152,6 +206,7 @@ void emit_return(struct gluten_ctx *g, struct gluten_offset v)
if (++g->ip.offset > INST_MAX)
die("Too many instructions");
}
+
/**
* emit_block() - Emit OP_BLOCK instruction: return error value
* @g: gluten context
diff --git a/cooker/emit.h b/cooker/emit.h
index ee0583f..d98789a 100644
--- a/cooker/emit.h
+++ b/cooker/emit.h
@@ -7,6 +7,9 @@
#define EMIT_H
void emit_nr(struct gluten_ctx *g, struct gluten_offset number);
+void emit_call(struct gluten_ctx *g, struct ns_spec *ns, 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,
int index, size_t len);
void emit_cmp(struct gluten_ctx *g, enum op_cmp_type cmp,
diff --git a/cooker/example.hjson b/cooker/example.hjson
index 4c656f7..7fec039 100644
--- a/cooker/example.hjson
+++ b/cooker/example.hjson
@@ -33,8 +33,11 @@
"match": [ /* Giuseppe's example */
{ "mknod": { "path": { "tag": "path" }, "mode": "c", "major": 1, "minor": { "in": [ 3, 5, 7, 8, 9 ], "tag": "minor" } } }
],
- "context": { "userns": "init", "mountns": "caller" },
- "call": { "mknod": { "path": { "tag": { "get": "path" } }, "mode": "c", "major": 1, "minor": { "tag": { "get": "minor" } } }, "ret": "x" },
+ "call": {
+ "mknod": { "path": { "tag": { "get": "path" } }, "mode": "c", "major": 1, "minor": { "tag": { "get": "minor" } } },
+ "ret": "x",
+ "context": { "user": "init", "mnt": "caller" }
+ },
"inject": { "what": "fd", "new": { "tag": "x" } },
"return": { "tag": "x" }
}
diff --git a/cooker/match.c b/cooker/match.c
index 5fe077f..7a4ca97 100644
--- a/cooker/match.c
+++ b/cooker/match.c
@@ -85,41 +85,12 @@ static union value parse_field(struct gluten_ctx *g,
JSON_Value *sel;
if (f->name)
- debug(" parsing field name %s", f->name);
-
-/*
- if (f->type == SELECT) {
- struct select *select = f->desc.d_select;
- struct field *s_field = select->field;
- JSON_Value *sel;
-
- if ((tmp = json_value_get_object(value))) {
- if (!(sel = json_object_get_value(tmp, s_field->name)))
- die(" no selector for '%s'", s_field->name);
- } else {
- sel = value;
- }
-
- value_get(s_field->desc, s_field->type, sel, &v);
- const_offset = emit_data(g, s_field->type, s_field->size, &v);
-
- data_offset = offset;
- data_offset.offset += s_field->offset;
-
- emit_cmp_field(g, CMP_NE, s_field, data_offset, const_offset,
- JUMP_NEXT_BLOCK);
-
- swap_field(g, select, v, index, &f);
-
- if (!f)
- return;
- }
-*/
+ debug(" parsing field name %s", f->name);
if (json_value_get_type(jvalue) == JSONObject &&
(tmp = json_value_get_object(jvalue)) &&
(tag_name = json_object_get_string(tmp, "tag"))) {
- debug(" setting tag reference '%s'", tag_name);
+ debug(" setting tag reference '%s'", tag_name);
gluten_add_tag(g, tag_name, offset);
jvalue = json_object_get_value(tmp, "value");
@@ -203,7 +174,7 @@ static void parse_arg(struct gluten_ctx *g, JSON_Value *jvalue, struct arg *a)
{
struct gluten_offset offset;
- debug(" Parsing match argument %s", a->f.name);
+ debug(" Parsing match argument %s", a->f.name);
offset = arg_load(g, a);
diff --git a/operations.c b/operations.c
index d28c4b8..2fb4053 100644
--- a/operations.c
+++ b/operations.c
@@ -52,38 +52,6 @@ static int send_inject_target(const struct seccomp_notif_addfd *resp,
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:
- err("unrecognized namespace index %d\n", i);
- }
-}
-
static struct gluten_offset *get_syscall_ret(struct syscall_desc *s)
{
if (s == NULL)
@@ -91,8 +59,8 @@ static struct gluten_offset *get_syscall_ret(struct syscall_desc *s)
if (s->has_ret == 0)
return NULL;
if (s->arg_count == 0)
- return s->data;
- return s->data + s->arg_count + 1;
+ return s->args;
+ return s->args + s->arg_count + 1;
}
static int write_syscall_ret(struct gluten *g, struct syscall_desc *s,
@@ -107,36 +75,26 @@ 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,
- const struct op_call *op, struct syscall_desc *s,
+ struct syscall_desc *s, struct ns_spec *ctx,
struct arg_clone *c)
{
- char ns_name[PATH_MAX / 2];
- const struct ns_spec *ns;
- struct op_context context;
- char p[PATH_MAX];
struct gluten_offset x;
- unsigned int i;
+ unsigned int i, n = 0;
long arg;
- pid_t pid;
-
- if (gluten_read(NULL, g, s, op->syscall, sizeof(struct syscall_desc)) == -1)
- return -1;
- if (gluten_read(NULL, g, &context, op->context, sizeof(context)) == -1)
- return -1;
c->err = 0;
c->ret = -1;
- c->nr = s-> nr;
+ c->nr = s->nr;
for (i = 0; i < s->arg_count; i++) {
- if (gluten_read(NULL, g, &arg, s->data[i], sizeof(arg)) == -1)
+ if (gluten_read(NULL, g, &arg, s->args[i], sizeof(arg)) == -1)
return -1;
/* If arg is a pointer then need to calculate the absolute
* address and the value of arg is the relative offset of the actual
* value.
*/
if (GET_BIT(s->arg_deref, i) == 1) {
- x.type = s->data[i].type;
+ x.type = s->args[i].type;
x.offset = arg;
if (gluten_read(NULL, g, &c->args[i], x,
sizeof(c->args[i])) == -1)
@@ -146,44 +104,41 @@ static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g,
}
}
- for (i = 0; i < NS_NUM; i++) {
- ns = &context.ns[i];
- proc_ns_name(i, ns_name);
- switch (ns->type) {
- case NS_NONE:
- strncpy(c->ns[i].path, "", PATH_MAX);
+ for (; ctx->spec != NS_SPEC_NONE; ctx++) {
+ enum ns_spec_type spec = ctx->spec;
+ enum ns_type ns = ctx->ns;
+
+ switch (spec) {
+ case NS_SPEC_NONE:
break;
- case NS_SPEC_TARGET:
- snprintf(c->ns[i].path, PATH_MAX, "/proc/%d/ns/%s",
- req->pid, ns_name);
+ case NS_SPEC_CALLER:
+ snprintf(c->ns_path[n++], PATH_MAX, "/proc/%d/ns/%s",
+ req->pid, ns_type_name[ns]);
break;
case NS_SPEC_PID:
- if (gluten_read(NULL, g, &pid, ns->id, ns->size) == -1)
- return -1;
- snprintf(c->ns[i].path, PATH_MAX, "/proc/%d/ns/%s", pid,
- ns_name);
+ snprintf(c->ns_path[n++], PATH_MAX, "/proc/%d/ns/%s",
+ ctx->target.pid, ns_type_name[ns]);
break;
case NS_SPEC_PATH:
- if (gluten_read(NULL, g, &p, ns->id, ns->size) == -1)
- return -1;
- snprintf(c->ns[i].path, PATH_MAX, "%s", p);
+ strncpy(c->ns_path[n++], ctx->target.path,
+ PATH_MAX);
break;
}
}
+ *c->ns_path[n] = 0;
+
return 0;
}
static int set_namespaces(struct arg_clone *c)
{
- unsigned int i;
+ char *path;
int fd;
- for (i = 0; i < sizeof(enum ns_type); i++) {
- if (strcmp(c->ns[i].path, "") == 0)
- continue;
- if ((fd = open(c->ns[i].path, O_CLOEXEC)) < 0)
- ret_err(-1, "open for file %s", c->ns[i].path);
+ for (path = c->ns_path[0]; *path; path++) {
+ if ((fd = open(path, O_CLOEXEC)) < 0)
+ ret_err(-1, "open for file %s", path);
if (setns(fd, 0) != 0)
ret_err(-1, "setns");
@@ -226,16 +181,21 @@ int op_call(const struct seccomp_notif *req, int notifier, struct gluten *g,
struct op_call *op)
{
struct seccomp_notif_resp resp;
- struct syscall_desc s;
- struct arg_clone c;
+ struct arg_clone c = { 0 };
+ struct syscall_desc *s;
+ struct ns_spec *ctx;
resp.id = req->id;
resp.val = 0;
resp.flags = 0;
resp.error = 0;
- if (prepare_arg_clone(req, g, op, &s, &c) == -1)
+ s = (struct syscall_desc *)gluten_ptr(NULL, g, op->desc);
+ ctx = (struct ns_spec *)gluten_ptr(NULL, g, s->context);
+
+ if (prepare_arg_clone(req, g, s, ctx, &c) == -1)
return -1;
+
debug(" op_call: execute syscall nr=%ld", c.nr);
if (do_call(&c) == -1) {
resp.error = -1;
@@ -249,7 +209,7 @@ int op_call(const struct seccomp_notif *req, int notifier, struct gluten *g,
return -1;
}
- return write_syscall_ret(g, &s, &c);
+ return write_syscall_ret(g, s, &c);
}
int op_load(const struct seccomp_notif *req, int notifier, struct gluten *g,
diff --git a/operations.h b/operations.h
index abdbe22..d74b4f9 100644
--- a/operations.h
+++ b/operations.h
@@ -34,7 +34,7 @@ struct ns_path {
struct arg_clone {
long nr;
void *args[6];
- struct ns_path ns[NS_NUM];
+ char ns_path[NS_TYPE_MAX + 1][PATH_MAX];
long ret;
int err;
};