Skip to content

Commit d7615bd

Browse files
ummakynesgregkh
authored andcommitted
netfilter: nf_tables: reject duplicate device on updates
[ Upstream commit cf5fb87 ] 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 <[email protected]> Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent c4c3133 commit d7615bd

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
@@ -2790,6 +2790,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
27902790
struct nft_chain *chain = ctx->chain;
27912791
struct nft_chain_hook hook = {};
27922792
struct nft_stats __percpu *stats = NULL;
2793+
struct nftables_pernet *nft_net;
27932794
struct nft_hook *h, *next;
27942795
struct nf_hook_ops *ops;
27952796
struct nft_trans *trans;
@@ -2832,6 +2833,20 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
28322833
if (nft_hook_list_find(&basechain->hook_list, h)) {
28332834
list_del(&h->list);
28342835
nft_netdev_hook_free(h);
2836+
continue;
2837+
}
2838+
2839+
nft_net = nft_pernet(ctx->net);
2840+
list_for_each_entry(trans, &nft_net->commit_list, list) {
2841+
if (trans->msg_type != NFT_MSG_NEWCHAIN ||
2842+
trans->table != ctx->table ||
2843+
!nft_trans_chain_update(trans))
2844+
continue;
2845+
2846+
if (nft_hook_list_find(&nft_trans_chain_hooks(trans), h)) {
2847+
nft_chain_release_hook(&hook);
2848+
return -EEXIST;
2849+
}
28352850
}
28362851
}
28372852
} else {
@@ -9033,6 +9048,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
90339048
{
90349049
const struct nlattr * const *nla = ctx->nla;
90359050
struct nft_flowtable_hook flowtable_hook;
9051+
struct nftables_pernet *nft_net;
90369052
struct nft_hook *hook, *next;
90379053
struct nf_hook_ops *ops;
90389054
struct nft_trans *trans;
@@ -9049,6 +9065,20 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
90499065
if (nft_hook_list_find(&flowtable->hook_list, hook)) {
90509066
list_del(&hook->list);
90519067
nft_netdev_hook_free(hook);
9068+
continue;
9069+
}
9070+
9071+
nft_net = nft_pernet(ctx->net);
9072+
list_for_each_entry(trans, &nft_net->commit_list, list) {
9073+
if (trans->msg_type != NFT_MSG_NEWFLOWTABLE ||
9074+
trans->table != ctx->table ||
9075+
!nft_trans_flowtable_update(trans))
9076+
continue;
9077+
9078+
if (nft_hook_list_find(&nft_trans_flowtable_hooks(trans), hook)) {
9079+
err = -EEXIST;
9080+
goto err_flowtable_update_hook;
9081+
}
90529082
}
90539083
}
90549084

0 commit comments

Comments
 (0)