diff options
-rw-r--r-- | common/gluten.h | 12 | ||||
-rw-r--r-- | common/util.c | 3 | ||||
-rw-r--r-- | cooker/call.c | 129 | ||||
-rw-r--r-- | cooker/gluten.c | 4 | ||||
-rw-r--r-- | cooker/match.c | 6 | ||||
-rw-r--r-- | demo/mknod.hjson | 37 | ||||
-rw-r--r-- | operations.c | 66 |
7 files changed, 179 insertions, 78 deletions
diff --git a/common/gluten.h b/common/gluten.h index fe62827..6414e20 100644 --- a/common/gluten.h +++ b/common/gluten.h @@ -42,7 +42,8 @@ enum gluten_offset_type { OFFSET_DATA = 2, OFFSET_SECCOMP_DATA = 3, OFFSET_INSTRUCTION = 4, - OFFSET_TYPE_MAX = OFFSET_INSTRUCTION, + OFFSET_METADATA = 5, + OFFSET_TYPE_MAX = OFFSET_METADATA, }; #define NULL_OFFSET ((struct gluten_offset){ .type = OFFSET_NULL }) @@ -143,6 +144,13 @@ struct context_desc { BUILD_BUG_ON(BITS_PER_NUM(CONTEXT_TYPE_MAX) + \ BITS_PER_NUM(CONTEXT_SPEC_TYPE_MAX) > 8) +enum metadata_type { + UID_TARGET = 0, + GID_TARGET = 1, + METADATA_MAX = GID_TARGET, +}; +extern const char *metadata_type_str[METADATA_MAX + 1]; + struct syscall_desc { uint32_t nr :9; uint32_t arg_count :3; @@ -289,6 +297,8 @@ struct gluten { GLUTEN_CONST char ro_data[RO_DATA_SIZE]; + GLUTEN_CONST enum metadata_type metadata; + char data[DATA_SIZE]; } __attribute__((packed)); diff --git a/common/util.c b/common/util.c index 8e15837..8815ecb 100644 --- a/common/util.c +++ b/common/util.c @@ -35,7 +35,8 @@ 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", "metadata", }; const char *context_type_name[CONTEXT_TYPE_MAX + 1] = { diff --git a/cooker/call.c b/cooker/call.c index 6dbfd29..173bdb4 100644 --- a/cooker/call.c +++ b/cooker/call.c @@ -16,6 +16,70 @@ #include "parse.h" #include "util.h" +/* TODO: refactor and simplify this horrible function */ +static union value parse_metadata(struct gluten_ctx *g, struct field *f, + struct gluten_offset **base_offset, + struct gluten_offset offset, + JSON_Object *metadata, bool dry_run, bool add) +{ + const char *tag; + size_t count = 0; + union value v = { .v_num = 0 }; + + if ((tag = json_object_get_string(metadata, "caller"))) { + debug(" args reference value at runtime '%s' with metadata %s", tag, tag); + (*base_offset)->type = OFFSET_METADATA; + if (strcmp(tag, "uid") == 0) { + (*base_offset)->offset = UID_TARGET; + } else if (strcmp(tag, "gid") == 0) { + (*base_offset)->offset = GID_TARGET; + } else { + die(" unrecognized metadata tag: %s", tag); + } + return v; + } + + if ((tag = json_object_get_string(metadata, "set"))) { + count++; + debug(" setting tag reference (post) '%s'", tag); + + if (!dry_run) + gluten_add_tag_post(g, tag, offset); + + if (f->flags & RBUF) + return v; + } + + if ((tag = json_object_get_string(metadata, "get"))) { + struct gluten_offset tag_offset; + + count++; + debug(" getting tag reference '%s'", tag); + + /* TODO: Check type */ + tag_offset = gluten_get_tag(g, tag); + if (tag_offset.type == OFFSET_NULL) + die(" tag not found"); + + if ((*base_offset)->type == OFFSET_NULL) { + **base_offset = tag_offset; + } else if (f->flags & MASK || add) { + emit_bitwise(g, f->type, BITWISE_OR, offset, offset, + tag_offset); + } else { + emit_copy_field(g, f, offset, tag_offset); + } + } + + if (json_object_get_count(metadata) > count) + die("stray object in tag reference"); + + if (!count) + die("invalid tag specification"); + + return v; +} + /** struct syscall_desc { @@ -78,7 +142,7 @@ static union value parse_field(struct gluten_ctx *g, struct arg *args, { struct gluten_offset offset = *base_offset; union value v = { .v_num = 0 }; - JSON_Object *tmp1, *tmp2; + JSON_Object *tmp1; struct field *f_inner; JSON_Value *sel; @@ -89,58 +153,11 @@ static union value parse_field(struct gluten_ctx *g, struct arg *args, offset.offset += f->offset; if (json_value_get_type(jvalue) == JSONObject && - (tmp1 = json_value_get_object(jvalue)) && - (tmp2 = json_object_get_object(tmp1, "tag"))) { - const char *tag_set, *tag_get; - size_t count = 0; - - if ((tag_set = json_object_get_string(tmp2, "set"))) { - count++; - debug(" setting tag reference (post) '%s'", tag_set); - - if (!dry_run) - gluten_add_tag_post(g, tag_set, offset); - - if (f->flags & RBUF) - return v; - } - - if ((tag_get = json_object_get_string(tmp2, "get"))) { - struct gluten_offset tag_offset; - - count++; - debug(" getting tag reference '%s'", tag_get); - - /* TODO: Check type */ - tag_offset = gluten_get_tag(g, tag_get); - if (tag_offset.type == OFFSET_NULL) - die(" tag not found"); - - if (base_offset->type == OFFSET_NULL) { - *base_offset = tag_offset; - } else if (f->flags & MASK || add) { - emit_bitwise(g, f->type, BITWISE_OR, offset, - offset, tag_offset); - } else { - emit_copy_field(g, f, offset, tag_offset); - } - } - - if (json_object_get_count(tmp2) > count) - die("stray object in tag reference"); - - if (!count) - die("invalid tag specification"); - - jvalue = json_object_get_value(tmp1, "value"); - - if (tag_get) { - if (jvalue) - die("stray value with \"get\" tag"); - - return v; - } - } + (tmp1 = json_value_get_object(jvalue))) + v = parse_metadata(g, f, &base_offset, offset, tmp1, dry_run, + add); + if (v.v_num == 0) + return v; if (!jvalue && !(f->flags & SIZE)) return v; @@ -205,7 +222,8 @@ static union value parse_field(struct gluten_ctx *g, struct arg *args, if (dry_run) break; - v.v_str = json_value_get_string(jvalue); + if ((v.v_str = json_value_get_string(jvalue)) == NULL) + die(" failed parsing string for %s", json_serialize_to_string(jvalue)); if (strlen(v.v_str) + 1 > f->size) die(" string %s too long for field", v.v_str); @@ -247,8 +265,7 @@ bool arg_needs_temp(struct field *f, int pos, JSON_Value *jvalue, return false; if (json_value_get_type(jvalue) == JSONObject && - (tmp = json_value_get_object(jvalue)) && - (tmp = json_object_get_object(tmp, "tag"))) { + (tmp = json_value_get_object(jvalue))) { if (json_object_get_string(tmp, "set")) return true; diff --git a/cooker/gluten.c b/cooker/gluten.c index 4d3aea5..708c005 100644 --- a/cooker/gluten.c +++ b/cooker/gluten.c @@ -119,8 +119,10 @@ struct gluten_offset gluten_get_tag(struct gluten_ctx *g, const char *name) int i; for (i = 0; i < TAGS_MAX && g->tags[i].name; i++) { - if (!strcmp(g->tags[i].name, name)) + if (!strcmp(g->tags[i].name, name)) { + debug("XXX got tag for name:%s offset:%d", name, g->tags[i].offset); return g->tags[i].offset; + } } die(" tag '%s' not found", name); diff --git a/cooker/match.c b/cooker/match.c index eeedead..36ac9df 100644 --- a/cooker/match.c +++ b/cooker/match.c @@ -119,7 +119,7 @@ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx if (json_value_get_type(jvalue) == JSONObject && (tmp = json_value_get_object(jvalue)) && - (tag_name = json_object_get_string(tmp, "tag"))) { + (tag_name = json_object_get_string(tmp, "set"))) { debug(" setting tag reference '%s'", tag_name); gluten_add_tag(g, tag_name, offset); @@ -258,7 +258,9 @@ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx parse_field(g, offset, cmp, jump, index, f, jvalue); break; case STRING: - v.v_str = json_value_get_string(jvalue); + if ((v.v_str = json_value_get_string(jvalue)) == NULL) + die(" failed parsing field for value:%s", + json_serialize_to_string_pretty(jvalue)); if (strlen(v.v_str) + 1 > f->size) die(" string %s too long for field", v.v_str); diff --git a/demo/mknod.hjson b/demo/mknod.hjson index 1936eb8..98715ec 100644 --- a/demo/mknod.hjson +++ b/demo/mknod.hjson @@ -2,32 +2,41 @@ { "match": [ { "mknodat": - { "path": { "tag": "path" }, - "mode": { "tag": "mode" }, - "type": { "tag": "type" }, + { "path": { "set": "path" }, + "mode": { "set": "mode" }, + "type": { "set": "type" }, "major": 1, - "minor": { "value": { "in": [ 3, 5, 7, 8, 9 ] }, "tag": "minor" } + "minor": { "value": { "in": [ 3, 5, 7, 8, 9 ] }, "set": "minor" } } }, { "mknod": - { "path": { "tag": "path" }, - "mode": { "tag": "mode" }, - "type": { "tag": "type" }, + { "path": { "set": "path" }, + "mode": { "set": "mode" }, + "type": { "set": "type" }, "major": 1, - "minor": { "value": { "in": [ 3, 5, 7, 8, 9 ] }, "tag": "minor" } + "minor": { "value": { "in": [ 3, 5, 7, 8, 9 ] }, "set": "minor" } } } ], - "call": + "call": [ { "mknod": - { "path": { "tag": { "get": "path" } }, - "mode": { "tag": { "get": "mode" } }, - "type": { "tag": { "get": "type" } }, + { "path": { "get": "path" }, + "mode": { "get": "mode" }, + "type": { "get": "type" }, "major": 1, - "minor": { "tag": { "get": "minor" } } + "minor": { "get": "minor" } }, - "context": { "mnt": "caller", "uid": "caller", "gid": "caller" } + "context": { "mnt": "caller" } }, + { + "lchown": { + "path": { "get": "path" }, + "uid" : { "caller": "uid" }, + "gid" : { "caller": "gid" } + }, + "context": { "mnt": "caller" } + } + ], "return": { "value": 0, "error": 0 } } ] diff --git a/operations.c b/operations.c index b5e536a..306d1ab 100644 --- a/operations.c +++ b/operations.c @@ -25,6 +25,7 @@ #include <linux/filter.h> #include <linux/audit.h> #include <errno.h> +#include <ctype.h> #include "common/gluten.h" #include "common/util.h" @@ -81,6 +82,60 @@ static int write_syscall_ret(struct gluten *g, struct syscall_desc *s, return 0; } +static void parse_number_string(char *line, char *v, size_t len) +{ + bool first = true; + unsigned int i, k = 0; + + for (i = 0; i < len; i++) { + /* Check until it encounters the first number */ + if(!isdigit(line[i]) && !first) + break; + if (!isdigit(line[i])) + continue; + v[k] = line[i]; + k++; + first = false; + } +} + +static int proc_state(char *field, pid_t pid) +{ + char path[PATH_MAX]; + char v[PATH_MAX] = { '0' }; + char *line = NULL; + size_t len = PATH_MAX; + ssize_t read; + FILE *fp; + + snprintf(path, PATH_MAX, "/proc/%d/status", pid); + if ((fp = fopen(path, "r")) == NULL) + ret_err(-1, "failed reading status for %d", pid); + + while ((read = getline(&line, &len, fp)) != -1) { + if (strstr(line, field) != NULL) + parse_number_string(line, v, len); + } + + fclose(fp); + return atoi(v); +} + +static int get_metadata_value(uint32_t offset, pid_t pid) +{ + switch (offset) { + case UID_TARGET: + return proc_state("Uid", pid); + break; + case GID_TARGET: + return proc_state("Gid", pid); + break; + default: + err("unrecognize metadata type"); + } + return 0; +} + /* TODO: Move all "context" stuff to separate file */ static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g, struct syscall_desc *s, struct context_desc *cdesc, @@ -100,7 +155,13 @@ static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g, */ if (GET_BIT(s->arg_deref, i) == 1) { c->args[i] = gluten_ptr(NULL, g, s->args[i]); - debug(" read pointer arg%d at offset %d", i, s->args[i].offset); + debug(" read pointer arg%d at offset %d", i, + s->args[i].offset); + } else if (s->args[i].type == OFFSET_METADATA) { + c->args[i] = (void *)(long)get_metadata_value( + s->args[i].offset, req->pid); + debug(" read metadata value %s: %d", + metadata_type_str[s->args[i].offset], (int *)c->args[i]); } else { if (gluten_read(NULL, g, &arg, s->args[i], sizeof(arg)) == -1) @@ -236,7 +297,7 @@ static int execute_syscall(void *args) 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 %ld: ret=%ld errno=%d%s%s", c->nr, c->ret, + debug(" execute syscall %s: ret=%ld errno=%d%s%s", syscall_name_str[c->nr], c->ret, c->err, *c->cwd ? " cwd=" : "", *c->cwd ? c->cwd : ""); if (c->ret < 0) { perror(" syscall"); @@ -277,7 +338,6 @@ int op_call(const struct seccomp_notif *req, int notifier, struct gluten *g, if (prepare_arg_clone(req, g, s, cdesc, &c) == -1) return -1; - debug(" op_call: execute syscall nr=%ld", c.nr); if (do_call(&c) == -1) { resp.error = -1; if (send_target(&resp, notifier) == -1) |