From b2e31a6e7493c56f923cb7d86f7a8a32940393ec Mon Sep 17 00:00:00 2001
From: Alice Frosi <afrosi@redhat.com>
Date: Wed, 7 Jun 2023 14:07:23 +0200
Subject: seitan,cooker: op_resolvefd

ops:
 - update resolvefd with the description
 - add debug prints

cooker:
  - add emit_resolvefd when match has type FDPATH
---
 common/gluten.h  | 15 +++++++++------
 cooker/call.c    |  1 +
 cooker/emit.c    | 41 ++++++++++++++++++++++++++++++++++++++++-
 cooker/emit.h    |  3 +++
 cooker/match.c   | 13 ++++++++++++-
 demo/ioctl.hjson |  8 ++++++++
 operations.c     | 23 ++++++++++++++---------
 operations.h     |  2 +-
 8 files changed, 88 insertions(+), 18 deletions(-)
 create mode 100644 demo/ioctl.hjson

diff --git a/common/gluten.h b/common/gluten.h
index edb447c..a50687f 100644
--- a/common/gluten.h
+++ b/common/gluten.h
@@ -217,11 +217,14 @@ struct op_mask {
 	struct gluten_offset desc;	/* struct mask_desc */
 };
 
-struct op_resolvedfd {
-	struct gluten_offset fd;
-	struct gluten_offset path;
-	size_t path_size;
-	unsigned int jmp;
+struct resolvefd_desc {
+        struct gluten_offset fd;
+        struct gluten_offset path;
+        size_t path_max;
+};
+
+struct op_resolvefd {
+	struct gluten_offset desc;
 };
 
 struct op_copy {
@@ -241,7 +244,7 @@ struct op {
 		struct op_load load;
 		struct op_mask mask;
 		struct op_cmp cmp;
-		struct op_resolvedfd resfd;
+		struct op_resolvefd resfd;
 		struct op_copy copy;
 	} op;
 };
diff --git a/cooker/call.c b/cooker/call.c
index 289a0cb..7aef157 100644
--- a/cooker/call.c
+++ b/cooker/call.c
@@ -275,6 +275,7 @@ bool arg_needs_temp(struct field *f, int pos, JSON_Value *jvalue,
 			return arg_needs_temp(f, pos, jvalue, NULL, level + 1);
 
 		return false;
+	case FDPATH:
 	case STRING:
 		return false;
 	case STRUCT:
diff --git a/cooker/emit.c b/cooker/emit.c
index d0928e3..7b1b14d 100644
--- a/cooker/emit.c
+++ b/cooker/emit.c
@@ -163,6 +163,40 @@ void emit_load(struct gluten_ctx *g, struct gluten_offset dst,
 		die("Too many instructions");
 }
 
+/**
+ * emit_resolved() - Emit OP_RESOLVEFD instruction: resolve file descriptor with path
+ * @g:		gluten context
+ * @fd:		offset of the file descriptor value
+ * @path:	offset of the path
+ * @path_size:	size of the path
+ */
+void emit_resolvefd(struct gluten_ctx *g, struct gluten_offset fd,
+		     struct gluten_offset path, size_t path_size)
+{
+	struct op *op = (struct op *)gluten_ptr(&g->g, g->ip);
+	struct op_resolvefd *resfd = &op->op.resfd;
+	struct gluten_offset o;
+	struct resolvefd_desc *desc;
+
+	op->type = OP_RESOLVEDFD;
+        o = gluten_ro_alloc(g, sizeof(struct resolvefd_desc));
+        desc = (struct resolvefd_desc *)gluten_ptr(&g->g, o);
+
+	desc->fd = fd;
+	desc->path = path;
+	desc->path_max = path_size;
+
+	resfd->desc = o;
+
+	debug("   %i: OP_RESOLVEDFD:", g->ip.offset);
+	debug("   \tfd: %s offset=%d", gluten_offset_name[fd.type], fd.offset);
+	debug("   \tpath: %s offset=%d size=%d", gluten_offset_name[path.type],
+	      path.offset, path_size);
+
+	if (++g->ip.offset > INST_MAX)
+		die("Too many instructions");
+}
+
 /**
  * emit_mask(): Emit OP_MASK instruction: mask and store
  * @g:		gluten context
@@ -422,7 +456,7 @@ static struct gluten_offset emit_data_do(struct gluten_ctx *g,
 		break;
 	case STRING:
 		strncpy(p, value->v_str, str_len);
-		debug("   C#%i: (%s:%i) %s", g->cp.offset, type_str[type],
+		debug("   C#%i: (%s:%i) %s", ret.offset, type_str[type],
 		      str_len, value->v_str);
 
 		break;
@@ -459,6 +493,11 @@ struct gluten_offset emit_data_or(struct gluten_ctx *g,
 			    true);
 }
 
+struct gluten_offset emit_seccomp_data(int index) {
+	struct gluten_offset o = { OFFSET_SECCOMP_DATA, index };
+	return o;
+}
+
 static void gluten_link(struct gluten_ctx *g, enum jump_type type,
 			struct op *start)
 {
diff --git a/cooker/emit.h b/cooker/emit.h
index 9ec64e0..18618ee 100644
--- a/cooker/emit.h
+++ b/cooker/emit.h
@@ -16,6 +16,7 @@ void emit_load(struct gluten_ctx *g, struct gluten_offset dst,
 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);
 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);
@@ -29,6 +30,8 @@ void emit_copy(struct gluten_ctx *g,
 	       struct gluten_offset dst, struct gluten_offset src, size_t size);
 void emit_copy_field(struct gluten_ctx *g, struct field *field,
 		     struct gluten_offset dst, struct gluten_offset src);
+void emit_resolvefd(struct gluten_ctx *g, struct gluten_offset fd,
+                     struct gluten_offset path, size_t path_size);
 void emit_end(struct gluten_ctx *g);
 struct gluten_offset emit_data(struct gluten_ctx *g, enum type type,
 			       size_t str_len, union value *value);
diff --git a/cooker/match.c b/cooker/match.c
index e9aed16..3c7650c 100644
--- a/cooker/match.c
+++ b/cooker/match.c
@@ -78,13 +78,14 @@ 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;
+	struct gluten_offset const_offset, mask_offset, data_offset, seccomp_offset;
 	union value v = { .v_num = 0 };
 	struct field *f_inner;
 	const char *tag_name;
 	JSON_Object *tmp;
 	JSON_Array *set;
 	JSON_Value *sel;
+	size_t size;
 
 	if (f->name)
 		debug("    parsing field name %s", f->name);
@@ -202,6 +203,16 @@ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx  xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
 		emit_cmp(g, CMP_NE, offset, const_offset, strlen(v.v_str) + 1,
 			 JUMP_NEXT_BLOCK);
 		break;
+	case FDPATH:
+		v.v_str = json_value_get_string(jvalue);
+		size = strlen(v.v_str) + 1;
+		offset = gluten_rw_alloc(g, size);
+		const_offset = emit_data(g, STRING, size, &v);
+		seccomp_offset = emit_seccomp_data(index);
+		emit_resolvefd(g, seccomp_offset, offset, size);
+		emit_cmp(g, CMP_NE, offset, const_offset, size,
+			 JUMP_NEXT_BLOCK);
+		break;
 	case STRUCT:
 		for (f_inner = f->desc.d_struct; f_inner->name; f_inner++) {
 			JSON_Value *field_value;
diff --git a/demo/ioctl.hjson b/demo/ioctl.hjson
new file mode 100644
index 0000000..53b59f5
--- /dev/null
+++ b/demo/ioctl.hjson
@@ -0,0 +1,8 @@
+[
+  {
+    "match": [
+      { "ioctl": { "path": "/dev/net/tun", "request": "TUNSETIFF" } }
+    ],
+    "return": 0
+  }
+]
diff --git a/operations.c b/operations.c
index 78206bd..50fdcfb 100644
--- a/operations.c
+++ b/operations.c
@@ -427,24 +427,29 @@ int op_cmp(const struct seccomp_notif *req, int notifier, struct gluten *g,
 }
 
 int op_resolve_fd(const struct seccomp_notif *req, int notifier,
-		  struct gluten *g, struct op_resolvedfd *op)
+		  struct gluten *g, struct op_resolvefd *op)
 {
-	char fdpath[PATH_MAX], buf[PATH_MAX], path[PATH_MAX];
+	const struct resolvefd_desc *desc = gluten_ptr(&req->data, g, op->desc);
+	char fdpath[PATH_MAX], buf[PATH_MAX];
 	ssize_t nbytes;
 	int fd;
 
 	(void)notifier;
 
-	if (gluten_read(NULL, g, &path, op->path, sizeof(op->path_size)) == -1)
-		return -1;
-	if (gluten_read(&req->data, g, &fd, op->fd, sizeof(fd)) == -1)
+	debug("  op_resolvefd: fd=(%s %d) path=(%s %d) path_max=%d",
+	      gluten_offset_name[desc->fd.type], desc->fd.offset,
+	      gluten_offset_name[desc->path.type], desc->path.offset,
+	      desc->path_max);
+
+	if (gluten_read(&req->data, g, &fd, desc->fd, sizeof(fd)) == -1)
 		return -1;
 
 	snprintf(fdpath, PATH_MAX, "/proc/%d/fd/%d", req->pid, fd);
-	if ((nbytes = readlink(fdpath, buf, op->path_size)) < 0)
-		ret_err(-1, "error reading %s", fdpath);
-	if (strcmp(path, buf) == 0)
-		return op->jmp;
+	if ((nbytes = readlink(fdpath, buf, desc->path_max)) < 0)
+		ret_err(-1, "error reading %s", buf);
+
+	debug("  op_resolvefd: fd %d -> path: %s", fd, buf);
+	gluten_write(g, desc->path, &buf, desc->path_max);
 
 	return 0;
 }
diff --git a/operations.h b/operations.h
index f543d7a..2f26fc6 100644
--- a/operations.h
+++ b/operations.h
@@ -53,7 +53,7 @@ int op_continue(const struct seccomp_notif *req, int notifier, struct gluten *g,
 int op_cmp(const struct seccomp_notif *req, int notifier, struct gluten *g,
 	   struct op_cmp *op);
 int op_resolve_fd(const struct seccomp_notif *req, int notifier,
-		  struct gluten *g, struct op_resolvedfd *op);
+		  struct gluten *g, struct op_resolvefd *op);
 int op_load(const struct seccomp_notif *req, int notifier, struct gluten *g,
 	    struct op_load *load);
 int op_copy(const struct seccomp_notif *req, int notifier, struct gluten *g,
-- 
cgit v1.2.3