aboutgitcodelistschat:MatrixIRC
path: root/cooker
diff options
context:
space:
mode:
Diffstat (limited to 'cooker')
-rw-r--r--cooker/call.c61
-rw-r--r--cooker/calls/net.c259
-rw-r--r--cooker/cooker.h6
-rw-r--r--cooker/emit.c38
-rw-r--r--cooker/emit.h4
-rw-r--r--cooker/gluten.c16
-rw-r--r--cooker/gluten.h4
-rw-r--r--cooker/match.c56
-rw-r--r--cooker/parse.c6
9 files changed, 434 insertions, 16 deletions
diff --git a/cooker/call.c b/cooker/call.c
index bb53829..dd37fe9 100644
--- a/cooker/call.c
+++ b/cooker/call.c
@@ -72,7 +72,7 @@ static union value parse_metadata(struct gluten_ctx *g, struct field *f,
if (tag_offset.type == OFFSET_NULL)
die(" tag not found");
- if ((*base_offset)->type == OFFSET_NULL) {
+ if ((*base_offset)->type == OFFSET_NULL || (f->flags & WBUF)) {
**base_offset = tag_offset;
} else if (f->flags & MASK || add) {
emit_bitwise(g, f->type, BITWISE_OR, offset, offset,
@@ -133,6 +133,10 @@ Examples of arguments:
- STRING: abcd write abcd to ro_data (using size), and pointer to it
parse_arg() passes ro_data offset
+- IOV: <tag> write (one!) struct iovec with iov_base pointer to tag
+ parse_arg() passes null offset
+ parse_field() gives back data offset
+
- STRUCT: 1, 2 write struct to ro_data, and pointer to it
parse_arg() passes ro_data offset
@@ -169,12 +173,38 @@ static union value parse_field(struct gluten_ctx *g, struct arg *args,
(tmp1 = json_value_get_object(jvalue)) && is_metadata_obj(tmp1)) {
v = parse_metadata(g, f, &base_offset, offset, tmp1, dry_run,
add);
- if (v.v_num == 0)
+ if (!(f->flags & IOV) && v.v_num == 0)
+ return v;
+ }
+
+ if (f->flags & IOV) {
+ struct gluten_offset iov;
+ struct iovec *iovp;
+ intptr_t *msg_iov;
+
+ if (dry_run)
return v;
+
+ /* iov_base: v */
+ /* iov_len: at the moment from field */
+ msg_iov = (intptr_t *)gluten_ptr(&g->g, offset);
+
+ iov = gluten_rw_alloc(g, sizeof(struct iovec));
+ iovp = (struct iovec *)gluten_ptr(&g->g, iov);
+ iovp->iov_base = (void *)(intptr_t)base_offset->offset;
+ gluten_relocation_add(g, iov);
+
+ iovp->iov_len = f->size;
+
+ *msg_iov = iov.offset;
+ gluten_relocation_add(g, offset);
+
+ return v;
}
if (!jvalue && !(f->flags & SIZE))
return v;
+
switch (f->type) {
case USHORT:
case INT:
@@ -249,12 +279,28 @@ static union value parse_field(struct gluten_ctx *g, struct arg *args,
tmp1 = json_value_get_object(jvalue);
f_value = json_object_get_value(tmp1, f_inner->name);
- debug(" parse struct internal value:%s",
+ debug(" parse struct, field %s, internal value:%s",
+ f_inner->name,
json_serialize_to_string(f_value));
- if (!f_value)
+ if (!f_value && !(f_inner->flags & SIZE))
continue;
- parse_field(g, args, &struct_start, index, f_inner,
- f_value, false, add);
+
+ if (f_inner->size && f_inner->type == SELECT) {
+ struct gluten_offset ptr_offset;
+ intptr_t *link;
+
+ ptr_offset = gluten_rw_alloc(g, f_inner->size);
+ parse_field(g, args, &ptr_offset, index, f_inner,
+ f_value, false, add);
+
+ link = (intptr_t *)gluten_ptr(&g->g, offset);
+ *link = ptr_offset.offset;
+ gluten_relocation_add(g, offset);
+ } else {
+ parse_field(g, args, &struct_start, index, f_inner,
+ f_value, false, add);
+ }
+
if (base_offset->type == OFFSET_NULL)
*base_offset = struct_start;
}
@@ -278,6 +324,9 @@ bool arg_needs_temp(struct field *f, int pos, JSON_Value *jvalue,
if (f->flags & COPY_ON_CALL)
return true;
+ if (f->flags & IOV)
+ return true;
+
if (f->flags & SIZE)
return false;
diff --git a/cooker/calls/net.c b/cooker/calls/net.c
index a348037..94b13cd 100644
--- a/cooker/calls/net.c
+++ b/cooker/calls/net.c
@@ -79,6 +79,9 @@ static struct num protocols[] = {
{ "mpls", IPPROTO_MPLS },
{ "raw", IPPROTO_RAW },
{ "mptcp", IPPROTO_MPTCP },
+
+ { "nl_route", NETLINK_ROUTE },
+
{ 0 },
};
@@ -243,9 +246,265 @@ static struct arg connect_args[] = {
{ 0 }
};
+static struct num send_flags[] = {
+ { "confirm", MSG_CONFIRM },
+ { "dontroute", MSG_DONTROUTE },
+ { "dontwait", MSG_DONTWAIT },
+ { "eor", MSG_EOR },
+ { "more", MSG_MORE },
+ { "nosignal", MSG_NOSIGNAL },
+ { "oob", MSG_OOB },
+ { "fastopen", MSG_FASTOPEN },
+ { 0 },
+};
+
+static struct arg send_args[] = {
+ { 0,
+ {
+ "fd", INT, 0,
+ 0,
+ 0,
+ { 0 },
+ },
+ },
+ { 1,
+ {
+ "buf", STRING, WBUF,
+ 0,
+ BUFSIZ,
+ { 0 },
+ },
+ },
+ { 2,
+ {
+ "len", LONG, SIZE,
+ 0,
+ 0,
+ { .d_size = (intptr_t)&send_args[1] },
+ },
+ },
+ { 3,
+ {
+ "flags", INT, FLAGS,
+ 0,
+ 0,
+ { .d_num = send_flags }
+ }
+ },
+ { 0 }
+};
+
+static struct arg sendto_args[] = {
+ { 0,
+ {
+ "fd", INT, 0,
+ 0,
+ 0,
+ { 0 },
+ },
+ },
+ { 1,
+ {
+ "buf", STRING, WBUF,
+ 0,
+ BUFSIZ,
+ { 0 },
+ },
+ },
+ { 2,
+ {
+ "len", LONG, SIZE,
+ 0,
+ 0,
+ { .d_size = (intptr_t)&sendto_args[1] },
+ },
+ },
+ { 3,
+ {
+ "flags", INT, FLAGS,
+ 0,
+ 0,
+ { .d_num = send_flags }
+ }
+ },
+ { 4,
+ {
+ "addr", SELECT, 0,
+ 0,
+ sizeof(struct sockaddr_storage),
+ { .d_select = &connect_addr_select },
+ },
+ },
+ { 5,
+ {
+ "addrlen", LONG, SIZE,
+ 0,
+ 0,
+ { .d_size = (intptr_t)&connect_addr_select },
+ },
+ },
+ { 0 }
+};
+
+static struct select sendmsg_name_select = {
+ &connect_family, { .d_num = connect_addr_select_family }
+};
+
+static struct field sendmsg_msghdr[] = {
+ {
+ "name", SELECT, 0,
+ offsetof(struct msghdr, msg_name),
+ sizeof(struct sockaddr_storage),
+ { .d_select = &sendmsg_name_select },
+ },
+ {
+ "namelen", LONG, SIZE,
+ offsetof(struct msghdr, msg_namelen),
+ 0,
+ { .d_size = (intptr_t)&sendmsg_name_select },
+ },
+ {
+ "iov", STRING, WBUF | IOV,
+ offsetof(struct msghdr, msg_iov),
+ BUFSIZ,
+ { .d_iovlen = offsetof(struct msghdr, msg_iovlen) -
+ offsetof(struct msghdr, msg_iov) },
+ },
+ {
+ "iovlen", LONG, 0,
+ offsetof(struct msghdr, msg_iovlen),
+ 0,
+ { 0 },
+ },
+ {
+ "control", STRING, 0,
+ offsetof(struct msghdr, msg_control),
+ BUFSIZ,
+ { 0 },
+ },
+ {
+ "controllen", LONG, SIZE,
+ offsetof(struct msghdr, msg_controllen),
+ 0,
+ { 0 },
+ },
+ {
+ "flags", INT, 0,
+ offsetof(struct msghdr, msg_flags),
+ 0,
+ { 0 },
+ },
+ { 0 }
+};
+
+static struct arg sendmsg_args[] = {
+ { 0,
+ {
+ "fd", INT, 0,
+ 0,
+ 0,
+ { 0 },
+ },
+ },
+ { 1,
+ {
+ "msg", STRUCT, 0,
+ 0,
+ sizeof(struct msghdr),
+ { .d_struct = sendmsg_msghdr },
+ },
+ },
+ { 2,
+ {
+ "flags", INT, FLAGS,
+ 0,
+ 0,
+ { .d_num = send_flags }
+ }
+ },
+ { 0 }
+};
+
+static struct arg recvmsg_args[] = {
+ { 0,
+ {
+ "fd", INT, 0,
+ 0,
+ 0,
+ { 0 },
+ },
+ },
+ { 1,
+ {
+ "msg", STRUCT, 0,
+ 0,
+ sizeof(struct msghdr),
+ { .d_struct = sendmsg_msghdr },
+ },
+ },
+ { 2,
+ {
+ "flags", INT, FLAGS,
+ 0,
+ 0,
+ { .d_num = send_flags }
+ }
+ },
+ { 0 }
+};
+
+static struct arg setsockopt_args[] = {
+ { 0,
+ {
+ "fd", INT, 0,
+ 0,
+ 0,
+ { 0 },
+ },
+ },
+ { 1,
+ {
+ "level", INT, 0,
+ 0,
+ 0,
+ { 0 },
+ },
+ },
+ { 2,
+ {
+ "optname", INT, 0,
+ 0,
+ 0,
+ { 0 },
+ },
+ },
+ { 3,
+ {
+ "optval", INT, 0,
+ 0,
+ BUFSIZ,
+ { 0 },
+ },
+ },
+ { 4,
+ {
+ "optlen", INT, 0,
+ 0,
+ 0,
+ { 0 },
+ },
+ },
+ { 0 }
+};
+
struct call syscalls_net[] = {
{ __NR_connect, "connect", connect_args },
{ __NR_bind, "bind", connect_args },
{ __NR_socket, "socket", socket_args },
+ /* { __NR_send, "send", send_args }, */
+ { __NR_sendto, "sendto", sendto_args },
+ { __NR_sendmsg, "sendmsg", sendmsg_args },
+ { __NR_recvmsg, "recvmsg", recvmsg_args },
+ { __NR_setsockopt, "setsockopt", setsockopt_args },
{ 0 },
};
diff --git a/cooker/cooker.h b/cooker/cooker.h
index 9217c40..05a1f1b 100644
--- a/cooker/cooker.h
+++ b/cooker/cooker.h
@@ -35,13 +35,15 @@ struct size;
* @d_num: Pointer to a list of numbers and their labels
* @d_struct: Pointer to a struct description
* @d_select: Pointer to description of a selector
- * @d_arg_size: Position of argument whose pointed length is described
+ * @d_size: Position of argument whose pointed length is described
+ * @d_iovlen: Relative offset from pointed iovec field to corresponding iovlen
*/
union desc {
struct num *d_num;
struct field *d_struct;
struct select *d_select;
intptr_t d_size;
+ ptrdiff_t d_iovlen;
};
/**
@@ -110,6 +112,8 @@ enum flags {
RBUF = BIT(5),
/* Copy value from original call, ignore on return */
WBUF = BIT(6),
+
+ IOV = BIT(7),
};
#define TYPE_COUNT (TYPE_END - 1)
diff --git a/cooker/emit.c b/cooker/emit.c
index efe70eb..7899fa5 100644
--- a/cooker/emit.c
+++ b/cooker/emit.c
@@ -119,7 +119,7 @@ void emit_call(struct gluten_ctx *g, struct context_desc *cdesc, long nr,
memcpy(desc->args, offset, sizeof(struct gluten_offset) * count);
desc->args[count] = ret_offset;
- debug(" %i: OP_CALL: %s, arguments:", g->ip.offset, syscall_name_str[nr]);
+ debug(" %i: OP_CALL: %s, arguments:", g->ip.offset, syscall_name(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);
@@ -180,6 +180,42 @@ void emit_store(struct gluten_ctx *g, struct gluten_offset dst,
}
/**
+ * emit_iovload() - Emit OP_IOVLOAD instruction: IO vector from loaded pointers
+ * @g: gluten context
+ * @iov: Pointer to msg_iov, already stored in gluten
+ * @iovlen: Pointer to msg_iovlen, already stored in gluten
+ * @dst: gluten destination to copy dereferenced data
+ * @len: Maximum length of data to copy altogether
+ */
+struct gluten_offset emit_iovload(struct gluten_ctx *g,
+ struct gluten_offset iov,
+ struct gluten_offset iovlen,
+ size_t len)
+{
+ struct op *op = (struct op *)gluten_ptr(&g->g, g->ip);
+ struct op_iovload *load = &op->op.iovload;
+ struct gluten_offset dst;
+
+ dst = gluten_rw_alloc(g, len);
+
+ op->type = OP_IOVLOAD;
+
+ load->iov = iov;
+ load->iovlen = iovlen;
+
+ load->dst = dst;
+ load->size = len;
+
+ debug(" %i: OP_IOVLOAD: #%i < (#%i) as iovec (size: %lu)",
+ g->ip.offset, dst.offset, iov.offset, len);
+
+ if (++g->ip.offset > INST_MAX)
+ die("Too many instructions");
+
+ return dst;
+}
+
+/**
* emit_resolved() - Emit OP_RESOLVEFD instruction: resolve file descriptor with path
* @g: gluten context
* @fd: offset of the file descriptor value
diff --git a/cooker/emit.h b/cooker/emit.h
index 835aae7..5557187 100644
--- a/cooker/emit.h
+++ b/cooker/emit.h
@@ -13,6 +13,10 @@ void emit_call(struct gluten_ctx *g, struct context_desc *cdesc, 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_iovload(struct gluten_ctx *g,
+ struct gluten_offset iov,
+ struct gluten_offset iovlen,
+ size_t len);
void emit_store(struct gluten_ctx *g, struct gluten_offset dst,
struct gluten_offset src, struct gluten_offset count);
struct gluten_offset emit_seccomp_data(int index);
diff --git a/cooker/gluten.c b/cooker/gluten.c
index 4d3aea5..69c9384 100644
--- a/cooker/gluten.c
+++ b/cooker/gluten.c
@@ -146,6 +146,7 @@ void gluten_add_attr(struct gluten_ctx *g, enum attr_type type, intptr_t id,
union value gluten_get_attr(struct gluten_ctx *g, enum attr_type type,
intptr_t id)
{
+ union value missing = { 0 };
int i;
for (i = 0; i < ATTRS_MAX && g->attrs[i].type; i++) {
@@ -153,8 +154,8 @@ union value gluten_get_attr(struct gluten_ctx *g, enum attr_type type,
return g->attrs[i].v;
}
- die(" attribute '%p' not found", id);
- return g->attrs[0].v; /* Pro forma, not actually happening */
+ debug(" attribute '%p' not found", id);
+ return missing;
}
/**
@@ -163,8 +164,8 @@ union value gluten_get_attr(struct gluten_ctx *g, enum attr_type type,
*/
void gluten_init(struct gluten_ctx *g)
{
- g->ip.type = g->lr.type = g->mr.type = OFFSET_INSTRUCTION;
g->ip.offset = g->lr.offset = g->mr.offset = 0;
+ g->ip.type = g->lr.type = g->mr.type = OFFSET_INSTRUCTION;
g->dp.type = OFFSET_DATA;
g->cp.type = OFFSET_RO_DATA;
}
@@ -185,3 +186,12 @@ void gluten_write(struct gluten_ctx *g, const char *path)
close(fd);
}
+
+void gluten_relocation_add(struct gluten_ctx *g, struct gluten_offset offset)
+{
+ g->g.header.relocation[g->rel_count++] = offset;
+ debug(" Added relocation for %s: %u", gluten_offset_name[offset.type],
+ offset.offset);
+ if (g->rel_count >= 256)
+ die("Too many relocations");
+}
diff --git a/cooker/gluten.h b/cooker/gluten.h
index 4659583..4a3b3f0 100644
--- a/cooker/gluten.h
+++ b/cooker/gluten.h
@@ -44,6 +44,8 @@ struct gluten_ctx {
struct arg *selected_arg[6];
enum scmp_mode mode;
+
+ size_t rel_count;
};
/**
@@ -70,8 +72,8 @@ void gluten_add_attr(struct gluten_ctx *g, enum attr_type type, intptr_t id,
union value v);
union value gluten_get_attr(struct gluten_ctx *g, enum attr_type type,
intptr_t id);
+void gluten_relocation_add(struct gluten_ctx *g, struct gluten_offset offset);
void gluten_init(struct gluten_ctx *g);
-void gluten_block_init(struct gluten_ctx *g);
void gluten_write(struct gluten_ctx *g, const char *path);
extern size_t gluten_size[TYPE_COUNT];
diff --git a/cooker/match.c b/cooker/match.c
index 36ac9df..c56d9e5 100644
--- a/cooker/match.c
+++ b/cooker/match.c
@@ -19,6 +19,40 @@
#include "calls/net.h"
#include "seccomp_profile.h"
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+static struct num netlink_types[] = {
+ { "newroute", RTM_NEWROUTE },
+ { 0 },
+};
+
+static struct num netlink_flags[] = {
+ { "request", NLM_F_REQUEST },
+ { "create", NLM_F_CREATE },
+ { 0 },
+};
+
+static struct field netlink_header_fields[] = {
+ {
+ "type", USHORT, 0,
+ offsetof(struct nlmsghdr, nlmsg_type),
+ 0, { .d_num = netlink_types }
+ },
+ {
+ "flags", USHORT, FLAGS,
+ offsetof(struct nlmsghdr, nlmsg_flags),
+ 0, { .d_num = netlink_flags }
+ },
+ { 0 },
+};
+
+static struct field netlink_header = {
+ "netlink", STRUCT, 0, 0, 0,
+ { .d_struct = netlink_header_fields }
+};
+
/**
* arg_load() - Allocate and build bytecode for one syscall argument
* @g: gluten context
@@ -117,6 +151,15 @@ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
break;
}
+ offset.offset += f->offset;
+
+ if (f->flags & IOV) {
+ struct gluten_offset iovlen = offset;
+
+ iovlen.offset += f->desc.d_iovlen;
+ offset = emit_iovload(g, offset, iovlen, f->size);
+ }
+
if (json_value_get_type(jvalue) == JSONObject &&
(tmp = json_value_get_object(jvalue)) &&
(tag_name = json_object_get_string(tmp, "set"))) {
@@ -155,8 +198,6 @@ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
if (!jvalue || (f->flags & RBUF))
return v;
- offset.offset += f->offset;
-
switch (f->type) {
case USHORT:
case INT:
@@ -258,6 +299,17 @@ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
parse_field(g, offset, cmp, jump, index, f, jvalue);
break;
case STRING:
+ if (json_value_get_type(jvalue) == JSONObject &&
+ (tmp = json_value_get_object(jvalue))) {
+ if ((jvalue = json_object_get_value(tmp, "netlink"))) {
+ parse_field(g, offset, cmp, jump, index,
+ &netlink_header, jvalue);
+ } else {
+ die(" unrecognised blob type");
+ }
+ break;
+ }
+
if ((v.v_str = json_value_get_string(jvalue)) == NULL)
die(" failed parsing field for value:%s",
json_serialize_to_string_pretty(jvalue));
diff --git a/cooker/parse.c b/cooker/parse.c
index 5d5cab3..8d0c20d 100644
--- a/cooker/parse.c
+++ b/cooker/parse.c
@@ -201,14 +201,14 @@ struct rule_parser {
static union value value_get_set(struct num *desc, JSON_Array *set)
{
+ union value n = { 0 };
struct num *tmp;
- union value n;
unsigned i;
for (i = 0; i < json_array_get_count(set); i++) {
for (tmp = desc; tmp->name; tmp++) {
if (!strcmp(tmp->name, json_array_get_string(set, i))) {
- n.v_num |= desc->value;
+ n.v_num |= tmp->value;
break;
}
}
@@ -364,6 +364,8 @@ static void parse_block(struct gluten_ctx *g, JSON_Object *block)
unsigned i;
memset(g->selected_arg, 0, sizeof(g->selected_arg));
+ memset(g->match_dst, 0, sizeof(g->match_dst));
+ memset(g->call_src, 0, sizeof(g->call_src));
memset(g->tags, 0, sizeof(g->tags));
g->lr = g->ip;