]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
evaluate: permit use of host-endian constant values in set lookup keys
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 12 Feb 2024 15:46:29 +0000 (16:46 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 22 Jan 2025 23:41:55 +0000 (00:41 +0100)
commit c0080feb0d034913409944d23873cce4bf9edf9e upstream.

AFL found following crash:

table ip filter {
map ipsec_in {
typeof ipsec in reqid . iif : verdict
flags interval
}

chain INPUT {
type filter hook input priority filter; policy drop;
ipsec in reqid . 100 @ipsec_in
}
}

Which yields:
nft: evaluate.c:1213: expr_evaluate_unary: Assertion `!expr_is_constant(arg)' failed.

All existing test cases with constant values use big endian values, but
"iif" expects host endian values.

As raw values were not supported before, concat byteorder conversion
doesn't handle constants.

Fix this:

1. Add constant handling so that the number is converted in-place,
   without unary expression.

2. Add the inverse handling on delinearization for non-interval set
   types.
   When dissecting the concat data soup, watch for integer constants where
   the datatype indicates host endian integer.

Last, extend an existing test case with the afl input to cover
in/output.

A new test case is added to test linearization, delinearization and
matching.

Based on original patch from Florian Westphal, patch subject and
description wrote by him.

Fixes: b422b07ab2f9 ("src: permit use of constant values in set lookup keys")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/netlink.h
src/evaluate.c
src/netlink_delinearize.c

index 2baa24175430244d5c5329325474d0d10edca6d9..0c053a32e1d7f843719fdb332361f000edb8bc4c 100644 (file)
@@ -54,6 +54,7 @@ struct rule_pp_ctx {
        struct payload_dep_ctx  pdctx;
        struct stmt             *stmt;
        unsigned int            flags;
+       struct set              *set;
 };
 
 extern const struct input_descriptor indesc_netlink;
index 73f375c1f6f13a097d17184f7a062149f0640927..098d9a11131eff3a31b1f8ca9bc495b51c82b445 100644 (file)
@@ -193,13 +193,20 @@ static int byteorder_conversion(struct eval_ctx *ctx, struct expr **expr,
 
                        assert(basetype == TYPE_INTEGER);
 
-                       if (div_round_up(i->len, BITS_PER_BYTE) >= 2) {
-                               op = byteorder_conversion_op(i, byteorder);
-                               unary = unary_expr_alloc(&i->location, op, i);
-                               if (expr_evaluate(ctx, &unary) < 0)
-                                       return -1;
+                       switch (i->etype) {
+                       case EXPR_VALUE:
+                               if (i->byteorder == BYTEORDER_HOST_ENDIAN)
+                                       mpz_switch_byteorder(i->value, div_round_up(i->len, BITS_PER_BYTE));
+                               break;
+                       default:
+                               if (div_round_up(i->len, BITS_PER_BYTE) >= 2) {
+                                       op = byteorder_conversion_op(i, byteorder);
+                                       unary = unary_expr_alloc(&i->location, op, i);
+                                       if (expr_evaluate(ctx, &unary) < 0)
+                                               return -1;
 
-                               list_replace(&i->list, &unary->list);
+                                       list_replace(&i->list, &unary->list);
+                               }
                        }
                }
 
index 0d31ba46e4bf447b575d34b7d7afce4f6ee85211..273669a3bb3bb65e6f3f5cfa9ff0536104feac83 100644 (file)
@@ -2570,10 +2570,11 @@ static struct expr *expr_postprocess_string(struct expr *expr)
 
 static void expr_postprocess_value(struct rule_pp_ctx *ctx, struct expr **exprp)
 {
+       bool interval = (ctx->set && ctx->set->flags & NFT_SET_INTERVAL);
        struct expr *expr = *exprp;
 
        // FIXME
-       if (expr->byteorder == BYTEORDER_HOST_ENDIAN)
+       if (expr->byteorder == BYTEORDER_HOST_ENDIAN && !interval)
                mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
 
        if (expr_basetype(expr)->type == TYPE_STRING)
@@ -2716,7 +2717,9 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
 
                                datatype_set(expr->left, expr->right->dtype);
                        }
+                       ctx->set = expr->right->set;
                        expr_postprocess(ctx, &expr->left);
+                       ctx->set = NULL;
                        break;
                default:
                        expr_postprocess(ctx, &expr->left);