diff --git a/backport-nft-Support-replacing-a-rule-added-in-the-same-batch.patch b/backport-nft-Support-replacing-a-rule-added-in-the-same-batch.patch new file mode 100644 index 0000000000000000000000000000000000000000..1c5599a5405740f3c47787b1d67a7818be257363 --- /dev/null +++ b/backport-nft-Support-replacing-a-rule-added-in-the-same-batch.patch @@ -0,0 +1,132 @@ +From 78d7a5f8619f3965ec2da13003a876c808c40cfb Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 20 Nov 2025 13:55:38 +0100 +Subject: nft: Support replacing a rule added in the same batch + +As reported in nfbz#1820, trying to add a rule and replacing it in the +same batch would crash iptables due to a stale rule pointer left in an +obj_update. + +Doing this is perfectly fine in legacy iptables, so implement the +missing feature instead of merely preventing the crash. + +Link: https://bugzilla.netfilter.org/show_bug.cgi?id=1820 +Fixes: b199aca80da57 ("nft: Fix leak when replacing a rule") +Signed-off-by: Phil Sutter +--- + iptables/nft.c | 52 ++++++++++++++++++++-- + .../shell/testcases/ipt-restore/0018-replace-new_0 | 31 +++++++++++++ + 2 files changed, 79 insertions(+), 4 deletions(-) + create mode 100755 iptables/tests/shell/testcases/ipt-restore/0018-replace-new_0 + +diff --git a/iptables/nft.c b/iptables/nft.c +index 908f5443..85080a6d 100644 +--- a/iptables/nft.c ++++ b/iptables/nft.c +@@ -1764,6 +1764,31 @@ err: + return NULL; + } + ++static struct obj_update *obj_update_by_rule(struct nft_handle *h, ++ struct nftnl_rule *r) ++{ ++ struct obj_update *n; ++ ++ list_for_each_entry(n, &h->obj_list, head) { ++ if (n->rule == r) ++ return n; ++ } ++ return NULL; ++} ++ ++static void copy_nftnl_rule_attr(struct nftnl_rule *to, ++ const struct nftnl_rule *from, ++ uint16_t attr) ++{ ++ const void *data; ++ uint32_t len; ++ ++ if (nftnl_rule_is_set(from, attr)) { ++ data = nftnl_rule_get_data(from, attr, &len); ++ nftnl_rule_set_data(to, attr, data, len); ++ } ++} ++ + int + nft_rule_append(struct nft_handle *h, const char *chain, const char *table, + struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose) +@@ -1775,12 +1800,31 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, + + nft_fn = nft_rule_append; + +- if (ref) { +- nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE, +- nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE)); ++ if (ref && !nftnl_rule_is_set(ref, NFTNL_RULE_HANDLE)) { ++ /* replacing a new rule, hijack its obj_update */ ++ struct obj_update *n = obj_update_by_rule(h, ref); ++ ++ if (!n) { ++ errno = ENOENT; ++ return 0; ++ } ++ if (n->type != NFT_COMPAT_RULE_APPEND && ++ n->type != NFT_COMPAT_RULE_INSERT) { ++ errno = EINVAL; ++ return 0; ++ } ++ copy_nftnl_rule_attr(r, ref, NFTNL_RULE_POSITION); ++ copy_nftnl_rule_attr(r, ref, NFTNL_RULE_ID); ++ nftnl_chain_rule_del(ref); ++ nftnl_rule_free(ref); ++ n->rule = r; ++ return 1; ++ } else if (ref) { ++ copy_nftnl_rule_attr(r, ref, NFTNL_RULE_HANDLE); + type = NFT_COMPAT_RULE_REPLACE; +- } else ++ } else { + type = NFT_COMPAT_RULE_APPEND; ++ } + + if (batch_rule_add(h, type, r) == NULL) + return 0; +diff --git a/iptables/tests/shell/testcases/ipt-restore/0018-replace-new_0 b/iptables/tests/shell/testcases/ipt-restore/0018-replace-new_0 +new file mode 100755 +index 00000000..3930bdea +--- /dev/null ++++ b/iptables/tests/shell/testcases/ipt-restore/0018-replace-new_0 +@@ -0,0 +1,31 @@ ++#!/bin/bash ++ ++set -e ++ ++RS='*filter ++-A FORWARD -m comment --comment "new rule being replaced" ++-R FORWARD 1 -m comment --comment "new replacing rule" ++COMMIT' ++EXP='*filter ++:INPUT ACCEPT [0:0] ++:FORWARD ACCEPT [0:0] ++:OUTPUT ACCEPT [0:0] ++-A FORWARD -m comment --comment "new replacing rule" ++COMMIT' ++$XT_MULTI iptables-restore <<< "$RS" ++diff -u -Z <(echo -e "$EXP") <($XT_MULTI iptables-save | grep -v '^#') ++ ++RS='*filter ++-A FORWARD -m comment --comment "rule to insert before" ++-I FORWARD 1 -m comment --comment "new rule being replaced" ++-R FORWARD 1 -m comment --comment "new replacing rule" ++COMMIT' ++EXP='*filter ++:INPUT ACCEPT [0:0] ++:FORWARD ACCEPT [0:0] ++:OUTPUT ACCEPT [0:0] ++-A FORWARD -m comment --comment "new replacing rule" ++-A FORWARD -m comment --comment "rule to insert before" ++COMMIT' ++$XT_MULTI iptables-restore <<< "$RS" ++diff -u -Z <(echo -e "$EXP") <($XT_MULTI iptables-save | grep -v '^#') +-- +cgit v1.2.3 diff --git a/iptables.spec b/iptables.spec index 505d2690ac7337f2c6ba4ed4047b732cfc4ebca3..4e10c56c9df55708a525b101de7b3523c1255eea 100644 --- a/iptables.spec +++ b/iptables.spec @@ -2,7 +2,7 @@ %global legacy_actions %{_libexecdir}/initscripts/legacy-actions Name: iptables Version: 1.8.9 -Release: 12 +Release: 13 Summary: IP packet filter administration utilities License: GPL-2.0-only and Artistic-2.0 URL: https://www.netfilter.org/ @@ -34,6 +34,7 @@ Patch17: backport-nft-cmd-Init-struct-nft_cmd-head-early.patch Patch18: backport-ip6tables-Fix-checking-existence-of-rule.patch Patch19: backport-iptables-legacy-Fix-for-mandatory-lock-waiting.patch Patch20: backport-tests-shell-iptables-0010-wait_0-is-unreliable.patch +Patch21: backport-nft-Support-replacing-a-rule-added-in-the-same-batch.patch BuildRequires: bison flex gcc kernel-headers libpcap-devel libselinux-devel systemd @@ -345,6 +346,12 @@ fi %{_datadir}/xtables/iptables.xslt %changelog +* Wed Dec 10 2025 yanglu - 1.8.9-13 +- Type:bugfix +- CVE:NA +- SUG:NA +- DESC:nft:Support replacing a rule added in the same batch + * Mon Aug 18 2025 yanglu - 1.8.9-12 - Type:bugfix - CVE:NA