]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
intervals: set internal element location with the deletion trigger
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 4 Dec 2024 22:36:05 +0000 (23:36 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 17 Jun 2025 09:17:27 +0000 (11:17 +0200)
commit 93077e35accccd8cc056b67f70bfb3182c819fd4 upstream.

set location of internal elements (already in the kernel) to the one
that partial or fully deletes it.

Otherwise, error reporting refers to internal location.

Before this patch:

 # nft delete element x y { 1.1.1.3 }
 Error: Could not process rule: Too many open files in system
 delete element x y { 1.1.1.3 }
                      ^^^^^^^

After this patch:

 # nft delete element x y { 1.1.1.3 }
 Error: Could not process rule: Too many open files in system
 delete element x y { 1.1.1.3 }
                      ^^^^^^^

This occurs after splitting an existing interval in two:

 remove: [1010100-10101ff]
 add: [1010100-1010102]
 add: [1010104-10101ff]

which results in two additions after removing the existing interval
that is split.

Fixes: 81e36530fcac ("src: replace interval segment tree overlap and automerge")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/intervals.c

index 3d711eb7fdd8d9f04119bc613734c93207feecff..0f5518ff00afd9928a5eb972d3cec431273d50d9 100644 (file)
@@ -82,6 +82,7 @@ static void remove_overlapping_range(struct set_automerge_ctx *ctx,
                                     struct expr *prev, struct expr *i)
 {
        if (i->flags & EXPR_F_KERNEL) {
+               i->location = prev->location;
                purge_elem(ctx, i);
                return;
        }
@@ -100,12 +101,14 @@ static bool merge_ranges(struct set_automerge_ctx *ctx,
                         struct range *prev_range, struct range *range)
 {
        if (prev->flags & EXPR_F_KERNEL) {
+               prev->location = i->location;
                purge_elem(ctx, prev);
                expr_free(i->key->left);
                i->key->left = expr_get(prev->key->left);
                mpz_set(prev_range->high, range->high);
                return true;
        } else if (i->flags & EXPR_F_KERNEL) {
+               i->location = prev->location;
                purge_elem(ctx, i);
                expr_free(prev->key->right);
                prev->key->right = expr_get(i->key->right);
@@ -300,6 +303,7 @@ static void __adjust_elem_left(struct set *set, struct expr *prev, struct expr *
 static void adjust_elem_left(struct set *set, struct expr *prev, struct expr *i,
                             struct expr *purge)
 {
+       prev->location = i->location;
        remove_elem(prev, set, purge);
        __adjust_elem_left(set, prev, i);
 
@@ -319,6 +323,7 @@ static void __adjust_elem_right(struct set *set, struct expr *prev, struct expr
 static void adjust_elem_right(struct set *set, struct expr *prev, struct expr *i,
                              struct expr *purge)
 {
+       prev->location = i->location;
        remove_elem(prev, set, purge);
        __adjust_elem_right(set, prev, i);
 
@@ -331,6 +336,8 @@ static void split_range(struct set *set, struct expr *prev, struct expr *i,
 {
        struct expr *clone;
 
+       prev->location = i->location;
+
        if (prev->flags & EXPR_F_KERNEL) {
                clone = expr_clone(prev);
                list_move_tail(&clone->list, &purge->expressions);
@@ -418,8 +425,10 @@ 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 (elem->flags & EXPR_F_REMOVE) {
-                               if (prev->flags & EXPR_F_KERNEL)
+                               if (prev->flags & EXPR_F_KERNEL) {
+                                       prev->location = elem->location;
                                        list_move_tail(&prev->list, &purge->expressions);
+                               }
 
                                list_del(&elem->list);
                                expr_free(elem);