[SRU][J][PATCH 1/1] netfilter: nf_tables: reject duplicate device on updates

Ian Whitfield ian.whitfield at canonical.com
Wed Sep 17 02:51:22 UTC 2025


From: Pablo Neira Ayuso <pablo at netfilter.org>

A chain/flowtable update with duplicated devices in the same batch is
possible. Unfortunately, netdev event path only removes the first
device that is found, leaving unregistered the hook of the duplicated
device.

Check if a duplicated device exists in the transaction batch, bail out
with EEXIST in such case.

WARNING is hit when unregistering the hook:

 [49042.221275] WARNING: CPU: 4 PID: 8425 at net/netfilter/core.c:340 nf_hook_entry_head+0xaa/0x150
 [49042.221375] CPU: 4 UID: 0 PID: 8425 Comm: nft Tainted: G S                  6.16.0+ #170 PREEMPT(full)
 [...]
 [49042.221382] RIP: 0010:nf_hook_entry_head+0xaa/0x150

Fixes: 78d9f48f7f44 ("netfilter: nf_tables: add devices to existing flowtable")
Fixes: b9703ed44ffb ("netfilter: nf_tables: support for adding new devices to an existing netdev chain")
Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>
Signed-off-by: Florian Westphal <fw at strlen.de>
(backported from commit cf5fb87fcdaaaafec55dcc0dc5a9e15ead343973)
[ijwhitfield: Adjusted context due to missing commit:
75e20bcdce24 ("netfilter: nf_tables: Introduce functions freeing nft_hook objects")
Edited patch to reverse change made in missing commit:
e169285f8c56 ("netfilter: nf_tables: do not store nft_ctx in transaction objects")
Did not include changes to nf_tables_updchain due to missing break commit:
b9703ed44ffb ("netfilter: nf_tables: support for adding new devices to an existing netdev chain")]
CVE-2025-38678
Signed-off-by: Ian Whitfield <ian.whitfield at canonical.com>
---
 net/netfilter/nf_tables_api.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index c2c6351eb72b..7569fad8fb25 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -7925,6 +7925,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
 {
 	const struct nlattr * const *nla = ctx->nla;
 	struct nft_flowtable_hook flowtable_hook;
+	struct nftables_pernet *nft_net;
 	struct nft_hook *hook, *next;
 	struct nft_trans *trans;
 	bool unregister = false;
@@ -7940,6 +7941,20 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
 		if (nft_hook_list_find(&flowtable->hook_list, hook)) {
 			list_del(&hook->list);
 			kfree(hook);
+			continue;
+		}
+
+		nft_net = nft_pernet(ctx->net);
+		list_for_each_entry(trans, &nft_net->commit_list, list) {
+			if (trans->msg_type != NFT_MSG_NEWFLOWTABLE ||
+			    trans->ctx.table != ctx->table ||
+			    !nft_trans_flowtable_update(trans))
+				continue;
+
+			if (nft_hook_list_find(&nft_trans_flowtable_hooks(trans), hook)) {
+				err = -EEXIST;
+				goto err_flowtable_update_hook;
+			}
 		}
 	}
 
-- 
2.43.0




More information about the kernel-team mailing list