aboutgitcodelistschat:MatrixIRC
diff options
context:
space:
mode:
authorAlice Frosi <afrosi@redhat.com>2023-08-29 11:50:00 +0200
committerAlice Frosi <afrosi@redhat.com>2023-08-30 10:48:59 +0200
commitd3917582873df723aa2a3ddbb6116950292e114c (patch)
tree778089680e396cf9bf86c201476952f0870e93de
parent0e8806838763655f5f35822e19a20cb21e8d4747 (diff)
downloadseitan-d3917582873df723aa2a3ddbb6116950292e114c.tar
seitan-d3917582873df723aa2a3ddbb6116950292e114c.tar.gz
seitan-d3917582873df723aa2a3ddbb6116950292e114c.tar.bz2
seitan-d3917582873df723aa2a3ddbb6116950292e114c.tar.lz
seitan-d3917582873df723aa2a3ddbb6116950292e114c.tar.xz
seitan-d3917582873df723aa2a3ddbb6116950292e114c.tar.zst
seitan-d3917582873df723aa2a3ddbb6116950292e114c.zip
cooker: simplify tag and add caller metadata
Group the metadata information: - simplify the json by removing the 'tag' and only using 'get' and 'set' keys - get uid and gid at runtime for the target ('caller'). This can be useful when the the UID and GID of the target are only known at runtime and they need to be used for setting the permissions of files - updated example demo/mknod.hjson Signed-off-by: Alice Frosi <afrosi@redhat.com>
-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)