]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
evaluate: do not crash on runaway number of concatenation components
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 8 Dec 2022 01:25:19 +0000 (02:25 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 8 Dec 2022 20:37:26 +0000 (21:37 +0100)
Display error message in case user specifies more data components than
those defined by the concatenation of selectors.

 # cat example.nft
 table ip x {
        chain y {
                type filter hook prerouting priority 0; policy drop;
                ip saddr . meta mark { 1.2.3.4 . 0x00000100 . 1.2.3.6-1.2.3.8 } accept
        }
 }
 # nft -f example.nft
 example.nft:4:3-22: Error: too many concatenation components
                ip saddr . meta mark { 1.2.3.4 . 0x00000100 . 1.2.3.6-1.2.3.8 } accept
                ~~~~~~~~~~~~~~~~~~~~   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Without this patch, nft crashes:

==464771==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60d000000418 at pc 0x7fbc17513aa5 bp 0x7ffc73d33c90 sp 0x7ffc73d33c88
READ of size 8 at 0x60d000000418 thread T0
    #0 0x7fbc17513aa4 in expr_evaluate_concat /home/pablo/devel/scm/git-netfilter/nftables/src/evaluate.c:1348
    #1 0x7fbc1752a9da in expr_evaluate /home/pablo/devel/scm/git-netfilter/nftables/src/evaluate.c:2476
    #2 0x7fbc175175e2 in expr_evaluate_set_elem /home/pablo/devel/scm/git-netfilter/nftables/src/evaluate.c:1504
    #3 0x7fbc1752aa22 in expr_evaluate /home/pablo/devel/scm/git-netfilter/nftables/src/evaluate.c:2482
    #4 0x7fbc17512cb5 in list_member_evaluate /home/pablo/devel/scm/git-netfilter/nftables/src/evaluate.c:1310
    #5 0x7fbc17518ca0 in expr_evaluate_set /home/pablo/devel/scm/git-netfilter/nftables/src/evaluate.c:1590
    [...]

Fixes: 64bb3f43bb96 ("src: allow to use typeof of raw expressions in set declaration")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/evaluate.c

index 991de1d7e977f6692f0a29f89d611e1eef7f3898..3a524aab0e1200bf7d4f6eb72d9e2f0e208222cd 100644 (file)
@@ -1318,20 +1318,28 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
        uint32_t type = dtype ? dtype->type : 0, ntype = 0;
        int off = dtype ? dtype->subtypes : 0;
        unsigned int flags = EXPR_F_CONSTANT | EXPR_F_SINGLETON;
+       const struct list_head *expressions;
        struct expr *i, *next, *key = NULL;
        const struct expr *key_ctx = NULL;
+       bool runaway = false;
        uint32_t size = 0;
 
        if (ctx->ectx.key && ctx->ectx.key->etype == EXPR_CONCAT) {
                key_ctx = ctx->ectx.key;
                assert(!list_empty(&ctx->ectx.key->expressions));
                key = list_first_entry(&ctx->ectx.key->expressions, struct expr, list);
+               expressions = &ctx->ectx.key->expressions;
        }
 
        list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
                enum byteorder bo = BYTEORDER_INVALID;
                unsigned dsize_bytes, dsize = 0;
 
+               if (runaway) {
+                       return expr_binary_error(ctx->msgs, *expr, key_ctx,
+                                                "too many concatenation components");
+               }
+
                if (i->etype == EXPR_CT &&
                    (i->ct.key == NFT_CT_SRC ||
                     i->ct.key == NFT_CT_DST))
@@ -1387,8 +1395,12 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
                dsize_bytes = div_round_up(dsize, BITS_PER_BYTE);
                (*expr)->field_len[(*expr)->field_count++] = dsize_bytes;
                size += netlink_padded_len(dsize);
-               if (key)
+               if (key) {
+                       if (list_is_last(&key->list, expressions))
+                               runaway = true;
+
                        key = list_next_entry(key, list);
+               }
        }
 
        (*expr)->flags |= flags;