summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2021-06-09 15:49:52 +0200
committerPhil Sutter <phil@nwl.cc>2021-06-09 19:36:25 +0200
commitbaecd1cf26851a4c5b7d469206a488f14fe5b147 (patch)
tree86f5285c2fd39b5dbc941b489a4f915551b23599 /src
parent001bd5b1b744428c77c68dd371fed58c3dc511f2 (diff)
segtree: Fix segfault when restoring a huge interval set
Restoring a set of IPv4 prefixes with about 1.1M elements crashes nft as set_to_segtree() exhausts the stack. Prevent this by allocating the pointer array on heap and make sure it is freed before returning to caller. With this patch in place, restoring said set succeeds with allocation of about 3GB of memory, according to valgrind. Signed-off-by: Phil Sutter <phil@nwl.cc>
Diffstat (limited to 'src')
-rw-r--r--src/segtree.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/src/segtree.c b/src/segtree.c
index a4e047e7..9de5422c 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -435,10 +435,10 @@ static int set_to_segtree(struct list_head *msgs, struct set *set,
struct expr *init, struct seg_tree *tree,
bool add, bool merge)
{
- struct elementary_interval *intervals[init->size];
+ struct elementary_interval **intervals;
struct expr *i, *next;
unsigned int n;
- int err;
+ int err = 0;
/* We are updating an existing set with new elements, check if the new
* interval overlaps with any of the existing ones.
@@ -449,6 +449,7 @@ static int set_to_segtree(struct list_head *msgs, struct set *set,
return err;
}
+ intervals = xmalloc_array(init->size, sizeof(intervals[0]));
n = expr_to_intervals(init, tree->keylen, intervals);
list_for_each_entry_safe(i, next, &init->expressions, list) {
@@ -467,10 +468,11 @@ static int set_to_segtree(struct list_head *msgs, struct set *set,
for (n = 0; n < init->size; n++) {
err = ei_insert(msgs, tree, intervals[n], merge);
if (err < 0)
- return err;
+ break;
}
- return 0;
+ xfree(intervals);
+ return err;
}
static bool segtree_needs_first_segment(const struct set *set,