aboutgitcodelistschat:MatrixIRC
path: root/cooker/emit.c
diff options
context:
space:
mode:
Diffstat (limited to 'cooker/emit.c')
-rw-r--r--cooker/emit.c150
1 files changed, 126 insertions, 24 deletions
diff --git a/cooker/emit.c b/cooker/emit.c
index 8c35f1d..c233b0a 100644
--- a/cooker/emit.c
+++ b/cooker/emit.c
@@ -14,8 +14,10 @@
#include "emit.h"
static const char *type_str[] = {
+ "UNDEF", "NONE",
"INT", "INTMASK", "INTFLAGS",
"U32", "U32MASK", "U32FLAGS",
+ "U64", "U64MASK", "U64FLAGS",
"LONG", "LONGMASK", "LONGFLAGS",
"STRING",
"STRUCT", "SELECT",
@@ -25,83 +27,183 @@ static const char *type_str[] = {
NULL
};
-static const char *cmp_type_str[] = { "EQ", "GT", "GE", "LT", "LE", NULL };
+static const char *cmp_type_str[] = {
+ "EQ", "NE", "GT", "GE", "LT", "LE", NULL
+};
-void emit_nr(struct gluten_ctx *g, long number)
+/**
+ * emit_nr() - Emit OP_NR instruction: jump on syscall mismatch
+ * @g: gluten context
+ * @number: Pointer to system call number
+ */
+void emit_nr(struct gluten_ctx *g, struct gluten_offset number)
{
- struct op_nr *nr = (struct op_nr *)gluten_ptr(&g->g, g->ip);
+ struct op *op = (struct op *)gluten_ptr(&g->g, g->ip);
+ struct op_nr *nr = &op->op.nr;
+
+ op->type = OP_NR;
nr->nr = number;
nr->no_match.type = OFFSET_INSTRUCTION;
- nr->no_match.offset = NEXT_BLOCK;
+ nr->no_match.offset = JUMP_NEXT_BLOCK;
- debug(" %i: OP_NR %li, < >", g->ip.offset, number);
+ debug(" %i: OP_NR: if syscall number is not %li, jump to %s",
+ g->ip.offset, number, jump_name[nr->no_match.offset]);
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
+ * @index: Index of system call argument
+ * @len: Length of data item pointed by reference
+ */
void emit_load(struct gluten_ctx *g, struct gluten_offset dst,
int index, size_t len)
{
- struct op_load *load = (struct op_load *)gluten_ptr(&g->g, g->ip);
+ struct op *op = (struct op *)gluten_ptr(&g->g, g->ip);
+ struct op_load *load = &op->op.load;
+
+ op->type = OP_LOAD;
load->src.type = OFFSET_SECCOMP_DATA;
load->src.offset = index;
load->dst = dst;
- debug(" %i: OP_LOAD #%i < %i (%lu)", g->ip.offset, dst.offset,
- index, len);
+ debug(" %i: OP_LOAD: #%i < args[%i] (size: %lu)",
+ g->ip.offset, dst.offset, index, len);
if (++g->ip.offset > INST_MAX)
die("Too many instructions");
}
-void emit_cmp(struct gluten_ctx *g, enum op_cmp_type cmp,
+/**
+ * emit_cmp(): Emit OP_CMP instruction: compare data from two offsets
+ * @g: gluten context
+ * @cmp_type: Type of comparison
+ * @x: gluten pointer to first operand of comparison
+ * @y: gluten pointer to second operand of comparison
+ * @size: Size of comparison
+ * @jmp: Jump direction if comparison is true
+ */
+void emit_cmp(struct gluten_ctx *g, enum op_cmp_type cmp_type,
struct gluten_offset x, struct gluten_offset y, size_t size,
enum jump_type jmp)
{
- struct op_cmp *op = (struct op_cmp *)gluten_ptr(&g->g, g->ip);
+ struct op *op = (struct op *)gluten_ptr(&g->g, g->ip);
+ struct op_cmp *cmp = &op->op.cmp;
- op->x = x;
- op->y = y;
- op->size = size;
- op->cmp = cmp;
- op->jmp = jmp;
+ op->type = OP_CMP;
- debug(" %i: OP_CMP (#%lu) %%%lu %s %%%lu", g->ip.offset, size,
- x.offset, cmp_type_str[cmp], y.offset);
+ cmp->x = x;
+ cmp->y = y;
+ cmp->size = size;
+ cmp->cmp = cmp_type;
+ cmp->jmp.type = OFFSET_INSTRUCTION;
+ cmp->jmp.offset = jmp;
+
+ debug(" %i: OP_CMP: if %s: #%lu %s (size: %lu) %s: #%lu, jump to %s",
+ g->ip.offset,
+ gluten_offset_name[x.type], x.offset,
+ cmp_type_str[cmp_type], size,
+ gluten_offset_name[y.type], y.offset,
+ jump_name[jmp]);
if (++g->ip.offset > INST_MAX)
die("Too many instructions");
}
+/**
+ * emit_cmp_field() - Emit OP_CMP for a given field type
+ * @g: gluten context
+ * @cmp: Type of comparison
+ * @field: Description of field from system call model
+ * @x: gluten pointer to first operand of comparison
+ * @y: gluten pointer to second operand of comparison
+ * @jmp: Jump direction if comparison is true
+ */
void emit_cmp_field(struct gluten_ctx *g, enum op_cmp_type cmp,
struct field *field,
- struct gluten_offset base, struct gluten_offset match,
+ struct gluten_offset x, struct gluten_offset y,
enum jump_type jmp)
{
- base.offset += field->offset;
-
- emit_cmp(g, cmp, base, match,
+ emit_cmp(g, cmp, x, y,
field->strlen ? field->strlen : gluten_size[field->type],
jmp);
}
struct gluten_offset emit_data(struct gluten_ctx *g, enum type type,
- union value *value)
+ size_t str_len, union value *value)
{
void *p = gluten_ptr(&g->g, g->cp);
struct gluten_offset ret = g->cp;
- if (type == INT) {
+ switch (type) {
+ case INT:
+ if (g->cp.offset + sizeof(int) > RO_DATA_SIZE)
+ die(" Read-only data section exceeded");
+
*(int *)p = value->v_int;
debug(" C#%i: (%s) %i", g->cp.offset, type_str[type],
value->v_int);
- if ((g->cp.offset += sizeof(int)) > RO_DATA_SIZE)
+
+ g->cp.offset += sizeof(int);
+ break;
+ case STRING:
+ if (g->cp.offset + str_len > RO_DATA_SIZE)
die(" Read-only data section exceeded");
+
+ strncpy(p, value->v_str, str_len);
+ debug(" C#%i: (%s:%i) %s", g->cp.offset, type_str[type],
+ str_len, value->v_str);
+
+ g->cp.offset += str_len;
+ break;
+ default:
+ ;
}
return ret;
}
+
+static void gluten_link(struct gluten_ctx *g, enum jump_type type,
+ struct op *start)
+{
+ struct gluten_offset *jmp;
+ struct op *op;
+
+ for (op = (struct op *)start; op->type; op++) {
+ switch (op->type) {
+ case OP_NR:
+ jmp = &op->op.nr.no_match;
+ break;
+ case OP_CMP:
+ jmp = &op->op.cmp.jmp;
+ break;
+ default:
+ continue;
+ }
+
+ if (jmp->offset == type) {
+ jmp->offset = g->ip.offset;
+ debug(" linked jump of instruction #%i to #%i",
+ op - (struct op *)g->g.inst, g->ip.offset);
+ }
+ }
+}
+
+void link_block(struct gluten_ctx *g)
+{
+ debug(" Linking block...");
+ gluten_link(g, JUMP_NEXT_BLOCK, (struct op *)gluten_ptr(&g->g, g->lr));
+}
+
+void link_match(struct gluten_ctx *g)
+{
+ debug(" Linking match...");
+ gluten_link(g, JUMP_NEXT_MATCH, (struct op *)gluten_ptr(&g->g, g->mr));
+}