From: Florian Westphal <fw@strlen.de> mainline inclusion from mainline-v7.1-rc2 commit f3224ee463f8f6f6ced7dcdf6081add4f8128527 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/15588 CVE: CVE-2026-46324 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- nft_netdev_unregister_hooks and __nft_unregister_flowtable_net_hooks need to use list_del_rcu(), this list can be walked by concurrent dumpers. Add a new helper and use it consistently. Fixes: f9a43007d3f7 ("netfilter: nf_tables: double hook unregistration in netns path") Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Conflicts: net/netfilter/nf_tables_api.c [1.The nf_tables_updchain() hook-list teardown path present in mainline (where hook.list lives on the stack and uses list_del() / nft_netdev_hook_free_rcu()) does not exist in OLK-5.10, so that hunk was skipped. 2. nf_tables_flowtable_destroy() in OLK-5.10 still performs flowtable->data.type->setup(..., FLOW_BLOCK_UNBIND) for each hook before removing it, a pattern that was refactored out upstream; the helper replacement from mainline therefore could not be used here. The existing list_del_rcu() call is retained, and the immediate kfree(hook) was changed to kfree_rcu(hook, rcu) to match the RCU-safe freeing used by the new helper. 3. Other hunks were applied manually by introducing the nft_netdev_hook_unlink_free_rcu() helper and using it consistently wherever OLK-5.10 already performed list_del_rcu()/kfree_rcu() on a netdev/flowtable hook, and by converting the two list_del() callers (nft_netdev_unregister_hooks and __nft_unregister_flowtable_net_hooks) to list_del_rcu() as required by the CVE fix. ] Signed-off-by: Dong Chenchen <dongchenchen2@huawei.com> --- net/netfilter/nf_tables_api.c | 38 ++++++++++++++++------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 2beef989cced..b97c4d0cf1d9 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -303,6 +303,12 @@ static int nft_netdev_register_hooks(struct net *net, return err; } +static void nft_netdev_hook_unlink_free_rcu(struct nft_hook *hook) +{ + list_del_rcu(&hook->list); + kfree_rcu(hook, rcu); +} + static void nft_netdev_unregister_hooks(struct net *net, struct list_head *hook_list, bool release_netdev) @@ -311,10 +317,8 @@ static void nft_netdev_unregister_hooks(struct net *net, list_for_each_entry_safe(hook, next, hook_list, list) { nf_unregister_net_hook(net, &hook->ops); - if (release_netdev) { - list_del(&hook->list); - kfree_rcu(hook, rcu); - } + if (release_netdev) + nft_netdev_hook_unlink_free_rcu(hook); } } @@ -1932,10 +1936,8 @@ void nf_tables_chain_destroy(struct nft_ctx *ctx) if (nft_base_chain_netdev(ctx->family, basechain->ops.hooknum)) { list_for_each_entry_safe(hook, next, - &basechain->hook_list, list) { - list_del_rcu(&hook->list); - kfree_rcu(hook, rcu); - } + &basechain->hook_list, list) + nft_netdev_hook_unlink_free_rcu(hook); } module_put(basechain->type->owner); if (rcu_access_pointer(basechain->stats)) { @@ -7004,10 +7006,8 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net, list_for_each_entry_safe(hook, next, hook_list, list) { nf_unregister_net_hook(net, &hook->ops); - if (release_netdev) { - list_del(&hook->list); - kfree_rcu(hook, rcu); - } + if (release_netdev) + nft_netdev_hook_unlink_free_rcu(hook); } } @@ -7065,8 +7065,7 @@ static int nft_register_flowtable_net_hooks(struct net *net, break; nft_unregister_flowtable_hook(net, flowtable, hook); - list_del_rcu(&hook->list); - kfree_rcu(hook, rcu); + nft_netdev_hook_unlink_free_rcu(hook); } return err; @@ -7076,10 +7075,8 @@ static void nft_flowtable_hooks_destroy(struct list_head *hook_list) { struct nft_hook *hook, *next; - list_for_each_entry_safe(hook, next, hook_list, list) { - list_del_rcu(&hook->list); - kfree_rcu(hook, rcu); - } + list_for_each_entry_safe(hook, next, hook_list, list) + nft_netdev_hook_unlink_free_rcu(hook); } static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh, @@ -7147,8 +7144,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh, list_for_each_entry_safe(hook, next, &flowtable_hook.list, list) { if (unregister) nft_unregister_flowtable_hook(ctx->net, flowtable, hook); - list_del_rcu(&hook->list); - kfree_rcu(hook, rcu); + nft_netdev_hook_unlink_free_rcu(hook); } return err; @@ -7639,7 +7635,7 @@ static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable) flowtable->data.type->setup(&flowtable->data, hook->ops.dev, FLOW_BLOCK_UNBIND); list_del_rcu(&hook->list); - kfree(hook); + kfree_rcu(hook, rcu); } kfree(flowtable->name); module_put(flowtable->data.type->owner); -- 2.43.0