From: Sasha Levin Date: Thu, 28 Sep 2023 11:59:01 +0000 (-0400) Subject: Fixes for 5.10 X-Git-Tag: v6.5.6~88 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=23bf62411aec784013c08a83db7e8e296055fa02;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.10 Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/netfilter-nf_tables-double-hook-unregistration-in-ne.patch b/queue-5.10/netfilter-nf_tables-double-hook-unregistration-in-ne.patch new file mode 100644 index 00000000000..1b74188f92f --- /dev/null +++ b/queue-5.10/netfilter-nf_tables-double-hook-unregistration-in-ne.patch @@ -0,0 +1,145 @@ +From a44991add96b467ad61a4b2c6434b527d7f34a22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Sep 2023 17:30:07 +0200 +Subject: netfilter: nf_tables: double hook unregistration in netns path + +From: Pablo Neira Ayuso + +commit f9a43007d3f7ba76d5e7f9421094f00f2ef202f8 upstream. + +[ This backport includes ab5e5c062f67 ("netfilter: nf_tables: use + kfree_rcu(ptr, rcu) to release hooks in clean_net path") ] + +__nft_release_hooks() is called from pre_netns exit path which +unregisters the hooks, then the NETDEV_UNREGISTER event is triggered +which unregisters the hooks again. + +[ 565.221461] WARNING: CPU: 18 PID: 193 at net/netfilter/core.c:495 __nf_unregister_net_hook+0x247/0x270 +[...] +[ 565.246890] CPU: 18 PID: 193 Comm: kworker/u64:1 Tainted: G E 5.18.0-rc7+ #27 +[ 565.253682] Workqueue: netns cleanup_net +[ 565.257059] RIP: 0010:__nf_unregister_net_hook+0x247/0x270 +[...] +[ 565.297120] Call Trace: +[ 565.300900] +[ 565.304683] nf_tables_flowtable_event+0x16a/0x220 [nf_tables] +[ 565.308518] raw_notifier_call_chain+0x63/0x80 +[ 565.312386] unregister_netdevice_many+0x54f/0xb50 + +Unregister and destroy netdev hook from netns pre_exit via kfree_rcu +so the NETDEV_UNREGISTER path see unregistered hooks. + +Fixes: 767d1216bff8 ("netfilter: nftables: fix possible UAF over chains from packet path in netns") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 54 ++++++++++++++++++++++++++--------- + 1 file changed, 41 insertions(+), 13 deletions(-) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index efbcf85cd6b7a..16e2500e8590b 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -303,12 +303,18 @@ static int nft_netdev_register_hooks(struct net *net, + } + + static void nft_netdev_unregister_hooks(struct net *net, +- struct list_head *hook_list) ++ struct list_head *hook_list, ++ bool release_netdev) + { +- struct nft_hook *hook; ++ struct nft_hook *hook, *next; + +- list_for_each_entry(hook, hook_list, list) ++ 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); ++ } ++ } + } + + static int nf_tables_register_hook(struct net *net, +@@ -334,9 +340,10 @@ static int nf_tables_register_hook(struct net *net, + return nf_register_net_hook(net, &basechain->ops); + } + +-static void nf_tables_unregister_hook(struct net *net, +- const struct nft_table *table, +- struct nft_chain *chain) ++static void __nf_tables_unregister_hook(struct net *net, ++ const struct nft_table *table, ++ struct nft_chain *chain, ++ bool release_netdev) + { + struct nft_base_chain *basechain; + const struct nf_hook_ops *ops; +@@ -351,11 +358,19 @@ static void nf_tables_unregister_hook(struct net *net, + return basechain->type->ops_unregister(net, ops); + + if (nft_base_chain_netdev(table->family, basechain->ops.hooknum)) +- nft_netdev_unregister_hooks(net, &basechain->hook_list); ++ nft_netdev_unregister_hooks(net, &basechain->hook_list, ++ release_netdev); + else + nf_unregister_net_hook(net, &basechain->ops); + } + ++static void nf_tables_unregister_hook(struct net *net, ++ const struct nft_table *table, ++ struct nft_chain *chain) ++{ ++ return __nf_tables_unregister_hook(net, table, chain, false); ++} ++ + static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *trans) + { + struct nftables_pernet *nft_net; +@@ -6822,13 +6837,25 @@ static void nft_unregister_flowtable_hook(struct net *net, + FLOW_BLOCK_UNBIND); + } + +-static void nft_unregister_flowtable_net_hooks(struct net *net, +- struct list_head *hook_list) ++static void __nft_unregister_flowtable_net_hooks(struct net *net, ++ struct list_head *hook_list, ++ bool release_netdev) + { +- struct nft_hook *hook; ++ struct nft_hook *hook, *next; + +- list_for_each_entry(hook, hook_list, list) ++ 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); ++ } ++ } ++} ++ ++static void nft_unregister_flowtable_net_hooks(struct net *net, ++ struct list_head *hook_list) ++{ ++ __nft_unregister_flowtable_net_hooks(net, hook_list, false); + } + + static int nft_register_flowtable_net_hooks(struct net *net, +@@ -9472,9 +9499,10 @@ static void __nft_release_hook(struct net *net, struct nft_table *table) + struct nft_chain *chain; + + list_for_each_entry(chain, &table->chains, list) +- nf_tables_unregister_hook(net, table, chain); ++ __nf_tables_unregister_hook(net, table, chain, true); + list_for_each_entry(flowtable, &table->flowtables, list) +- nft_unregister_flowtable_net_hooks(net, &flowtable->hook_list); ++ __nft_unregister_flowtable_net_hooks(net, &flowtable->hook_list, ++ true); + } + + static void __nft_release_hooks(struct net *net) +-- +2.40.1 + diff --git a/queue-5.10/netfilter-nf_tables-unregister-flowtable-hooks-on-ne.patch b/queue-5.10/netfilter-nf_tables-unregister-flowtable-hooks-on-ne.patch new file mode 100644 index 00000000000..da8e1c5e9c7 --- /dev/null +++ b/queue-5.10/netfilter-nf_tables-unregister-flowtable-hooks-on-ne.patch @@ -0,0 +1,90 @@ +From d4e0e230dc64b104adbbc089f94d8f09e086d95d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Sep 2023 17:30:06 +0200 +Subject: netfilter: nf_tables: unregister flowtable hooks on netns exit + +From: Pablo Neira Ayuso + +commit 6069da443bf65f513bb507bb21e2f87cfb1ad0b6 upstream. + +Unregister flowtable hooks before they are releases via +nf_tables_flowtable_destroy() otherwise hook core reports UAF. + +BUG: KASAN: use-after-free in nf_hook_entries_grow+0x5a7/0x700 net/netfilter/core.c:142 net/netfilter/core.c:142 +Read of size 4 at addr ffff8880736f7438 by task syz-executor579/3666 + +CPU: 0 PID: 3666 Comm: syz-executor579 Not tainted 5.16.0-rc5-syzkaller #0 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 +Call Trace: + + __dump_stack lib/dump_stack.c:88 [inline] + __dump_stack lib/dump_stack.c:88 [inline] lib/dump_stack.c:106 + dump_stack_lvl+0x1dc/0x2d8 lib/dump_stack.c:106 lib/dump_stack.c:106 + print_address_description+0x65/0x380 mm/kasan/report.c:247 mm/kasan/report.c:247 + __kasan_report mm/kasan/report.c:433 [inline] + __kasan_report mm/kasan/report.c:433 [inline] mm/kasan/report.c:450 + kasan_report+0x19a/0x1f0 mm/kasan/report.c:450 mm/kasan/report.c:450 + nf_hook_entries_grow+0x5a7/0x700 net/netfilter/core.c:142 net/netfilter/core.c:142 + __nf_register_net_hook+0x27e/0x8d0 net/netfilter/core.c:429 net/netfilter/core.c:429 + nf_register_net_hook+0xaa/0x180 net/netfilter/core.c:571 net/netfilter/core.c:571 + nft_register_flowtable_net_hooks+0x3c5/0x730 net/netfilter/nf_tables_api.c:7232 net/netfilter/nf_tables_api.c:7232 + nf_tables_newflowtable+0x2022/0x2cf0 net/netfilter/nf_tables_api.c:7430 net/netfilter/nf_tables_api.c:7430 + nfnetlink_rcv_batch net/netfilter/nfnetlink.c:513 [inline] + nfnetlink_rcv_skb_batch net/netfilter/nfnetlink.c:634 [inline] + nfnetlink_rcv_batch net/netfilter/nfnetlink.c:513 [inline] net/netfilter/nfnetlink.c:652 + nfnetlink_rcv_skb_batch net/netfilter/nfnetlink.c:634 [inline] net/netfilter/nfnetlink.c:652 + nfnetlink_rcv+0x10e6/0x2550 net/netfilter/nfnetlink.c:652 net/netfilter/nfnetlink.c:652 + +__nft_release_hook() calls nft_unregister_flowtable_net_hooks() which +only unregisters the hooks, then after RCU grace period, it is +guaranteed that no packets add new entries to the flowtable (no flow +offload rules and flowtable hooks are reachable from packet path), so it +is safe to call nf_flow_table_free() which cleans up the remaining +entries from the flowtable (both software and hardware) and it unbinds +the flow_block. + +Fixes: ff4bf2f42a40 ("netfilter: nf_tables: add nft_unregister_flowtable_hook()") +Reported-by: syzbot+e918523f77e62790d6d9@syzkaller.appspotmail.com +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 52c776b5967ef..efbcf85cd6b7a 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -9466,16 +9466,24 @@ int __nft_release_basechain(struct nft_ctx *ctx) + } + EXPORT_SYMBOL_GPL(__nft_release_basechain); + ++static void __nft_release_hook(struct net *net, struct nft_table *table) ++{ ++ struct nft_flowtable *flowtable; ++ struct nft_chain *chain; ++ ++ list_for_each_entry(chain, &table->chains, list) ++ nf_tables_unregister_hook(net, table, chain); ++ list_for_each_entry(flowtable, &table->flowtables, list) ++ nft_unregister_flowtable_net_hooks(net, &flowtable->hook_list); ++} ++ + static void __nft_release_hooks(struct net *net) + { + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); + struct nft_table *table; +- struct nft_chain *chain; + +- list_for_each_entry(table, &nft_net->tables, list) { +- list_for_each_entry(chain, &table->chains, list) +- nf_tables_unregister_hook(net, table, chain); +- } ++ list_for_each_entry(table, &nft_net->tables, list) ++ __nft_release_hook(net, table); + } + + static void __nft_release_table(struct net *net, struct nft_table *table) +-- +2.40.1 + diff --git a/queue-5.10/series b/queue-5.10/series index d5304e7c73e..342302491d9 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -59,3 +59,5 @@ bnxt_en-flush-xdp-for-bnxt_poll_nitroa0-s-napi.patch net-rds-fix-possible-null-pointer-dereference.patch gpio-tb10x-fix-an-error-handling-path-in-tb10x_gpio_.patch i2c-mux-demux-pinctrl-check-the-return-value-of-devm.patch +netfilter-nf_tables-unregister-flowtable-hooks-on-ne.patch +netfilter-nf_tables-double-hook-unregistration-in-ne.patch