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

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