nftables/SOURCES/0023-evaluate-reset-statement-length-context-only-for-set.patch
2026-08-26 08:03:54 -04:00

219 lines
7.0 KiB
Diff

From 3f363237125fded5adb4bc9ed8890e518a518286 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 17 Jul 2026 11:08:18 +0200
Subject: [PATCH] evaluate: reset statement length context only for set
mappings
JIRA: https://issues.redhat.com/browse/RHEL-190549
Upstream Status: nftables commit 57f092a87fc4bc61e29cff31dfff976e1f2005ab
commit 57f092a87fc4bc61e29cff31dfff976e1f2005ab
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Sun Nov 5 18:33:14 2023 +0100
evaluate: reset statement length context only for set mappings
map expression (which is used a key to look up for the mapping) needs to
consider the statement length context, otherwise incorrect bytecode is
generated when {ct,meta} statement is generated.
# nft -f - <<EOF
add table ip6 t
add chain ip6 t c
add map ip6 t mapv6 { typeof ip6 dscp : meta mark; }
EOF
# nft -d netlink add rule ip6 t c meta mark set ip6 dscp map @mapv6
ip6 t c
[ payload load 2b @ network header + 0 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
... missing byteorder conversion here before shift ...
[ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
[ lookup reg 1 set mapv6 dreg 1 ]
[ meta set mark with reg 1 ]
Reset statement length context only for the mapping side for the
elements in the set.
Fixes: edecd58755a8 ("evaluate: support shifts larger than the width of the left operand")
Reported-by: Brian Davidson <davidson.brian@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/evaluate.c | 2 +-
tests/py/ip6/ip6.t | 5 +++
tests/py/ip6/ip6.t.json | 58 +++++++++++++++++++++++++++++++++
tests/py/ip6/ip6.t.payload.inet | 23 +++++++++++++
tests/py/ip6/ip6.t.payload.ip6 | 19 +++++++++++
5 files changed, 106 insertions(+), 1 deletion(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index 711990a..1850043 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1913,13 +1913,13 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
}
expr_set_context(&ctx->ectx, NULL, 0);
- ctx->stmt_len = 0;
if (expr_evaluate(ctx, &map->map) < 0)
return -1;
if (expr_is_constant(map->map))
return expr_error(ctx->msgs, map->map,
"Map expression can not be constant");
+ ctx->stmt_len = 0;
mappings = map->mappings;
mappings->set_flags |= NFT_SET_MAP;
diff --git a/tests/py/ip6/ip6.t b/tests/py/ip6/ip6.t
index 2ffe318..60ea223 100644
--- a/tests/py/ip6/ip6.t
+++ b/tests/py/ip6/ip6.t
@@ -17,6 +17,11 @@ ip6 dscp != 0x20;ok;ip6 dscp != cs4
ip6 dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef};ok
ip6 dscp vmap { 0x04 : accept, 0x3f : continue } counter;ok
+!map1 type dscp : mark;ok
+meta mark set ip6 dscp map @map1;ok
+!map2 type dscp . ipv6_addr : mark;ok
+meta mark set ip6 dscp . ip6 daddr map @map2;ok
+
ip6 flowlabel 22;ok
ip6 flowlabel != 233;ok
- ip6 flowlabel 33-45;ok
diff --git a/tests/py/ip6/ip6.t.json b/tests/py/ip6/ip6.t.json
index cf80217..5411190 100644
--- a/tests/py/ip6/ip6.t.json
+++ b/tests/py/ip6/ip6.t.json
@@ -135,6 +135,64 @@
}
]
+# meta mark set ip6 dscp map @map1
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": "@map1",
+ "key": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ }
+ }
+ }
+ }
+ }
+]
+
+# meta mark set ip6 dscp . ip6 daddr map @map2
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": "@map2",
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
# ip6 flowlabel 22
[
{
diff --git a/tests/py/ip6/ip6.t.payload.inet b/tests/py/ip6/ip6.t.payload.inet
index 20dfe54..214a0ed 100644
--- a/tests/py/ip6/ip6.t.payload.inet
+++ b/tests/py/ip6/ip6.t.payload.inet
@@ -53,6 +53,29 @@ ip6 test-ip6 input
[ lookup reg 1 set __map%d dreg 0 ]
[ counter pkts 0 bytes 0 ]
+# meta mark set ip6 dscp map @map1
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ lookup reg 1 set map1 dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip6 dscp . ip6 daddr map @map2
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ payload load 16b @ network header + 24 => reg 9 ]
+ [ lookup reg 1 set map2 dreg 1 ]
+ [ meta set mark with reg 1 ]
+
# ip6 flowlabel 22
inet test-inet input
[ meta load nfproto => reg 1 ]
diff --git a/tests/py/ip6/ip6.t.payload.ip6 b/tests/py/ip6/ip6.t.payload.ip6
index f8e3ca3..428b8ea 100644
--- a/tests/py/ip6/ip6.t.payload.ip6
+++ b/tests/py/ip6/ip6.t.payload.ip6
@@ -41,6 +41,25 @@ ip6 test-ip6 input
[ lookup reg 1 set __map%d dreg 0 ]
[ counter pkts 0 bytes 0 ]
+# meta mark set ip6 dscp map @map1
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ lookup reg 1 set map1 dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip6 dscp . ip6 daddr map @map2
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ payload load 16b @ network header + 24 => reg 9 ]
+ [ lookup reg 1 set map2 dreg 1 ]
+ [ meta set mark with reg 1 ]
+
# ip6 flowlabel 22
ip6 test-ip6 input
[ payload load 3b @ network header + 1 => reg 1 ]