[PATCH nft] mergesort: use lhs expression when sorting concatenation

Pablo Neira Ayuso <[email protected]> Mon, 27 Jul 2026 16:21:15 +0200
Newsgroups gmane.comp.security.firewalls.netfilter.devel
Message-ID <[email protected]>
Otherwise, concatenations using binary operations hit an assertion.

 # cat ruleset.nft
 table inet t {
        chain c {
                tcp flags . tcp dport vmap { syn | ack . 80 : drop, ack . 90 : accept }
        }
 }
 # nft -f ruleset.nft
 # nft list ruleset
 nft: src/mergesort.c:23: concat_expr_msort_value: Assertion `ilen > 0' failed.
 Aborted

Inspect the left-hand size of the expression for the merge sorting.

Fixes: 741a06ac15d2 ("mergesort: find base value expression type via recursion")
Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1841
Signed-off-by: Pablo Neira Ayuso <[email protected]>
---
 src/mergesort.c | 38 ++++++++++++++++++++++++++++++++++----
 1 file changed, 34 insertions(+), 4 deletions(-)

diff --git a/src/mergesort.c b/src/mergesort.c
index 2e8ddd22f813..f4b4d56b579c 100644
--- a/src/mergesort.c
+++ b/src/mergesort.c
@@ -12,16 +12,46 @@
 #include <gmputil.h>
 #include <list.h>
 
+static mpz_srcptr concat_expr_msort_value_one(const struct expr *expr,
+					      unsigned int *i_len)
+{
+	mpz_srcptr i_value;
+
+	switch (expr->etype) {
+	case EXPR_BINOP:
+	case EXPR_MAPPING:
+	case EXPR_RANGE:
+		i_value = expr->left->value;
+		*i_len = expr->left->len;
+		break;
+	case EXPR_VALUE:
+		i_value = expr->value;
+		*i_len = expr->len;
+		break;
+	case EXPR_RANGE_VALUE:
+		i_value = expr->range.low;
+		*i_len = expr->len;
+		break;
+	default:
+		BUG("Unknown expression %s", expr_name(expr));
+	}
+
+	*i_len = div_round_up(*i_len, BITS_PER_BYTE);
+
+	return i_value;
+}
+
 static void concat_expr_msort_value(const struct expr *expr, mpz_t value)
 {
-	unsigned int len = 0, ilen;
+	unsigned int len = 0, i_len;
 	const struct expr *i;
+	mpz_srcptr i_value;
 	char data[512];
 
 	list_for_each_entry(i, &expr_concat(expr)->expressions, list) {
-		ilen = div_round_up(i->len, BITS_PER_BYTE);
-		mpz_export_data(data + len, i->value, BYTEORDER_BIG_ENDIAN, ilen);
-		len += ilen;
+		i_value = concat_expr_msort_value_one(i, &i_len);
+		mpz_export_data(data + len, i_value, BYTEORDER_BIG_ENDIAN, i_len);
+		len += i_len;
 	}
 
 	mpz_import_data(value, data, BYTEORDER_BIG_ENDIAN, len);
-- 
2.47.3