Skip to content

Commit 00edc88

Browse files
ummakynesgregkh
authored andcommitted
netfilter: nf_tables: reject duplicate device on updates
commit cf5fb87 upstream. 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+ torvalds#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: Sasha Levin <sashal@kernel.org>
1 parent c07e944 commit 00edc88

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
@@ -2576,6 +2576,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
25762576
struct nft_chain *chain = ctx->chain;
25772577
struct nft_chain_hook hook = {};
25782578
struct nft_stats *stats = NULL;
2579+
struct nftables_pernet *nft_net;
25792580
struct nft_hook *h, *next;
25802581
struct nf_hook_ops *ops;
25812582
struct nft_trans *trans;
@@ -2616,6 +2617,20 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
26162617
if (nft_hook_list_find(&basechain->hook_list, h)) {
26172618
list_del(&h->list);
26182619
kfree(h);
2620+
continue;
2621+
}
2622+
2623+
nft_net = nft_pernet(ctx->net);
2624+
list_for_each_entry(trans, &nft_net->commit_list, list) {
2625+
if (trans->msg_type != NFT_MSG_NEWCHAIN ||
2626+
trans->ctx.table != ctx->table ||
2627+
!nft_trans_chain_update(trans))
2628+
continue;
2629+
2630+
if (nft_hook_list_find(&nft_trans_chain_hooks(trans), h)) {
2631+
nft_chain_release_hook(&hook);
2632+
return -EEXIST;
2633+
}
26192634
}
26202635
}
26212636
} else {
@@ -8493,6 +8508,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
84938508
{
84948509
const struct nlattr * const *nla = ctx->nla;
84958510
struct nft_flowtable_hook flowtable_hook;
8511+
struct nftables_pernet *nft_net;
84968512
struct nft_hook *hook, *next;
84978513
struct nft_trans *trans;
84988514
bool unregister = false;
@@ -8508,6 +8524,20 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
85088524
if (nft_hook_list_find(&flowtable->hook_list, hook)) {
85098525
list_del(&hook->list);
85108526
kfree(hook);
8527+
continue;
8528+
}
8529+
8530+
nft_net = nft_pernet(ctx->net);
8531+
list_for_each_entry(trans, &nft_net->commit_list, list) {
8532+
if (trans->msg_type != NFT_MSG_NEWFLOWTABLE ||
8533+
trans->ctx.table != ctx->table ||
8534+
!nft_trans_flowtable_update(trans))
8535+
continue;
8536+
8537+
if (nft_hook_list_find(&nft_trans_flowtable_hooks(trans), hook)) {
8538+
err = -EEXIST;
8539+
goto err_flowtable_update_hook;
8540+
}
85118541
}
85128542
}
85138543

0 commit comments

Comments
 (0)