Skip to content

Commit 323904a

Browse files
committed
netfilter: nf_tables: reject duplicate device on updates
JIRA: https://issues.redhat.com/browse/RHEL-115582 Upstream Status: commit cf5fb87 commit cf5fb87 Author: Pablo Neira Ayuso <pablo@netfilter.org> Date: Wed Aug 13 02:38:50 2025 +0200 netfilter: nf_tables: reject duplicate device on updates 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: 78d9f48 ("netfilter: nf_tables: add devices to existing flowtable") Fixes: b9703ed ("netfilter: nf_tables: support for adding new devices to an existing netdev chain") Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Florian Westphal <fwestpha@redhat.com>
1 parent 3e12aed commit 323904a

File tree

1 file changed

+30
-0
lines changed

1 file changed

+30
-0
lines changed

net/netfilter/nf_tables_api.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2761,6 +2761,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
27612761
struct nft_chain *chain = ctx->chain;
27622762
struct nft_chain_hook hook = {};
27632763
struct nft_stats __percpu *stats = NULL;
2764+
struct nftables_pernet *nft_net;
27642765
struct nft_hook *h, *next;
27652766
struct nf_hook_ops *ops;
27662767
struct nft_trans *trans;
@@ -2801,6 +2802,20 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
28012802
if (nft_hook_list_find(&basechain->hook_list, h)) {
28022803
list_del(&h->list);
28032804
nft_netdev_hook_free(h);
2805+
continue;
2806+
}
2807+
2808+
nft_net = nft_pernet(ctx->net);
2809+
list_for_each_entry(trans, &nft_net->commit_list, list) {
2810+
if (trans->msg_type != NFT_MSG_NEWCHAIN ||
2811+
trans->table != ctx->table ||
2812+
!nft_trans_chain_update(trans))
2813+
continue;
2814+
2815+
if (nft_hook_list_find(&nft_trans_chain_hooks(trans), h)) {
2816+
nft_chain_release_hook(&hook);
2817+
return -EEXIST;
2818+
}
28042819
}
28052820
}
28062821
} else {
@@ -8995,6 +9010,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
89959010
{
89969011
const struct nlattr * const *nla = ctx->nla;
89979012
struct nft_flowtable_hook flowtable_hook;
9013+
struct nftables_pernet *nft_net;
89989014
struct nft_hook *hook, *next;
89999015
struct nft_trans *trans;
90009016
bool unregister = false;
@@ -9010,6 +9026,20 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
90109026
if (nft_hook_list_find(&flowtable->hook_list, hook)) {
90119027
list_del(&hook->list);
90129028
nft_netdev_hook_free(hook);
9029+
continue;
9030+
}
9031+
9032+
nft_net = nft_pernet(ctx->net);
9033+
list_for_each_entry(trans, &nft_net->commit_list, list) {
9034+
if (trans->msg_type != NFT_MSG_NEWFLOWTABLE ||
9035+
trans->table != ctx->table ||
9036+
!nft_trans_flowtable_update(trans))
9037+
continue;
9038+
9039+
if (nft_hook_list_find(&nft_trans_flowtable_hooks(trans), hook)) {
9040+
err = -EEXIST;
9041+
goto err_flowtable_update_hook;
9042+
}
90139043
}
90149044
}
90159045

0 commit comments

Comments
 (0)