From c38fccbc867019d6c063be1c1d8137edfe52f8de Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Wed, 7 Jun 2023 23:02:23 +0200 Subject: mknod/mknodat values, initial support for MASK flag, OP_BITWISE Signed-off-by: Stefano Brivio --- cooker/call.c | 41 ++++++++++++++++++++++++++---------- cooker/calls/fs.c | 63 ++++++++++++++++++++++++++++++++++++++++++++----------- cooker/cooker.h | 1 + cooker/emit.c | 56 ++++++++++++++++++++++++++++++------------------- cooker/emit.h | 9 +++++--- cooker/match.c | 44 ++++++++++++++++++++++++++------------ 6 files changed, 154 insertions(+), 60 deletions(-) (limited to 'cooker') diff --git a/cooker/call.c b/cooker/call.c index 7aef157..7ae3d48 100644 --- a/cooker/call.c +++ b/cooker/call.c @@ -113,10 +113,14 @@ static union value parse_field(struct gluten_ctx *g, struct arg *args, if (tag_offset.type == OFFSET_NULL) die(" tag not found"); - if (base_offset->type == OFFSET_NULL) + if (base_offset->type == OFFSET_NULL) { *base_offset = tag_offset; - else + } 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) @@ -252,9 +256,10 @@ bool arg_needs_temp(struct field *f, int pos, JSON_Value *jvalue, case INT: case LONG: case U32: + return false; case GNU_DEV_MAJOR: case GNU_DEV_MINOR: - return false; + return true; case SELECT: f_inner = f->desc.d_select->field; if (arg_needs_temp(f_inner, pos, jvalue, top_level_tag, level)) @@ -300,7 +305,7 @@ bool arg_needs_temp(struct field *f, int pos, JSON_Value *jvalue, } static struct gluten_offset parse_arg(struct gluten_ctx *g, struct arg *args, - struct arg *a, + struct arg *a, bool multi_field, struct gluten_offset offset, JSON_Value *jvalue) { @@ -314,10 +319,15 @@ static struct gluten_offset parse_arg(struct gluten_ctx *g, struct arg *args, return offset; } - if (arg_needs_temp(&a->f, a->pos, jvalue, &top_level_tag, 0)) - offset = gluten_rw_alloc(g, a->f.size); - else if (a->f.size && !top_level_tag) + if (arg_needs_temp(&a->f, a->pos, jvalue, &top_level_tag, 0) || + multi_field) { + if (a->f.size) + offset = gluten_rw_alloc(g, a->f.size); + else + offset = gluten_rw_alloc_type(g, a->f.type); + } else if ((a->f.size && !top_level_tag)) { offset = gluten_ro_alloc(g, a->f.size); + } parse_field(g, args, &offset, a->pos, &a->f, jvalue, false, false); return offset; @@ -336,6 +346,8 @@ static void parse_call(struct gluten_ctx *g, struct ns_spec *ns, long nr, struct { bool needs_fd; bool has_fd; + bool found; + bool multi_field; } arg_check[6] = { 0 }; int arg_max_pos = -1; unsigned count = 0; @@ -349,6 +361,10 @@ static void parse_call(struct gluten_ctx *g, struct ns_spec *ns, long nr, a = g->selected_arg[a->pos]; } + if (arg_check[a->pos].found) + arg_check[a->pos].multi_field = true; + arg_check[a->pos].found = true; + if (a->f.type == FDPATH) arg_check[a->pos].needs_fd = true; @@ -362,10 +378,13 @@ static void parse_call(struct gluten_ctx *g, struct ns_spec *ns, long nr, /* TODO: Factor this out into a function in... parse.c? */ for (a = args; a->f.name; a++) { JSON_Value *jvalue; + bool multi_field; if (a->f.type == SELECTED) a = g->selected_arg[a->pos]; + multi_field = arg_check[a->pos].multi_field; + /* Not common with parse_match(), though */ if ((jvalue = json_object_get_value(obj, a->f.name))) { if (arg_check[a->pos].has_fd) @@ -373,15 +392,15 @@ static void parse_call(struct gluten_ctx *g, struct ns_spec *ns, long nr, else if (arg_check[a->pos].needs_fd) arg_check[a->pos].has_fd = true; - offset[a->pos] = parse_arg(g, args, a, offset[a->pos], - jvalue); + offset[a->pos] = parse_arg(g, args, a, multi_field, + 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, args, a, offset[a->pos], - jvalue); + offset[a->pos] = parse_arg(g, args, a, multi_field, + offset[a->pos], jvalue); } else { die(" No specification for argument %s", a->f.name); } diff --git a/cooker/calls/fs.c b/cooker/calls/fs.c index cfc0091..469dd88 100644 --- a/cooker/calls/fs.c +++ b/cooker/calls/fs.c @@ -58,13 +58,44 @@ swapoff #include #include -#include +#define _GNU_SOURCE #include +#include #include #include "../cooker.h" #include "../calls.h" +static struct num modes[] = { + { "S_ISUID", S_ISUID }, + { "S_ISGID", S_ISGID }, + { "S_IRWXU", S_IRWXU }, + { "S_IRUSR", S_IRUSR }, + { "S_IWUSR", S_IWUSR }, + { "S_IXUSR", S_IXUSR }, + { "S_IRWXG", S_IRWXG }, + { "S_IRGRP", S_IRGRP }, + { "S_IWGRP", S_IWGRP }, + { "S_IXGRP", S_IXGRP }, + { "S_IRWXO", S_IRWXO }, + { "S_IROTH", S_IROTH }, + { "S_IWOTH", S_IWOTH }, + { "S_IXOTH", S_IXOTH }, + { "S_ISVTX", S_ISVTX }, + { 0 }, +}; + +static struct num types[] = { + { "S_IFSOCK", S_IFSOCK }, + { "S_IFLNK", S_IFLNK }, + { "S_IFREG", S_IFREG }, + { "S_IFBLK", S_IFBLK }, + { "S_IFDIR", S_IFDIR }, + { "S_IFCHR", S_IFCHR }, + { "S_IFIFO", S_IFIFO }, + { 0 }, +}; + static struct arg mknod_args[] = { { 0, { @@ -75,9 +106,16 @@ static struct arg mknod_args[] = { }, { 1, { - "mode", U32 /* TODO */, 0, + "mode", INT, FLAGS | MASK, 0, 0, - { 0 /* TODO */ }, + { .d_num = modes }, + } + }, + { 1, + { + "type", INT, FLAGS | MASK, + 0, 0, + { .d_num = types }, } }, { 2, @@ -98,13 +136,7 @@ static struct arg mknod_args[] = { }; static struct arg mknodat_args[] = { - { 0, - { - "dirfd", UNDEF, 0, - 0, 1 /* TODO: PATH_MAX */, - { 0 } - } - }, + /* No dirfd: we only support absolute paths at the moment */ { 1, { "path", STRING, 0, @@ -114,9 +146,16 @@ static struct arg mknodat_args[] = { }, { 2, { - "mode", UNDEF /* TODO */, FLAGS, + "mode", INT, FLAGS | MASK, + 0, 0, + { .d_num = modes }, + } + }, + { 2, + { + "type", INT, FLAGS | MASK, 0, 0, - { 0 /* TODO */ }, + { .d_num = types }, } }, { 3, diff --git a/cooker/cooker.h b/cooker/cooker.h index b26ea2d..24d8f7f 100644 --- a/cooker/cooker.h +++ b/cooker/cooker.h @@ -18,6 +18,7 @@ #include #include +#include #include #define TAGS_MAX 256 diff --git a/cooker/emit.c b/cooker/emit.c index 506a561..107b2ce 100644 --- a/cooker/emit.c +++ b/cooker/emit.c @@ -198,40 +198,49 @@ void emit_resolvefd(struct gluten_ctx *g, struct gluten_offset fd, } /** - * emit_mask(): Emit OP_MASK instruction: mask and store + * emit_bitwise(): Emit OP_BITWISE instruction: bitwise operation and store * @g: gluten context * @type: Type of operands - * @src: gluten pointer to source operand - * @mask: gluten pointer to mask + * @op_type: Type of bitwise operation + * @dst: gluten pointer to destination operand, can be OFFSET_NULL + * @x: gluten pointer to first source operand + * @y: gluten pointer to second source operand * - * Return: offset to destination operand, allocated here + * Return: offset to destination operand, allocated here if not given */ -struct gluten_offset emit_mask(struct gluten_ctx *g, enum type type, - struct gluten_offset src, - struct gluten_offset mask) +struct gluten_offset emit_bitwise(struct gluten_ctx *g, enum type type, + enum bitwise_type op_type, + struct gluten_offset dst, + struct gluten_offset x, + struct gluten_offset y) { struct op *op = (struct op *)gluten_ptr(&g->g, g->ip); - struct op_mask *op_mask = &op->op.mask; + struct op_bitwise *op_bitwise = &op->op.bitwise; struct gluten_offset o; - struct mask_desc *desc; + struct bitwise_desc *desc; - op->type = OP_MASK; + op->type = OP_BITWISE; - o = gluten_ro_alloc(g, sizeof(struct mask_desc)); - desc = (struct mask_desc *)gluten_ptr(&g->g, o); + o = gluten_ro_alloc(g, sizeof(struct bitwise_desc)); + desc = (struct bitwise_desc *)gluten_ptr(&g->g, o); desc->size = gluten_size[type]; - desc->dst = gluten_rw_alloc(g, desc->size); - desc->src = src; - desc->mask = mask; + desc->type = op_type; + if (dst.type == OFFSET_NULL) + desc->dst = gluten_rw_alloc(g, desc->size); + else + desc->dst = dst; + desc->x = x; + desc->y = y; - op_mask->desc = o; + op_bitwise->desc = o; - debug(" %i: OP_MASK: %s: #%lu (size: %lu) := %s: #%lu & %s: #%lu", + debug(" %i: OP_BITWISE: %s: #%lu (size: %lu) := %s: #%lu %s %s: #%lu", g->ip.offset, - gluten_offset_name[desc->dst.type], desc->dst.offset, desc->size, - gluten_offset_name[desc->src.type], desc->src.offset, - gluten_offset_name[desc->mask.type], desc->mask.offset); + gluten_offset_name[desc->dst.type], desc->dst.offset, desc->size, + gluten_offset_name[desc->x.type], desc->x.offset, + bitwise_type_str[op_type], + gluten_offset_name[desc->y.type], desc->y.offset); if (++g->ip.offset > INST_MAX) die("Too many instructions"); @@ -537,5 +546,10 @@ void link_match(struct gluten_ctx *g) { debug(" Linking match..."); gluten_link(g, JUMP_NEXT_MATCH, (struct op *)gluten_ptr(&g->g, g->mr)); - gluten_link(g, JUMP_NEXT_ACTION, (struct op *)gluten_ptr(&g->g, g->mr)); +} + +void link_matches(struct gluten_ctx *g) +{ + debug(" Linking matches..."); + gluten_link(g, JUMP_NEXT_ACTION, (struct op *)gluten_ptr(&g->g, g->lr)); } diff --git a/cooker/emit.h b/cooker/emit.h index 81f947e..978c9e0 100644 --- a/cooker/emit.h +++ b/cooker/emit.h @@ -13,10 +13,12 @@ void emit_call(struct gluten_ctx *g, struct ns_spec *ns, long nr, 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); -struct gluten_offset emit_mask(struct gluten_ctx *g, enum type type, - struct gluten_offset src, - struct gluten_offset mask); struct gluten_offset emit_seccomp_data(int index); +struct gluten_offset emit_bitwise(struct gluten_ctx *g, enum type type, + enum bitwise_type op_type, + struct gluten_offset dst, + struct gluten_offset x, + struct gluten_offset y); void emit_cmp(struct gluten_ctx *g, enum op_cmp_type cmp, struct gluten_offset x, struct gluten_offset y, size_t size, enum jump_type jmp); @@ -43,5 +45,6 @@ struct gluten_offset emit_data_or(struct gluten_ctx *g, enum type type, union value *value); void link_block(struct gluten_ctx *g); void link_match(struct gluten_ctx *g); +void link_matches(struct gluten_ctx *g); #endif /* EMIT_H */ diff --git a/cooker/match.c b/cooker/match.c index 3c7650c..d32bf0a 100644 --- a/cooker/match.c +++ b/cooker/match.c @@ -78,7 +78,7 @@ static union value parse_field(struct gluten_ctx *g, enum op_cmp_type cmp, enum jump_type jump, int index, struct field *f, JSON_Value *jvalue) { - struct gluten_offset const_offset, mask_offset, data_offset, seccomp_offset; + struct gluten_offset const_offset, mask_offset, seccomp_offset; union value v = { .v_num = 0 }; struct field *f_inner; const char *tag_name; @@ -90,6 +90,32 @@ static union value parse_field(struct gluten_ctx *g, if (f->name) debug(" parsing field name %s", f->name); + /* Some types need pre-tagging preparation */ + switch (f->type) { + case GNU_DEV_MAJOR: + /* +xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx +______________________ _____________ + */ + v.v_num = ((long long)0xfff << 44) | (0xfff << 8); + mask_offset = emit_data(g, U64, 0, &v); + offset = emit_bitwise(g, U64, BITWISE_AND, NULL_OFFSET, + offset, mask_offset); + break; + case GNU_DEV_MINOR: + /* +xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx + ____________________________ ________ + */ + v.v_num = 0xff | ((long long)0xffffff << 12); + mask_offset = emit_data(g, U64, 0, &v); + offset = emit_bitwise(g, U64, BITWISE_AND, NULL_OFFSET, + offset, mask_offset); + break; + default: + break; + } + if (json_value_get_type(jvalue) == JSONObject && (tmp = json_value_get_object(jvalue)) && (tag_name = json_object_get_string(tmp, "tag"))) { @@ -153,30 +179,20 @@ static union value parse_field(struct gluten_ctx *g, xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx ______________________ _____________ */ - v.v_num = ((long long)0xfff << 44) | (0xfff << 8); - mask_offset = emit_data(g, U64, 0, &v); - v.v_num = value_get_num(f->desc.d_num, jvalue); v.v_num = (v.v_num & 0xfff) << 8 | (v.v_num & ~0xfff) << 32; const_offset = emit_data(g, U64, 0, &v); - - data_offset = emit_mask(g, U64, offset, mask_offset); - emit_cmp_field(g, cmp, f, data_offset, const_offset, jump); + emit_cmp_field(g, cmp, f, offset, const_offset, jump); break; case GNU_DEV_MINOR: /* xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx ____________________________ ________ */ - v.v_num = 0xff | ((long long)0xffffff << 12); - mask_offset = emit_data(g, U64, 0, &v); - v.v_num = value_get_num(f->desc.d_num, jvalue); v.v_num = (v.v_num & 0xff) | (v.v_num & ~0xfff) << 12; const_offset = emit_data(g, U64, 0, &v); - - data_offset = emit_mask(g, U64, offset, mask_offset); - emit_cmp_field(g, cmp, f, data_offset, const_offset, jump); + emit_cmp_field(g, cmp, f, offset, const_offset, jump); break; case SELECT: f_inner = f->desc.d_select->field; @@ -329,4 +345,6 @@ void handle_matches(struct gluten_ctx *g, JSON_Value *value) link_match(g); } + + link_matches(g); } -- cgit v1.2.3