aboutgitcodelistschat:MatrixIRC
path: root/operations.c
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2024-08-13 18:50:33 +0200
committerStefano Brivio <sbrivio@redhat.com>2024-08-13 19:00:35 +0200
commit9bf3b1cc7a94357c250f77f16829c96cbae801fe (patch)
tree56cbc184974b18d33aa288dda7b12e5a77c38a94 /operations.c
parentd699dac08778c597eefac1067a325059925e87e6 (diff)
downloadseitan-9bf3b1cc7a94357c250f77f16829c96cbae801fe.tar
seitan-9bf3b1cc7a94357c250f77f16829c96cbae801fe.tar.gz
seitan-9bf3b1cc7a94357c250f77f16829c96cbae801fe.tar.bz2
seitan-9bf3b1cc7a94357c250f77f16829c96cbae801fe.tar.lz
seitan-9bf3b1cc7a94357c250f77f16829c96cbae801fe.tar.xz
seitan-9bf3b1cc7a94357c250f77f16829c96cbae801fe.tar.zst
seitan-9bf3b1cc7a94357c250f77f16829c96cbae801fe.zip
call, emit, match: Add support for vectorised operations, nfnetlinkHEADmaster
We want to add and delete rules with iptables(8), and manipulate set elements with nft(8). These are the first users we encounter sending multiple netlink messages in one sendmsg(). To support matching on those, we need to iterate over several messages, looking for a matching one, or a mismatching one (depending on quantifiers and match type), but we don't want to implement program loops because of security design reasons. We can't implement a generalised instruction that vectorises existing ones, either, because we need to support universal and existential quantifiers in fields that are repeated multiple times, once per each netlink message, with bitwise operations and non-exact matching types. Add vectorisation support to OP_CMP and OP_BITWISE instead, with a generic description for a vector (only sequences of netlink messages with length in nlmsghdr are supported at the moment) so that, depending on the quantifiers, we'll repeat those operations as many times as needed. This way, we don't risk any O(n^2) explosion, and we are bound by O(m * n) instead, with m compare/bitwise operations for a given expression, and n number of netlink messages. Add demos for nft and iptables using the new concepts. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'operations.c')
-rw-r--r--operations.c149
1 files changed, 119 insertions, 30 deletions
diff --git a/operations.c b/operations.c
index eb8d614..4438879 100644
--- a/operations.c
+++ b/operations.c
@@ -459,6 +459,8 @@ int op_iovload(const struct seccomp_notif *req, int notifier, struct gluten *g,
close(fd);
+ memset(dst + count, 0, load->size - count + load->zero_fill);
+
return 0;
}
@@ -592,8 +594,11 @@ int op_bitwise(const struct seccomp_notif *req, int notifier, struct gluten *g,
struct op_bitwise *op)
{
const struct bitwise_desc *desc = gluten_ptr(&req->data, g, op->desc);
- const unsigned char *x, *y;
- unsigned char *dst;
+ const struct vec_desc vec = desc->vec;
+ const unsigned char *x_ptr, *y_ptr;
+ struct gluten_offset x, dst;
+ unsigned char *dst_ptr;
+ uint32_t *vlen;
unsigned i;
(void)notifier;
@@ -601,10 +606,6 @@ int op_bitwise(const struct seccomp_notif *req, int notifier, struct gluten *g,
if (!desc)
return -1;
- dst = gluten_write_ptr( g, desc->dst);
- x = gluten_ptr(&req->data, g, desc->x);
- y = gluten_ptr(&req->data, g, desc->y);
-
/*
if (!dst || !src || !mask ||
!check_gluten_limits(desc->dst, desc->size) ||
@@ -612,6 +613,7 @@ int op_bitwise(const struct seccomp_notif *req, int notifier, struct gluten *g,
!check_gluten_limits(desc->mask, desc->size))
return -1;
*/
+
debug(" op_bitwise: dst=(%s %d) := x=(%s %d) %s y=(%s %d) size=%d",
gluten_offset_name[desc->dst.type], desc->dst.offset,
gluten_offset_name[desc->x.type], desc->x.offset,
@@ -619,13 +621,37 @@ int op_bitwise(const struct seccomp_notif *req, int notifier, struct gluten *g,
gluten_offset_name[desc->y.type], desc->y.offset,
desc->size);
- for (i = 0; i < desc->size; i++) {
- if (desc->type == BITWISE_AND)
- dst[i] = x[i] & y[i];
- else if (desc->type == BITWISE_OR)
- dst[i] = x[i] | y[i];
- else
- return -1;
+ if (vec.start.type != OFFSET_NULL) {
+ debug(" vector start=(%s %d), length offset: %i",
+ gluten_offset_name[vec.start.type], vec.start.offset,
+ vec.len_offset);
+ }
+
+ if (vec.start.type == OFFSET_NULL)
+ vlen = &((uint32_t){ 1 });
+ else
+ vlen = (uint32_t *)gluten_ptr(&req->data, g, vec.start);
+
+ y_ptr = gluten_ptr(&req->data, g, desc->y);
+
+ for (x = desc->x, dst = desc->dst;
+ *vlen;
+ x.offset += *vlen, vlen += *vlen, dst.offset += desc->size) {
+
+ x_ptr = gluten_ptr(&req->data, g, x);
+ dst_ptr = gluten_write_ptr( g, dst);
+
+ for (i = 0; i < desc->size; i++) {
+ if (desc->type == BITWISE_AND)
+ dst_ptr[i] = x_ptr[i] & y_ptr[i];
+ else if (desc->type == BITWISE_OR)
+ dst_ptr[i] = x_ptr[i] | y_ptr[i];
+ else
+ return -1;
+ }
+
+ if (vec.start.type == OFFSET_NULL)
+ break;
}
return 0;
@@ -683,9 +709,13 @@ int op_cmp(const struct seccomp_notif *req, int notifier, struct gluten *g,
struct op_cmp *op)
{
const struct cmp_desc *desc = gluten_ptr(&req->data, g, op->desc);
+ bool some = false, all = true, verdict;
+ const struct vec_desc vec = desc->vec;
char str_x[PATH_MAX], str_y[PATH_MAX];
+ const void *x_ptr, *y_ptr;
+ struct gluten_offset x;
enum op_cmp_type cmp;
- const void *px, *py;
+ uint32_t *vlen;
int res;
(void)notifier;
@@ -693,29 +723,88 @@ int op_cmp(const struct seccomp_notif *req, int notifier, struct gluten *g,
if (!desc)
return -1;
- px = gluten_ptr(&req->data, g, desc->x);
- py = gluten_ptr(&req->data, g, desc->y);
- cmp = desc->cmp;
-
- if (!px || !py ||
- !check_gluten_limits(desc->x, desc->size) ||
- !check_gluten_limits(desc->y, desc->size))
- return -1;
str_offset_value(req, g, &desc->x, desc->size, str_x, PATH_MAX);
str_offset_value(req, g, &desc->y, desc->size, str_y, PATH_MAX);
debug(" op_cmp: operands x=%s y=%s", str_x, str_y);
- res = memcmp(px, py, desc->size);
+ if (vec.start.type != OFFSET_NULL) {
+ debug(" vector start=(%s %d), length offset: %i",
+ gluten_offset_name[vec.start.type], vec.start.offset,
+ vec.len_offset);
+ }
+
+ if (vec.start.type == OFFSET_NULL)
+ vlen = &((uint32_t){ 1 });
+ else
+ vlen = (uint32_t *)gluten_ptr(&req->data, g, vec.start);
+
+ y_ptr = gluten_ptr(&req->data, g, desc->y);
- if ((res == 0 && (cmp == CMP_EQ || cmp == CMP_LE || cmp == CMP_GE)) ||
- (res < 0 && (cmp == CMP_LT || cmp == CMP_LE)) ||
- (res > 0 && (cmp == CMP_GT || cmp == CMP_GE)) ||
- (res != 0 && (cmp == CMP_NE))) {
- debug(" op_cmp: successful comparison, jump to %d",
- desc->jmp.offset);
+ if (!y_ptr || !check_gluten_limits(desc->y, desc->size))
+ return -1;
+
+ cmp = desc->cmp;
+
+ for (x = desc->x;
+ *vlen;
+ x.offset += *vlen, vlen = (uint32_t *)((uint8_t *)vlen + *vlen)) {
+ unsigned char *c;
+ int __i;
+
+ debug(" in loop, vlen: %u", *vlen);
+
+ x_ptr = gluten_ptr(&req->data, g, x);
+
+ if (!x_ptr || !check_gluten_limits(x, desc->size))
+ return -1;
+
+ debug(" in loop #2");
+
+ res = memcmp(x_ptr, y_ptr, desc->size);
+
+ debug("=== x: %04x, y: %04x", *(uint16_t *)x_ptr, *(uint16_t *)y_ptr);
+
+ c = (unsigned char *)x_ptr;
+ for (__i = 0; __i < 32; __i += 4)
+ debug("%02x %02x %02x %02x", c[__i], c[__i + 1], c[__i + 2], c[__i + 3]);
+
+ if ((res == 0 &&
+ (cmp == CMP_EQ || cmp == CMP_LE || cmp == CMP_GE)) ||
+ (res < 0 &&
+ (cmp == CMP_LT || cmp == CMP_LE)) ||
+ (res > 0 &&
+ (cmp == CMP_GT || cmp == CMP_GE)) ||
+ (res != 0 &&
+ (cmp == CMP_NE)))
+ some = true;
+ else
+ all = false;
+
+ if (vec.start.type == OFFSET_NULL)
+ break;
+
+ debug(" in loop #3");
+ }
+
+ /* FIXME: vectors always imply the existential quantifier for now:
+ * CMP_NE and all non-equal: jump
+ * CMP_EQ and some equal: jump
+ */
+ if (vec.start.type == OFFSET_NULL)
+ verdict = some;
+ else if (cmp == CMP_NE)
+ verdict = all;
+ else
+ verdict = some;
+
+ debug(" op_cmp: comparison: %s for some, %s for all, verdict: %s",
+ some ? "true" : "false", all ? "true" : "false",
+ verdict ? "true" : "false");
+
+ if (verdict) {
+ debug(" -> jump to %d", desc->jmp.offset);
return desc->jmp.offset;
}
- debug(" op_cmp: comparison is false");
return 0;
}