|
|
b59ec1 |
From 72f0ca53bcc6586b921ff70dac9f3a911e4ec170 Mon Sep 17 00:00:00 2001
|
|
|
b59ec1 |
From: Phil Sutter <psutter@redhat.com>
|
|
|
b59ec1 |
Date: Thu, 9 Feb 2023 10:27:57 +0100
|
|
|
b59ec1 |
Subject: [PATCH] proto: track full stack of seen l2 protocols, not just
|
|
|
b59ec1 |
cumulative offset
|
|
|
b59ec1 |
|
|
|
b59ec1 |
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2094887
|
|
|
b59ec1 |
Upstream Status: nftables commit 0d9daa0407212
|
|
|
b59ec1 |
|
|
|
b59ec1 |
commit 0d9daa0407212c8cc89b3ea8aee031ddf0109b08
|
|
|
b59ec1 |
Author: Florian Westphal <fw@strlen.de>
|
|
|
b59ec1 |
Date: Mon Jul 25 14:32:13 2022 +0200
|
|
|
b59ec1 |
|
|
|
b59ec1 |
proto: track full stack of seen l2 protocols, not just cumulative offset
|
|
|
b59ec1 |
|
|
|
b59ec1 |
For input, a cumulative size counter of all pushed l2 headers is enough,
|
|
|
b59ec1 |
because we have the full expression tree available to us.
|
|
|
b59ec1 |
|
|
|
b59ec1 |
For delinearization we need to track all seen l2 headers, else we lose
|
|
|
b59ec1 |
information that we might need at a later time.
|
|
|
b59ec1 |
|
|
|
b59ec1 |
Consider:
|
|
|
b59ec1 |
|
|
|
b59ec1 |
rule netdev nt nc set update ether saddr . vlan id
|
|
|
b59ec1 |
|
|
|
b59ec1 |
during delinearization, the vlan proto_desc replaces the ethernet one,
|
|
|
b59ec1 |
and by the time we try to split the concatenation apart we will search
|
|
|
b59ec1 |
the ether saddr offset vs. the templates for proto_vlan.
|
|
|
b59ec1 |
|
|
|
b59ec1 |
This replaces the offset with an array that stores the protocol
|
|
|
b59ec1 |
descriptions seen.
|
|
|
b59ec1 |
|
|
|
b59ec1 |
Then, if the payload offset is larger than our description, search the
|
|
|
b59ec1 |
l2 stack and adjust the offset until we're within the expected offset
|
|
|
b59ec1 |
boundary.
|
|
|
b59ec1 |
|
|
|
b59ec1 |
Reported-by: Eric Garver <eric@garver.life>
|
|
|
b59ec1 |
Signed-off-by: Florian Westphal <fw@strlen.de>
|
|
|
b59ec1 |
|
|
|
b59ec1 |
Signed-off-by: Phil Sutter <psutter@redhat.com>
|
|
|
b59ec1 |
---
|
|
|
b59ec1 |
include/proto.h | 3 +-
|
|
|
b59ec1 |
src/evaluate.c | 15 +++++++--
|
|
|
b59ec1 |
src/netlink_delinearize.c | 5 ---
|
|
|
b59ec1 |
src/payload.c | 67 ++++++++++++++++++++++++++++++++-------
|
|
|
b59ec1 |
src/proto.c | 2 --
|
|
|
b59ec1 |
5 files changed, 71 insertions(+), 21 deletions(-)
|
|
|
b59ec1 |
|
|
|
b59ec1 |
diff --git a/include/proto.h b/include/proto.h
|
|
|
b59ec1 |
index a04240a..35e760c 100644
|
|
|
b59ec1 |
--- a/include/proto.h
|
|
|
b59ec1 |
+++ b/include/proto.h
|
|
|
b59ec1 |
@@ -193,13 +193,14 @@ struct proto_ctx {
|
|
|
b59ec1 |
struct {
|
|
|
b59ec1 |
struct location location;
|
|
|
b59ec1 |
const struct proto_desc *desc;
|
|
|
b59ec1 |
- unsigned int offset;
|
|
|
b59ec1 |
struct {
|
|
|
b59ec1 |
struct location location;
|
|
|
b59ec1 |
const struct proto_desc *desc;
|
|
|
b59ec1 |
} protos[PROTO_CTX_NUM_PROTOS];
|
|
|
b59ec1 |
unsigned int num_protos;
|
|
|
b59ec1 |
} protocol[PROTO_BASE_MAX + 1];
|
|
|
b59ec1 |
+ const struct proto_desc *stacked_ll[PROTO_CTX_NUM_PROTOS];
|
|
|
b59ec1 |
+ uint8_t stacked_ll_count;
|
|
|
b59ec1 |
};
|
|
|
b59ec1 |
|
|
|
b59ec1 |
extern void proto_ctx_init(struct proto_ctx *ctx, unsigned int family,
|
|
|
b59ec1 |
diff --git a/src/evaluate.c b/src/evaluate.c
|
|
|
b59ec1 |
index 82bf131..9246064 100644
|
|
|
b59ec1 |
--- a/src/evaluate.c
|
|
|
b59ec1 |
+++ b/src/evaluate.c
|
|
|
b59ec1 |
@@ -678,7 +678,13 @@ static int resolve_protocol_conflict(struct eval_ctx *ctx,
|
|
|
b59ec1 |
conflict_resolution_gen_dependency(ctx, link, payload, &nstmt) < 0)
|
|
|
b59ec1 |
return 1;
|
|
|
b59ec1 |
|
|
|
b59ec1 |
- payload->payload.offset += ctx->pctx.protocol[base].offset;
|
|
|
b59ec1 |
+ if (base == PROTO_BASE_LL_HDR) {
|
|
|
b59ec1 |
+ unsigned int i;
|
|
|
b59ec1 |
+
|
|
|
b59ec1 |
+ for (i = 0; i < ctx->pctx.stacked_ll_count; i++)
|
|
|
b59ec1 |
+ payload->payload.offset += ctx->pctx.stacked_ll[i]->length;
|
|
|
b59ec1 |
+ }
|
|
|
b59ec1 |
+
|
|
|
b59ec1 |
rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
|
|
|
b59ec1 |
|
|
|
b59ec1 |
return 0;
|
|
|
b59ec1 |
@@ -727,7 +733,12 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr)
|
|
|
b59ec1 |
if (desc == payload->payload.desc) {
|
|
|
b59ec1 |
const struct proto_hdr_template *tmpl;
|
|
|
b59ec1 |
|
|
|
b59ec1 |
- payload->payload.offset += ctx->pctx.protocol[base].offset;
|
|
|
b59ec1 |
+ if (desc->base == PROTO_BASE_LL_HDR) {
|
|
|
b59ec1 |
+ unsigned int i;
|
|
|
b59ec1 |
+
|
|
|
b59ec1 |
+ for (i = 0; i < ctx->pctx.stacked_ll_count; i++)
|
|
|
b59ec1 |
+ payload->payload.offset += ctx->pctx.stacked_ll[i]->length;
|
|
|
b59ec1 |
+ }
|
|
|
b59ec1 |
check_icmp:
|
|
|
b59ec1 |
if (desc != &proto_icmp && desc != &proto_icmp6)
|
|
|
b59ec1 |
return 0;
|
|
|
b59ec1 |
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
|
|
|
b59ec1 |
index cba419d..0b5519d 100644
|
|
|
b59ec1 |
--- a/src/netlink_delinearize.c
|
|
|
b59ec1 |
+++ b/src/netlink_delinearize.c
|
|
|
b59ec1 |
@@ -1976,11 +1976,6 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx,
|
|
|
b59ec1 |
struct expr *expr,
|
|
|
b59ec1 |
struct expr *payload)
|
|
|
b59ec1 |
{
|
|
|
b59ec1 |
- enum proto_bases base = payload->payload.base;
|
|
|
b59ec1 |
-
|
|
|
b59ec1 |
- assert(payload->payload.offset >= ctx->pctx.protocol[base].offset);
|
|
|
b59ec1 |
- payload->payload.offset -= ctx->pctx.protocol[base].offset;
|
|
|
b59ec1 |
-
|
|
|
b59ec1 |
switch (expr->op) {
|
|
|
b59ec1 |
case OP_EQ:
|
|
|
b59ec1 |
case OP_NEQ:
|
|
|
b59ec1 |
diff --git a/src/payload.c b/src/payload.c
|
|
|
b59ec1 |
index 66418cd..2c0d0ac 100644
|
|
|
b59ec1 |
--- a/src/payload.c
|
|
|
b59ec1 |
+++ b/src/payload.c
|
|
|
b59ec1 |
@@ -116,8 +116,13 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx,
|
|
|
b59ec1 |
if (desc->base == base->base) {
|
|
|
b59ec1 |
assert(base->length > 0);
|
|
|
b59ec1 |
|
|
|
b59ec1 |
- if (!left->payload.is_raw)
|
|
|
b59ec1 |
- ctx->protocol[base->base].offset += base->length;
|
|
|
b59ec1 |
+ if (!left->payload.is_raw) {
|
|
|
b59ec1 |
+ if (desc->base == PROTO_BASE_LL_HDR &&
|
|
|
b59ec1 |
+ ctx->stacked_ll_count < PROTO_CTX_NUM_PROTOS) {
|
|
|
b59ec1 |
+ ctx->stacked_ll[ctx->stacked_ll_count] = base;
|
|
|
b59ec1 |
+ ctx->stacked_ll_count++;
|
|
|
b59ec1 |
+ }
|
|
|
b59ec1 |
+ }
|
|
|
b59ec1 |
}
|
|
|
b59ec1 |
proto_ctx_update(ctx, desc->base, loc, desc);
|
|
|
b59ec1 |
}
|
|
|
b59ec1 |
@@ -869,6 +874,38 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
|
|
|
b59ec1 |
}
|
|
|
b59ec1 |
}
|
|
|
b59ec1 |
|
|
|
b59ec1 |
+static const struct proto_desc *get_stacked_desc(const struct proto_ctx *ctx,
|
|
|
b59ec1 |
+ const struct proto_desc *top,
|
|
|
b59ec1 |
+ const struct expr *e,
|
|
|
b59ec1 |
+ unsigned int *skip)
|
|
|
b59ec1 |
+{
|
|
|
b59ec1 |
+ unsigned int i, total, payload_offset = e->payload.offset;
|
|
|
b59ec1 |
+
|
|
|
b59ec1 |
+ assert(e->etype == EXPR_PAYLOAD);
|
|
|
b59ec1 |
+
|
|
|
b59ec1 |
+ if (e->payload.base != PROTO_BASE_LL_HDR ||
|
|
|
b59ec1 |
+ payload_offset < top->length) {
|
|
|
b59ec1 |
+ *skip = 0;
|
|
|
b59ec1 |
+ return top;
|
|
|
b59ec1 |
+ }
|
|
|
b59ec1 |
+
|
|
|
b59ec1 |
+ for (i = 0, total = 0; i < ctx->stacked_ll_count; i++) {
|
|
|
b59ec1 |
+ const struct proto_desc *stacked;
|
|
|
b59ec1 |
+
|
|
|
b59ec1 |
+ stacked = ctx->stacked_ll[i];
|
|
|
b59ec1 |
+ if (payload_offset < stacked->length) {
|
|
|
b59ec1 |
+ *skip = total;
|
|
|
b59ec1 |
+ return stacked;
|
|
|
b59ec1 |
+ }
|
|
|
b59ec1 |
+
|
|
|
b59ec1 |
+ payload_offset -= stacked->length;
|
|
|
b59ec1 |
+ total += stacked->length;
|
|
|
b59ec1 |
+ }
|
|
|
b59ec1 |
+
|
|
|
b59ec1 |
+ *skip = total;
|
|
|
b59ec1 |
+ return top;
|
|
|
b59ec1 |
+}
|
|
|
b59ec1 |
+
|
|
|
b59ec1 |
/**
|
|
|
b59ec1 |
* payload_expr_complete - fill in type information of a raw payload expr
|
|
|
b59ec1 |
*
|
|
|
b59ec1 |
@@ -880,9 +917,10 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
|
|
|
b59ec1 |
*/
|
|
|
b59ec1 |
void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx)
|
|
|
b59ec1 |
{
|
|
|
b59ec1 |
+ unsigned int payload_offset = expr->payload.offset;
|
|
|
b59ec1 |
const struct proto_desc *desc;
|
|
|
b59ec1 |
const struct proto_hdr_template *tmpl;
|
|
|
b59ec1 |
- unsigned int i;
|
|
|
b59ec1 |
+ unsigned int i, total;
|
|
|
b59ec1 |
|
|
|
b59ec1 |
assert(expr->etype == EXPR_PAYLOAD);
|
|
|
b59ec1 |
|
|
|
b59ec1 |
@@ -891,9 +929,12 @@ void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx)
|
|
|
b59ec1 |
return;
|
|
|
b59ec1 |
assert(desc->base == expr->payload.base);
|
|
|
b59ec1 |
|
|
|
b59ec1 |
+ desc = get_stacked_desc(ctx, desc, expr, &total);
|
|
|
b59ec1 |
+ payload_offset -= total;
|
|
|
b59ec1 |
+
|
|
|
b59ec1 |
for (i = 0; i < array_size(desc->templates); i++) {
|
|
|
b59ec1 |
tmpl = &desc->templates[i];
|
|
|
b59ec1 |
- if (tmpl->offset != expr->payload.offset ||
|
|
|
b59ec1 |
+ if (tmpl->offset != payload_offset ||
|
|
|
b59ec1 |
tmpl->len != expr->len)
|
|
|
b59ec1 |
continue;
|
|
|
b59ec1 |
|
|
|
b59ec1 |
@@ -950,6 +991,7 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask,
|
|
|
b59ec1 |
unsigned int payload_len = expr->len;
|
|
|
b59ec1 |
const struct proto_desc *desc;
|
|
|
b59ec1 |
unsigned int off, i, len = 0;
|
|
|
b59ec1 |
+ unsigned int total;
|
|
|
b59ec1 |
|
|
|
b59ec1 |
assert(expr->etype == EXPR_PAYLOAD);
|
|
|
b59ec1 |
|
|
|
b59ec1 |
@@ -959,10 +1001,8 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask,
|
|
|
b59ec1 |
|
|
|
b59ec1 |
assert(desc->base == expr->payload.base);
|
|
|
b59ec1 |
|
|
|
b59ec1 |
- if (ctx->protocol[expr->payload.base].offset) {
|
|
|
b59ec1 |
- assert(payload_offset >= ctx->protocol[expr->payload.base].offset);
|
|
|
b59ec1 |
- payload_offset -= ctx->protocol[expr->payload.base].offset;
|
|
|
b59ec1 |
- }
|
|
|
b59ec1 |
+ desc = get_stacked_desc(ctx, desc, expr, &total);
|
|
|
b59ec1 |
+ payload_offset -= total;
|
|
|
b59ec1 |
|
|
|
b59ec1 |
off = round_up(mask->len, BITS_PER_BYTE) - mask_len;
|
|
|
b59ec1 |
payload_offset += off;
|
|
|
b59ec1 |
@@ -1009,10 +1049,11 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask,
|
|
|
b59ec1 |
void payload_expr_expand(struct list_head *list, struct expr *expr,
|
|
|
b59ec1 |
const struct proto_ctx *ctx)
|
|
|
b59ec1 |
{
|
|
|
b59ec1 |
+ unsigned int payload_offset = expr->payload.offset;
|
|
|
b59ec1 |
const struct proto_hdr_template *tmpl;
|
|
|
b59ec1 |
const struct proto_desc *desc;
|
|
|
b59ec1 |
+ unsigned int i, total;
|
|
|
b59ec1 |
struct expr *new;
|
|
|
b59ec1 |
- unsigned int i;
|
|
|
b59ec1 |
|
|
|
b59ec1 |
assert(expr->etype == EXPR_PAYLOAD);
|
|
|
b59ec1 |
|
|
|
b59ec1 |
@@ -1021,13 +1062,16 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
|
|
|
b59ec1 |
goto raw;
|
|
|
b59ec1 |
assert(desc->base == expr->payload.base);
|
|
|
b59ec1 |
|
|
|
b59ec1 |
+ desc = get_stacked_desc(ctx, desc, expr, &total);
|
|
|
b59ec1 |
+ payload_offset -= total;
|
|
|
b59ec1 |
+
|
|
|
b59ec1 |
for (i = 1; i < array_size(desc->templates); i++) {
|
|
|
b59ec1 |
tmpl = &desc->templates[i];
|
|
|
b59ec1 |
|
|
|
b59ec1 |
if (tmpl->len == 0)
|
|
|
b59ec1 |
break;
|
|
|
b59ec1 |
|
|
|
b59ec1 |
- if (tmpl->offset != expr->payload.offset)
|
|
|
b59ec1 |
+ if (tmpl->offset != payload_offset)
|
|
|
b59ec1 |
continue;
|
|
|
b59ec1 |
|
|
|
b59ec1 |
if (tmpl->icmp_dep && ctx->th_dep.icmp.type &&
|
|
|
b59ec1 |
@@ -1039,6 +1083,7 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
|
|
|
b59ec1 |
list_add_tail(&new->list, list);
|
|
|
b59ec1 |
expr->len -= tmpl->len;
|
|
|
b59ec1 |
expr->payload.offset += tmpl->len;
|
|
|
b59ec1 |
+ payload_offset += tmpl->len;
|
|
|
b59ec1 |
if (expr->len == 0)
|
|
|
b59ec1 |
return;
|
|
|
b59ec1 |
} else if (expr->len > 0) {
|
|
|
b59ec1 |
@@ -1051,7 +1096,7 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
|
|
|
b59ec1 |
}
|
|
|
b59ec1 |
raw:
|
|
|
b59ec1 |
new = payload_expr_alloc(&expr->location, NULL, 0);
|
|
|
b59ec1 |
- payload_init_raw(new, expr->payload.base, expr->payload.offset,
|
|
|
b59ec1 |
+ payload_init_raw(new, expr->payload.base, payload_offset,
|
|
|
b59ec1 |
expr->len);
|
|
|
b59ec1 |
list_add_tail(&new->list, list);
|
|
|
b59ec1 |
}
|
|
|
b59ec1 |
diff --git a/src/proto.c b/src/proto.c
|
|
|
b59ec1 |
index a013a00..2663f21 100644
|
|
|
b59ec1 |
--- a/src/proto.c
|
|
|
b59ec1 |
+++ b/src/proto.c
|
|
|
b59ec1 |
@@ -160,8 +160,6 @@ static void proto_ctx_debug(const struct proto_ctx *ctx, enum proto_bases base,
|
|
|
b59ec1 |
proto_base_names[i],
|
|
|
b59ec1 |
ctx->protocol[i].desc ? ctx->protocol[i].desc->name :
|
|
|
b59ec1 |
"none");
|
|
|
b59ec1 |
- if (ctx->protocol[i].offset)
|
|
|
b59ec1 |
- pr_debug(" (offset: %u)", ctx->protocol[i].offset);
|
|
|
b59ec1 |
if (i == base)
|
|
|
b59ec1 |
pr_debug(" <-");
|
|
|
b59ec1 |
pr_debug("\n");
|
|
|
b59ec1 |
--
|
|
|
b59ec1 |
2.39.1
|
|
|
b59ec1 |
|