From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Subject: [PATCH nft 2/3] segtree: basic support for binary operations in concatenated set ranges
Date: Wed, 5 Aug 2026 18:39:19 +0200 [thread overview]
Message-ID: <20260805163920.238975-2-pablo@netfilter.org> (raw)
In-Reply-To: <20260805163920.238975-1-pablo@netfilter.org>
Use of tcp flags in concatenated set ranges such as (note the 100-110
range):
table ip x {
chain y {
tcp flags . tcp dport vmap { syn | ack . 80 : accept, ack . 90 : drop, rst . 100-110 : drop
}
}
is broken when listing the ruleset:
AddressSanitizer:DEADLYSIGNAL
=================================================================
==218685==ERROR: AddressSanitizer: SEGV on unknown address 0x50b000029798 (pc 0x7f8318b8fac0 bp 0x7ffd080a4310 sp 0x7ffd080a4198 T0)
==218685==The signal is caused by a READ memory access.
#0 0x7f8318b8fac0 in __gmpz_cmp (/lib/x86_64-linux-gnu/libgmp.so.10+0x19ac0) (BuildId: dff5c2156ec812613c5e4431005c576b212dd323)
#1 0x7f83192fbc3f in concat_range_aggregate src/segtree.c:404
#2 0x7f8319240889 in netlink_list_setelems src/netlink.c:1774
#3 0x7f8319115fdd in cache_init_objects src/cache.c:1189
#4 0x7f8319116f10 in nft_cache_init src/cache.c:1266
#5 0x7f831911772b in nft_cache_update src/cache.c:1325
#6 0x7f83191eac34 in nft_evaluate src/libnftables.c:580
#7 0x7f83191eb8b6 in nft_run_cmd_from_buffer src/libnftables.c:638
#8 0x558baf3bc403 in main src/main.c:538
add basic support so it works with tcp flags, add a new assertion to
crash safely to ensure expression type is EXPR_VALUE before access
when trying to compose the range (this code only supports EXPR_VALUE
when building a range expression at this stage) and a new test.
This patch includes a new tests/shell unit file.
Fixes: 8ac2f3b2fca3 ("src: Add support for concatenated set ranges")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/segtree.c | 27 ++-
.../dumps/vmap_concat_range_binary.json-nft | 209 ++++++++++++++++++
.../maps/dumps/vmap_concat_range_binary.nft | 14 ++
.../testcases/maps/vmap_concat_range_binary | 22 ++
4 files changed, 271 insertions(+), 1 deletion(-)
create mode 100644 tests/shell/testcases/maps/dumps/vmap_concat_range_binary.json-nft
create mode 100755 tests/shell/testcases/maps/dumps/vmap_concat_range_binary.nft
create mode 100755 tests/shell/testcases/maps/vmap_concat_range_binary
diff --git a/src/segtree.c b/src/segtree.c
index a721078cfa59..c8a7a3541ac3 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -362,6 +362,29 @@ static int range_mask_len(const mpz_t start, const mpz_t end, unsigned int len)
return ret;
}
+static int concat_expr_cmp(const struct expr *r1, const struct expr *r2)
+{
+ int ret;
+
+ assert(r1->etype == r2->etype);
+
+ switch (r1->etype) {
+ case EXPR_BINOP:
+ assert(r1->op == r2->op);
+ ret = 0;
+ ret = mpz_cmp(r1->left->value, r2->left->value);
+ ret |= mpz_cmp(r1->right->value, r2->right->value);
+ break;
+ case EXPR_VALUE:
+ ret = mpz_cmp(r1->value, r2->value);
+ break;
+ default:
+ BUG("unexpected expression %s", expr_name(r1->key));
+ }
+
+ return ret;
+}
+
/* Given a set with two elements (start and end), transform them into a
* concatenation of ranges. That is, from a list of start expressions and a list
* of end expressions, form a list of start - end expressions.
@@ -401,11 +424,13 @@ void concat_range_aggregate(struct expr *set)
r2_next = r2->list.next;
free_r1 = 0;
- if (!mpz_cmp(r1->value, r2->value)) {
+ if (!concat_expr_cmp(r1, r2)) {
free_r1 = 1;
goto next;
}
+ assert(r1->etype == EXPR_VALUE && r1->etype == EXPR_VALUE);
+
if (expr_basetype(r1)->type == TYPE_STRING &&
expr_basetype(r2)->type == TYPE_STRING) {
string_type = true;
diff --git a/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.json-nft b/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.json-nft
new file mode 100644
index 000000000000..8868f2eb180e
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.json-nft
@@ -0,0 +1,209 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "z",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": {
+ "typeof": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ }
+ },
+ "handle": 0,
+ "map": "verdict",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "concat": [
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ },
+ 80
+ ]
+ },
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "ack",
+ 90
+ ]
+ },
+ {
+ "drop": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "rst",
+ {
+ "range": [
+ 100,
+ 110
+ ]
+ }
+ ]
+ },
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "data": "@y"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ },
+ 80
+ ]
+ },
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "ack",
+ 90
+ ]
+ },
+ {
+ "drop": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "rst",
+ {
+ "range": [
+ 100,
+ 110
+ ]
+ }
+ ]
+ },
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.nft b/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.nft
new file mode 100755
index 000000000000..bc74535b852f
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.nft
@@ -0,0 +1,14 @@
+table ip x {
+ map y {
+ typeof tcp flags . tcp dport : verdict
+ flags interval
+ elements = { syn | ack . 80 : accept,
+ ack . 90 : drop,
+ rst . 100-110 : drop }
+ }
+
+ chain z {
+ tcp flags . tcp dport vmap @y
+ tcp flags . tcp dport vmap { syn | ack . 80 : accept, ack . 90 : drop, rst . 100-110 : drop }
+ }
+}
diff --git a/tests/shell/testcases/maps/vmap_concat_range_binary b/tests/shell/testcases/maps/vmap_concat_range_binary
new file mode 100755
index 000000000000..ad5ef4a9177e
--- /dev/null
+++ b/tests/shell/testcases/maps/vmap_concat_range_binary
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+
+RULESET="table ip x {
+ map y {
+ typeof tcp flags . tcp dport : verdict
+ flags interval
+ elements = { syn | ack . 80 : accept,
+ ack . 90 : drop,
+ rst . 100-110 : drop }
+ }
+
+ chain z {
+ tcp flags . tcp dport vmap @y
+ tcp flags . tcp dport vmap { syn | ack . 80 : accept, ack . 90 : drop, rst . 100-110 : drop }
+ }
+}"
+
+$NFT -f - <<< $RULESET
--
2.47.3
next prev parent reply other threads:[~2026-08-05 16:39 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-05 16:39 [PATCH nft,v2 1/3] mergesort: use lhs expression when sorting concatenation Pablo Neira Ayuso
2026-08-05 16:39 ` Pablo Neira Ayuso [this message]
2026-08-05 16:39 ` [PATCH nft 3/3] tests: shell: add flush set after expiration Pablo Neira Ayuso
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260805163920.238975-2-pablo@netfilter.org \
--to=pablo@netfilter.org \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.