]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
meta: stash context statement length when generating payload/meta dependency
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 18 Jul 2023 21:10:01 +0000 (23:10 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 23 Jan 2025 00:35:36 +0000 (01:35 +0100)
commit 5f1676ac9f1aeb36d7695c3c354dade013a1e4f3 upstream.

... meta mark set ip dscp

generates an implicit dependency from the inet family to match on meta
nfproto ip.

The length of this implicit expression is incorrectly adjusted to the
statement length, ie. relational to compare meta nfproto takes 4 bytes
instead of 1 byte. The evaluation of 'ip dscp' under the meta mark
statement triggers this implicit dependency which should not consider
the context statement length since it is added before the statement
itself.

This problem shows when listing the ruleset, since netlink_parse_cmp()
where left->len < right->len, hence handling the implicit dependency as
a concatenation, but it is actually a bug in the evaluation step that
leads to incorrect bytecode.

Fixes: 3c64ea7995cb ("evaluate: honor statement length in integer evaluation")
Fixes: edecd58755a8 ("evaluate: support shifts larger than the width of the left operand")
Tested-by: Brian Davidson <davidson.brian@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/payload.c

index 43e3c30eee460667ab1567f94e07fa8b77ce0d98..563e926fd3e54652522995e0d2fdf7674fe8f883 100644 (file)
@@ -389,9 +389,11 @@ static int payload_add_dependency(struct eval_ctx *ctx,
 {
        const struct proto_hdr_template *tmpl;
        struct expr *dep, *left, *right;
+       unsigned int stmt_len;
        struct stmt *stmt;
-       int protocol = proto_find_num(desc, upper);
+       int protocol;
 
+       protocol = proto_find_num(desc, upper);
        if (protocol < 0)
                return expr_error(ctx->msgs, expr,
                                  "conflicting protocols specified: %s vs. %s",
@@ -408,11 +410,17 @@ static int payload_add_dependency(struct eval_ctx *ctx,
                                    constant_data_ptr(protocol, tmpl->len));
 
        dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
+
+       stmt_len = ctx->stmt_len;
+       ctx->stmt_len = 0;
+
        stmt = expr_stmt_alloc(&dep->location, dep);
        if (stmt_evaluate(ctx, stmt) < 0) {
                return expr_error(ctx->msgs, expr,
                                          "dependency statement is invalid");
        }
+       ctx->stmt_len = stmt_len;
+
        relational_expr_pctx_update(&ctx->pctx, dep);
        *res = stmt;
        return 0;
@@ -502,6 +510,7 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
 {
        const struct hook_proto_desc *h = &hook_proto_desc[ctx->pctx.family];
        const struct proto_desc *desc;
+       unsigned int stmt_len;
        struct stmt *stmt;
        uint16_t type;
 
@@ -516,12 +525,18 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
                                          "protocol specification is invalid "
                                          "for this family");
 
+               stmt_len = ctx->stmt_len;
+               ctx->stmt_len = 0;
+
                stmt = meta_stmt_meta_iiftype(&expr->location, type);
                if (stmt_evaluate(ctx, stmt) < 0) {
                        return expr_error(ctx->msgs, expr,
                                          "dependency statement is invalid");
                }
                *res = stmt;
+
+               ctx->stmt_len = stmt_len;
+
                return 0;
        }