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

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