aboutgitcodelistschat:MatrixIRC
diff options
context:
space:
mode:
-rw-r--r--common/gluten.h12
-rw-r--r--common/util.c3
-rw-r--r--cooker/call.c129
-rw-r--r--cooker/gluten.c4
-rw-r--r--cooker/match.c6
-rw-r--r--demo/mknod.hjson37
-rw-r--r--operations.c66
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)