Blame SOURCES/0073-evaluate-attempt-to-set_eval-flag-if-dynamic-updates.patch

96192c
From 48021b277a1ab92480c43e1fa7573b00e33f5212 Mon Sep 17 00:00:00 2001
96192c
From: Phil Sutter <psutter@redhat.com>
96192c
Date: Fri, 14 Jan 2022 11:39:17 +0100
96192c
Subject: [PATCH] evaluate: attempt to set_eval flag if dynamic updates
96192c
 requested
96192c
96192c
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2039594
96192c
Upstream Status: nftables commit 8d443adfcc8c1
96192c
Conflicts:
96192c
* Context change due to missing commit 242965f452e64
96192c
  ("src: add support for multi-statement in dynamic sets and maps")
96192c
* Adjusted test-case: Due to missing kernel commit 7b1394892de8d
96192c
  ("netfilter: nft_dynset: relax superfluous check on set updates"),
96192c
  'update' statement is allowed only if timeout flag is present
96192c
96192c
commit 8d443adfcc8c19effd6be9a9c903ee96e374f2e8
96192c
Author: Florian Westphal <fw@strlen.de>
96192c
Date:   Tue Jan 11 12:08:59 2022 +0100
96192c
96192c
    evaluate: attempt to set_eval flag if dynamic updates requested
96192c
96192c
    When passing no upper size limit, the dynset expression forces
96192c
    an internal 64k upperlimit.
96192c
96192c
    In some cases, this can result in 'nft -f' to restore the ruleset.
96192c
    Avoid this by always setting the EVAL flag on a set definition when
96192c
    we encounter packet-path update attempt in the batch.
96192c
96192c
    Reported-by: Yi Chen <yiche@redhat.com>
96192c
    Suggested-by: Pablo Neira Ayuso <pablo@netfilter.org>
96192c
    Signed-off-by: Florian Westphal <fw@strlen.de>
96192c
---
96192c
 src/evaluate.c                                | 11 +++++++
96192c
 .../testcases/sets/dumps/dynset_missing.nft   | 12 +++++++
96192c
 tests/shell/testcases/sets/dynset_missing     | 32 +++++++++++++++++++
96192c
 3 files changed, 55 insertions(+)
96192c
 create mode 100644 tests/shell/testcases/sets/dumps/dynset_missing.nft
96192c
 create mode 100755 tests/shell/testcases/sets/dynset_missing
96192c
96192c
diff --git a/src/evaluate.c b/src/evaluate.c
96192c
index 00ec20b..9381f23 100644
96192c
--- a/src/evaluate.c
96192c
+++ b/src/evaluate.c
96192c
@@ -3076,6 +3076,8 @@ static int stmt_evaluate_log(struct eval_ctx *ctx, struct stmt *stmt)
96192c
 
96192c
 static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
96192c
 {
96192c
+	struct set *this_set;
96192c
+
96192c
 	expr_set_context(&ctx->ectx, NULL, 0);
96192c
 	if (expr_evaluate(ctx, &stmt->set.set) < 0)
96192c
 		return -1;
96192c
@@ -3103,6 +3105,15 @@ static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
96192c
 						 "meter statement must be stateful");
96192c
 	}
96192c
 
96192c
+	this_set = stmt->set.set->set;
96192c
+
96192c
+	/* Make sure EVAL flag is set on set definition so that kernel
96192c
+	 * picks a set that allows updates from the packet path.
96192c
+	 *
96192c
+	 * Alternatively we could error out in case 'flags dynamic' was
96192c
+	 * not given, but we can repair this here.
96192c
+	 */
96192c
+	this_set->flags |= NFT_SET_EVAL;
96192c
 	return 0;
96192c
 }
96192c
 
96192c
diff --git a/tests/shell/testcases/sets/dumps/dynset_missing.nft b/tests/shell/testcases/sets/dumps/dynset_missing.nft
96192c
new file mode 100644
96192c
index 0000000..fdb1b97
96192c
--- /dev/null
96192c
+++ b/tests/shell/testcases/sets/dumps/dynset_missing.nft
96192c
@@ -0,0 +1,12 @@
96192c
+table ip test {
96192c
+	set dlist {
96192c
+		type ipv4_addr
96192c
+		size 65535
96192c
+		flags dynamic,timeout
96192c
+	}
96192c
+
96192c
+	chain output {
96192c
+		type filter hook output priority filter; policy accept;
96192c
+		udp dport 1234 update @dlist { ip daddr } counter packets 0 bytes 0
96192c
+	}
96192c
+}
96192c
diff --git a/tests/shell/testcases/sets/dynset_missing b/tests/shell/testcases/sets/dynset_missing
96192c
new file mode 100755
96192c
index 0000000..89afcd5
96192c
--- /dev/null
96192c
+++ b/tests/shell/testcases/sets/dynset_missing
96192c
@@ -0,0 +1,32 @@
96192c
+#!/bin/bash
96192c
+
96192c
+set -e
96192c
+
96192c
+$NFT -f /dev/stdin <
96192c
+table ip test {
96192c
+	chain output { type filter hook output priority 0;
96192c
+	}
96192c
+}
96192c
+EOF
96192c
+
96192c
+# misses 'flags dynamic'
96192c
+$NFT 'add set ip test dlist {type ipv4_addr; flags timeout; }'
96192c
+
96192c
+# picks rhash backend because 'size' was also missing.
96192c
+$NFT 'add rule ip test output udp dport 1234 update @dlist { ip daddr } counter'
96192c
+
96192c
+tmpfile=$(mktemp)
96192c
+
96192c
+trap "rm -rf $tmpfile" EXIT
96192c
+
96192c
+# kernel has forced an 64k upper size, i.e. this restore file
96192c
+# has 'size 65536' but no 'flags dynamic'.
96192c
+$NFT list ruleset > $tmpfile
96192c
+
96192c
+# this restore works, because set is still the rhash backend.
96192c
+$NFT -f $tmpfile # success
96192c
+$NFT flush ruleset
96192c
+
96192c
+# fails without commit 'attempt to set_eval flag if dynamic updates requested',
96192c
+# because set in $tmpfile has 'size x' but no 'flags dynamic'.
96192c
+$NFT -f $tmpfile
96192c
-- 
96192c
2.31.1
96192c