diff options
author | Stefano Brivio <sbrivio@redhat.com> | 2023-06-02 06:21:21 +0200 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2023-06-02 06:21:21 +0200 |
commit | 80309fbd77cbafa3784fa7295afb56c446d59b93 (patch) | |
tree | 27cfa1ce846e1d2dc0aa2e55487db66120312aff | |
parent | 1644bbec6161ec971a2ba3c213ce285b995cac22 (diff) | |
download | seitan-80309fbd77cbafa3784fa7295afb56c446d59b93.tar seitan-80309fbd77cbafa3784fa7295afb56c446d59b93.tar.gz seitan-80309fbd77cbafa3784fa7295afb56c446d59b93.tar.bz2 seitan-80309fbd77cbafa3784fa7295afb56c446d59b93.tar.lz seitan-80309fbd77cbafa3784fa7295afb56c446d59b93.tar.xz seitan-80309fbd77cbafa3784fa7295afb56c446d59b93.tar.zst seitan-80309fbd77cbafa3784fa7295afb56c446d59b93.zip |
cooker, seitan: OP_CALL arguments and context
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r-- | common/gluten.h | 137 | ||||
-rw-r--r-- | common/util.c | 6 | ||||
-rw-r--r-- | cooker/call.c | 156 | ||||
-rw-r--r-- | cooker/calls/net.c | 1 | ||||
-rw-r--r-- | cooker/emit.c | 55 | ||||
-rw-r--r-- | cooker/emit.h | 3 | ||||
-rw-r--r-- | cooker/example.hjson | 7 | ||||
-rw-r--r-- | cooker/match.c | 35 | ||||
-rw-r--r-- | operations.c | 110 | ||||
-rw-r--r-- | operations.h | 2 |
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; }; |