From fb2a89cbfc5049d360bb734b4896946e9963e39a Mon Sep 17 00:00:00 2001
From: Alice Frosi <afrosi@redhat.com>
Date: Fri, 2 Jun 2023 14:25:30 +0200
Subject: cooker, seitan: fix some bugs for op call

cooker:
 - added missing OP_CALL type
 - local copy of the offset for the type STRUCT
 - fix return offset
 - added type LONG in emit_data

seitan:
 - check context if NULL
 - fix ptr dereference
 - added a couple of debug print
 - added error message in seitan for eval
---
 cooker/call.c |  7 +++----
 cooker/emit.c |  8 ++++++--
 operations.c  | 37 +++++++++++++++++++++++--------------
 seitan.c      |  3 ++-
 4 files changed, 34 insertions(+), 21 deletions(-)

diff --git a/cooker/call.c b/cooker/call.c
index db2d6b8..9561568 100644
--- a/cooker/call.c
+++ b/cooker/call.c
@@ -57,7 +57,7 @@ Examples of arguments:
 				parse_arg() passes ro_data offset
 
 - STRUCT: 1, 2		write struct to ro_data, and pointer to it
-				parse_tag() passes ro_data offset
+				parse_arg() passes ro_data offset
 
 - STRUCT: "get" <tag>	write pointer to tag
 				parse_arg() passes null offset
@@ -208,14 +208,14 @@ static union value parse_field(struct gluten_ctx *g, struct arg *args,
 		break;
 	case STRUCT:
 		for (f_inner = f->desc.d_struct; f_inner->name; f_inner++) {
+			struct gluten_offset struct_start = offset;
 			JSON_Value *f_value;
 
 			tmp1 = json_value_get_object(jvalue);
 			f_value = json_object_get_value(tmp1, f_inner->name);
 			if (!f_value)
 				continue;
-
-			parse_field(g, args, &offset, index, f_inner, f_value,
+			parse_field(g, args, &struct_start, index, f_inner, f_value,
 				    false, add);
 		}
 		break;
@@ -323,7 +323,6 @@ static struct gluten_offset parse_arg(struct gluten_ctx *g, struct arg *args,
 		offset = gluten_rw_alloc(g, a->f.size);
 	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;
diff --git a/cooker/emit.c b/cooker/emit.c
index 705df4b..05e3f81 100644
--- a/cooker/emit.c
+++ b/cooker/emit.c
@@ -73,6 +73,7 @@ void emit_call(struct gluten_ctx *g, struct ns_spec *ns, long nr,
 	unsigned ns_count, i;
 	struct ns_spec *ctx;
 
+	op->type = OP_CALL;
 	for (ns_count = 0; ns[ns_count].spec != NS_SPEC_NONE; ns_count++);
 
 	if (ns_count) {
@@ -92,14 +93,16 @@ void emit_call(struct gluten_ctx *g, struct ns_spec *ns, long nr,
 		desc->arg_deref |= BIT(i) * is_ptr[i];
 	desc->context = o1;
 	memcpy(desc->args, offset, sizeof(struct gluten_offset) * count);
-	desc->args[count + 1] = ret_offset;
+	desc->args[count] = ret_offset;
 
 	debug("   %i: OP_CALL: %i, arguments:", g->ip.offset, nr);
 	for (i = 0; i < count; i++) {
 		debug("\t%i: %s %s%i", i, gluten_offset_name[offset[i].type],
 		      is_ptr[i] ? "*" : "", offset[i].offset);
 	}
-
+	if (desc->has_ret)
+		debug("\treturn: %s %i", gluten_offset_name[ret_offset.type],
+		      offset[i].offset);
 	call->desc = o2;
 
 	if (++g->ip.offset > INST_MAX)
@@ -298,6 +301,7 @@ static struct gluten_offset emit_data_do(struct gluten_ctx *g,
 		}
 
 		break;
+	case LONG:
 	case U64:
 		if (add) {
 			*(uint64_t *)p |= value->v_num;
diff --git a/operations.c b/operations.c
index 2fb4053..304b39b 100644
--- a/operations.c
+++ b/operations.c
@@ -59,8 +59,8 @@ static struct gluten_offset *get_syscall_ret(struct syscall_desc *s)
 	if (s->has_ret == 0)
 		return NULL;
 	if (s->arg_count == 0)
-		return s->args;
-	return s->args + s->arg_count + 1;
+		return &s->args[0];
+	return &s->args[s->arg_count];
 }
 
 static int write_syscall_ret(struct gluten *g, struct syscall_desc *s,
@@ -68,8 +68,11 @@ static int write_syscall_ret(struct gluten *g, struct syscall_desc *s,
 {
 	struct gluten_offset *p = get_syscall_ret(s);
 
-	if (p != NULL)
-		return gluten_write(g, *p, &c->ret, sizeof(c->ret));
+	if (p != NULL) {
+		debug("  op_call: write return value=%ld",c->ret);
+		if (gluten_write(g, *p, &c->ret, sizeof(c->ret)) == -1)
+			ret_err(-1, "  failed writing return value at %d", p->offset);
+	}
 
 	return 0;
 }
@@ -78,7 +81,6 @@ static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g,
 			     struct syscall_desc *s, struct ns_spec *ctx,
 			     struct arg_clone *c)
 {
-	struct gluten_offset x;
 	unsigned int i, n = 0;
 	long arg;
 
@@ -87,23 +89,27 @@ static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g,
 	c->nr = s->nr;
 
 	for (i = 0; i < s->arg_count; i++) {
-		if (gluten_read(NULL, g, &arg, s->args[i], sizeof(arg)) == -1)
-			return -1;
 		/* If arg is a pointer then need to calculate the absolute
 		 * address and the value of arg is the relative offset of the actual
 		 * value.
 		*/
 		if (GET_BIT(s->arg_deref, i) == 1) {
-			x.type = s->args[i].type;
-			x.offset = arg;
-			if (gluten_read(NULL, g, &c->args[i], x,
-					sizeof(c->args[i])) == -1)
-				return -1;
+			c->args[i] = gluten_ptr(NULL, g, s->args[i]);
+			debug("  read pointer arg%d at offset %d", i, s->args[i].offset);
 		} else {
+			if (gluten_read(NULL, g, &arg, s->args[i],
+					sizeof(arg)) == -1)
+				ret_err(-1, "  failed reading arg %d", i);
+			debug("  read arg%d at offset %d v=%ld", i,
+			      s->args[i].offset, arg);
 			c->args[i] = (void *)arg;
 		}
 	}
 
+	/* TODO: add proper check when there is no context */
+	if (ctx == NULL)
+		return 0;
+
 	for (; ctx->spec != NS_SPEC_NONE; ctx++) {
 		enum ns_spec_type spec = ctx->spec;
 		enum ns_type ns = ctx->ns;
@@ -219,6 +225,8 @@ int op_load(const struct seccomp_notif *req, int notifier, struct gluten *g,
 	char path[PATH_MAX];
 	int fd, ret = 0;
 
+	debug("  op_load: argument %d", load->src.offset);
+
 	snprintf(path, sizeof(path), "/proc/%d/mem", req->pid);
 	if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0)
 		ret_err(-1, "error opening mem for %d", req->pid);
@@ -358,13 +366,13 @@ int op_cmp(const struct seccomp_notif *req, int notifier, struct gluten *g,
 	    (res < 0 && (cmp == CMP_LT || cmp == CMP_LE)) ||
 	    (res > 0 && (cmp == CMP_GT || cmp == CMP_GE)) ||
 	    (res != 0 && (cmp == CMP_NE))) {
-		debug("  execute op_cmp: successful comparison");
+		debug("  op_cmp: successful comparison");
 		return 0;
 	}
 
 	if (gluten_read(NULL, g, &jmp, op->jmp, sizeof(jmp)) == -1)
 		return -1;
-	debug("  execute op_cmp: jump to %d", jmp);
+	debug("  op_cmp: jump to %d", jmp);
 	return jmp;
 }
 
@@ -403,6 +411,7 @@ int op_nr(const struct seccomp_notif *req, int notifier, struct gluten *g,
 		return -1;
 	if (gluten_read(NULL, g, &jmp, op->no_match, sizeof(jmp)) == -1)
 		return -1;
+	debug("  op_nr: checking syscall=%ld");
 	if (nr == req->data.nr)
 		return jmp;
 
diff --git a/seitan.c b/seitan.c
index fff820c..30772df 100644
--- a/seitan.c
+++ b/seitan.c
@@ -238,7 +238,8 @@ int main(int argc, char **argv)
 				/* The notifier fd was closed by the target */
 				running = false;
 			} else if (notifier == events[i].data.fd) {
-				eval(&g, req, notifier);
+				if (eval(&g, req, notifier) == -1 )
+					err("  an error occured during the evaluation");
 			}
 		}
 	}
-- 
cgit v1.2.3