]> 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>
Tue, 13 Feb 2024 16:23:55 +0000 (17:23 +0100)
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 32f8a3e58aba02e880f9d7f1326f4b37daad8af0..27a62462bf7d963eb80f0f066694d48ea130c7b6 100644 (file)
@@ -61,6 +61,7 @@ struct rule_pp_ctx {
        struct dl_proto_ctx     *dl;
        struct stmt             *stmt;
        unsigned int            flags;
+       struct set              *set;
 };
 
 extern const struct input_descriptor indesc_netlink;
index 92e009efd4b16ea5b848147f3999931052b1485f..f8b8530c4b32043b8b842ee7592870bb01123aa7 100644 (file)
@@ -199,13 +199,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 27630a8a9b34d336deb386ef0f787569b928fdeb..1d30a78c3441c85f9c13cdae48f61449d5b3d715 100644 (file)
@@ -2722,10 +2722,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)
@@ -2869,7 +2870,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);