]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
intervals: fix element deletions with maps
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 3 Jul 2024 14:29:26 +0000 (16:29 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 4 Jul 2024 22:10:47 +0000 (00:10 +0200)
Set element deletion in maps (including catchall elements) does not work.

 # nft delete element ip x m { \* }
 BUG: invalid range expression type catch-all set element
 nft: src/expression.c:1472: range_expr_value_low: Assertion `0' failed.
 Aborted

Call interval_expr_key() to fetch expr->left in the mapping but use the
expression that represents the mapping because it provides access to the
EXPR_F_REMOVE flags.

Moreover, assume maximum value for catchall expression by means of the
expr->len to reuse the existing code to check if the element to be
deleted really exists.

Fixes: 3e8d934e4f72 ("intervals: support to partial deletion with automerge")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/intervals.c

index 6c3f36fec02aae3c412f8cb5924f687fc05c8893..ff202be9375bee3f1c5d124d3db74f0f8ba91c73 100644 (file)
@@ -383,7 +383,7 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
                          struct expr *purge, struct expr *elems,
                          unsigned int debug_mask)
 {
-       struct expr *i, *next, *prev = NULL;
+       struct expr *i, *next, *elem, *prev = NULL;
        struct range range, prev_range;
        int err = 0;
        mpz_t rop;
@@ -394,21 +394,26 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
        mpz_init(range.high);
        mpz_init(rop);
 
-       list_for_each_entry_safe(i, next, &elems->expressions, list) {
-               if (i->key->etype == EXPR_SET_ELEM_CATCHALL)
-                       continue;
+       list_for_each_entry_safe(elem, next, &elems->expressions, list) {
+               i = interval_expr_key(elem);
 
-               range_expr_value_low(range.low, i);
-               range_expr_value_high(range.high, i);
+               if (i->key->etype == EXPR_SET_ELEM_CATCHALL) {
+                       /* Assume max value to simplify handling. */
+                       mpz_bitmask(range.low, i->len);
+                       mpz_bitmask(range.high, i->len);
+               } else {
+                       range_expr_value_low(range.low, i);
+                       range_expr_value_high(range.high, i);
+               }
 
-               if (!prev && i->flags & EXPR_F_REMOVE) {
+               if (!prev && elem->flags & EXPR_F_REMOVE) {
                        expr_error(msgs, i, "element does not exist");
                        err = -1;
                        goto err;
                }
 
-               if (!(i->flags & EXPR_F_REMOVE)) {
-                       prev = i;
+               if (!(elem->flags & EXPR_F_REMOVE)) {
+                       prev = elem;
                        mpz_set(prev_range.low, range.low);
                        mpz_set(prev_range.high, range.high);
                        continue;
@@ -416,12 +421,12 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
 
                if (mpz_cmp(prev_range.low, range.low) == 0 &&
                    mpz_cmp(prev_range.high, range.high) == 0) {
-                       if (i->flags & EXPR_F_REMOVE) {
+                       if (elem->flags & EXPR_F_REMOVE) {
                                if (prev->flags & EXPR_F_KERNEL)
                                        list_move_tail(&prev->list, &purge->expressions);
 
-                               list_del(&i->list);
-                               expr_free(i);
+                               list_del(&elem->list);
+                               expr_free(elem);
                        }
                } else if (set->automerge) {
                        if (setelem_adjust(set, purge, &prev_range, &range, prev, i) < 0) {
@@ -429,7 +434,7 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
                                err = -1;
                                goto err;
                        }
-               } else if (i->flags & EXPR_F_REMOVE) {
+               } else if (elem->flags & EXPR_F_REMOVE) {
                        expr_error(msgs, i, "element does not exist");
                        err = -1;
                        goto err;