* [PATCH v1 net 0/2] gtp/geneve: Suppress list_del() splat during ->exit_batch_rtnl().
@ 2025-02-17 20:37 Kuniyuki Iwashima
2025-02-17 20:37 ` [PATCH v1 net 1/2] gtp: Suppress list corruption splat in gtp_net_exit_batch_rtnl() Kuniyuki Iwashima
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Kuniyuki Iwashima @ 2025-02-17 20:37 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Brad Spengler, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
The common pattern in tunnel device's ->exit_batch_rtnl() is iterating
two netdev lists for each netns: (i) for_each_netdev() to clean up
devices in the netns, and (ii) the device type specific list to clean
up devices in other netns.
list_for_each_entry(net, net_list, exit_list) {
for_each_netdev_safe(net, dev, next) {
/* (i) call unregister_netdevice_queue(dev, list) */
}
list_for_each_entry_safe(xxx, xxx_next, &net->yyy, zzz) {
/* (ii) call unregister_netdevice_queue(xxx->dev, list) */
}
}
Then, ->exit_batch_rtnl() could touch the same device twice.
Say we have two netns A & B and device B that is created in netns A and
moved to netns B.
1. cleanup_net() processes netns A and then B.
2. ->exit_batch_rtnl() finds the device B while iterating netns A's (ii)
[ device B is not yet unlinked from netns B as
unregister_netdevice_many() has not been called. ]
3. ->exit_batch_rtnl() finds the device B while iterating netns B's (i)
gtp and geneve calls ->dellink() at 2. and 3. that calls list_del() for (ii)
and unregister_netdevice_queue().
Calling unregister_netdevice_queue() twice is fine because it uses
list_move_tail(), but the 2nd list_del() triggers a splat when
CONFIG_DEBUG_LIST is enabled.
Possible solution is either of
(a) Use list_del_init() in ->dellink()
(b) Iterate dev with empty ->unreg_list for (i) like
#define for_each_netdev_alive(net, d) \
list_for_each_entry(d, &(net)->dev_base_head, dev_list) \
if (list_empty(&d->unreg_list))
(c) Remove (i) and delegate it to default_device_exit_batch().
This series avoids the 2nd ->dellink() by (c) to suppress the splat for
gtp and geneve.
Note that IPv4/IPv6 tunnels calls just unregister_netdevice() during
->exit_batch_rtnl() and dev is unlinked from (ii) later in ->ndo_uninit(),
so they are safe.
Also, pfcp has the same pattern but is safe because
unregister_netdevice_many() is called for each netns.
Kuniyuki Iwashima (2):
gtp: Suppress list corruption splat in gtp_net_exit_batch_rtnl().
geneve: Suppress list corruption splat in geneve_destroy_tunnels().
drivers/net/geneve.c | 7 -------
drivers/net/gtp.c | 5 -----
2 files changed, 12 deletions(-)
--
2.39.5 (Apple Git-154)
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v1 net 1/2] gtp: Suppress list corruption splat in gtp_net_exit_batch_rtnl().
2025-02-17 20:37 [PATCH v1 net 0/2] gtp/geneve: Suppress list_del() splat during ->exit_batch_rtnl() Kuniyuki Iwashima
@ 2025-02-17 20:37 ` Kuniyuki Iwashima
2025-02-17 20:37 ` [PATCH v1 net 2/2] geneve: Suppress list corruption splat in geneve_destroy_tunnels() Kuniyuki Iwashima
2025-02-20 3:00 ` [PATCH v1 net 0/2] gtp/geneve: Suppress list_del() splat during ->exit_batch_rtnl() patchwork-bot+netdevbpf
2 siblings, 0 replies; 4+ messages in thread
From: Kuniyuki Iwashima @ 2025-02-17 20:37 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Brad Spengler, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev,
Pablo Neira Ayuso, Harald Welte
Brad Spengler reported the list_del() corruption splat in
gtp_net_exit_batch_rtnl(). [0]
Commit eb28fd76c0a0 ("gtp: Destroy device along with udp socket's netns
dismantle.") added the for_each_netdev() loop in gtp_net_exit_batch_rtnl()
to destroy devices in each netns as done in geneve and ip tunnels.
However, this could trigger ->dellink() twice for the same device during
->exit_batch_rtnl().
Say we have two netns A & B and gtp device B that resides in netns B but
whose UDP socket is in netns A.
1. cleanup_net() processes netns A and then B.
2. gtp_net_exit_batch_rtnl() finds the device B while iterating
netns A's gn->gtp_dev_list and calls ->dellink().
[ device B is not yet unlinked from netns B
as unregister_netdevice_many() has not been called. ]
3. gtp_net_exit_batch_rtnl() finds the device B while iterating
netns B's for_each_netdev() and calls ->dellink().
gtp_dellink() cleans up the device's hash table, unlinks the dev from
gn->gtp_dev_list, and calls unregister_netdevice_queue().
Basically, calling gtp_dellink() multiple times is fine unless
CONFIG_DEBUG_LIST is enabled.
Let's remove for_each_netdev() in gtp_net_exit_batch_rtnl() and
delegate the destruction to default_device_exit_batch() as done
in bareudp.
[0]:
list_del corruption, ffff8880aaa62c00->next (autoslab_size_M_dev_P_net_core_dev_11127_8_1328_8_S_4096_A_64_n_139+0xc00/0x1000 [slab object]) is LIST_POISON1 (ffffffffffffff02) (prev is 0xffffffffffffff04)
kernel BUG at lib/list_debug.c:58!
Oops: invalid opcode: 0000 [#1] PREEMPT SMP KASAN
CPU: 1 UID: 0 PID: 1804 Comm: kworker/u8:7 Tainted: G T 6.12.13-grsec-full-20250211091339 #1
Tainted: [T]=RANDSTRUCT
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
Workqueue: netns cleanup_net
RIP: 0010:[<ffffffff84947381>] __list_del_entry_valid_or_report+0x141/0x200 lib/list_debug.c:58
Code: c2 76 91 31 c0 e8 9f b1 f7 fc 0f 0b 4d 89 f0 48 c7 c1 02 ff ff ff 48 89 ea 48 89 ee 48 c7 c7 e0 c2 76 91 31 c0 e8 7f b1 f7 fc <0f> 0b 4d 89 e8 48 c7 c1 04 ff ff ff 48 89 ea 48 89 ee 48 c7 c7 60
RSP: 0018:fffffe8040b4fbd0 EFLAGS: 00010283
RAX: 00000000000000cc RBX: dffffc0000000000 RCX: ffffffff818c4054
RDX: ffffffff84947381 RSI: ffffffff818d1512 RDI: 0000000000000000
RBP: ffff8880aaa62c00 R08: 0000000000000001 R09: fffffbd008169f32
R10: fffffe8040b4f997 R11: 0000000000000001 R12: a1988d84f24943e4
R13: ffffffffffffff02 R14: ffffffffffffff04 R15: ffff8880aaa62c08
RBX: kasan shadow of 0x0
RCX: __wake_up_klogd.part.0+0x74/0xe0 kernel/printk/printk.c:4554
RDX: __list_del_entry_valid_or_report+0x141/0x200 lib/list_debug.c:58
RSI: vprintk+0x72/0x100 kernel/printk/printk_safe.c:71
RBP: autoslab_size_M_dev_P_net_core_dev_11127_8_1328_8_S_4096_A_64_n_139+0xc00/0x1000 [slab object]
RSP: process kstack fffffe8040b4fbd0+0x7bd0/0x8000 [kworker/u8:7+netns 1804 ]
R09: kasan shadow of process kstack fffffe8040b4f990+0x7990/0x8000 [kworker/u8:7+netns 1804 ]
R10: process kstack fffffe8040b4f997+0x7997/0x8000 [kworker/u8:7+netns 1804 ]
R15: autoslab_size_M_dev_P_net_core_dev_11127_8_1328_8_S_4096_A_64_n_139+0xc08/0x1000 [slab object]
FS: 0000000000000000(0000) GS:ffff888116000000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000748f5372c000 CR3: 0000000015408000 CR4: 00000000003406f0 shadow CR4: 00000000003406f0
Stack:
0000000000000000 ffffffff8a0c35e7 ffffffff8a0c3603 ffff8880aaa62c00
ffff8880aaa62c00 0000000000000004 ffff88811145311c 0000000000000005
0000000000000001 ffff8880aaa62000 fffffe8040b4fd40 ffffffff8a0c360d
Call Trace:
<TASK>
[<ffffffff8a0c360d>] __list_del_entry_valid include/linux/list.h:131 [inline] fffffe8040b4fc28
[<ffffffff8a0c360d>] __list_del_entry include/linux/list.h:248 [inline] fffffe8040b4fc28
[<ffffffff8a0c360d>] list_del include/linux/list.h:262 [inline] fffffe8040b4fc28
[<ffffffff8a0c360d>] gtp_dellink+0x16d/0x360 drivers/net/gtp.c:1557 fffffe8040b4fc28
[<ffffffff8a0d0404>] gtp_net_exit_batch_rtnl+0x124/0x2c0 drivers/net/gtp.c:2495 fffffe8040b4fc88
[<ffffffff8e705b24>] cleanup_net+0x5a4/0xbe0 net/core/net_namespace.c:635 fffffe8040b4fcd0
[<ffffffff81754c97>] process_one_work+0xbd7/0x2160 kernel/workqueue.c:3326 fffffe8040b4fd88
[<ffffffff81757195>] process_scheduled_works kernel/workqueue.c:3407 [inline] fffffe8040b4fec0
[<ffffffff81757195>] worker_thread+0x6b5/0xfa0 kernel/workqueue.c:3488 fffffe8040b4fec0
[<ffffffff817782a0>] kthread+0x360/0x4c0 kernel/kthread.c:397 fffffe8040b4ff78
[<ffffffff814d8594>] ret_from_fork+0x74/0xe0 arch/x86/kernel/process.c:172 fffffe8040b4ffb8
[<ffffffff8110f509>] ret_from_fork_asm+0x29/0xc0 arch/x86/entry/entry_64.S:399 fffffe8040b4ffe8
</TASK>
Modules linked in:
Fixes: eb28fd76c0a0 ("gtp: Destroy device along with udp socket's netns dismantle.")
Reported-by: Brad Spengler <spender@grsecurity.net>
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
Cc: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: Harald Welte <laforge@gnumonks.org>
---
drivers/net/gtp.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index d64740bf44ed..b7b46c5e6399 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -2481,11 +2481,6 @@ static void __net_exit gtp_net_exit_batch_rtnl(struct list_head *net_list,
list_for_each_entry(net, net_list, exit_list) {
struct gtp_net *gn = net_generic(net, gtp_net_id);
struct gtp_dev *gtp, *gtp_next;
- struct net_device *dev;
-
- for_each_netdev(net, dev)
- if (dev->rtnl_link_ops == >p_link_ops)
- gtp_dellink(dev, dev_to_kill);
list_for_each_entry_safe(gtp, gtp_next, &gn->gtp_dev_list, list)
gtp_dellink(gtp->dev, dev_to_kill);
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v1 net 2/2] geneve: Suppress list corruption splat in geneve_destroy_tunnels().
2025-02-17 20:37 [PATCH v1 net 0/2] gtp/geneve: Suppress list_del() splat during ->exit_batch_rtnl() Kuniyuki Iwashima
2025-02-17 20:37 ` [PATCH v1 net 1/2] gtp: Suppress list corruption splat in gtp_net_exit_batch_rtnl() Kuniyuki Iwashima
@ 2025-02-17 20:37 ` Kuniyuki Iwashima
2025-02-20 3:00 ` [PATCH v1 net 0/2] gtp/geneve: Suppress list_del() splat during ->exit_batch_rtnl() patchwork-bot+netdevbpf
2 siblings, 0 replies; 4+ messages in thread
From: Kuniyuki Iwashima @ 2025-02-17 20:37 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Brad Spengler, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
As explained in the previous patch, iterating for_each_netdev() and
gn->geneve_list during ->exit_batch_rtnl() could trigger ->dellink()
twice for the same device.
If CONFIG_DEBUG_LIST is enabled, we will see a list_del() corruption
splat in the 2nd call of geneve_dellink().
Let's remove for_each_netdev() in geneve_destroy_tunnels() and delegate
that part to default_device_exit_batch().
Fixes: 9593172d93b9 ("geneve: Fix use-after-free in geneve_find_dev().")
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
drivers/net/geneve.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index a1f674539965..dbb3960126ee 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -1902,14 +1902,7 @@ static void geneve_destroy_tunnels(struct net *net, struct list_head *head)
{
struct geneve_net *gn = net_generic(net, geneve_net_id);
struct geneve_dev *geneve, *next;
- struct net_device *dev, *aux;
- /* gather any geneve devices that were moved into this ns */
- for_each_netdev_safe(net, dev, aux)
- if (dev->rtnl_link_ops == &geneve_link_ops)
- geneve_dellink(dev, head);
-
- /* now gather any other geneve devices that were created in this ns */
list_for_each_entry_safe(geneve, next, &gn->geneve_list, next)
geneve_dellink(geneve->dev, head);
}
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v1 net 0/2] gtp/geneve: Suppress list_del() splat during ->exit_batch_rtnl().
2025-02-17 20:37 [PATCH v1 net 0/2] gtp/geneve: Suppress list_del() splat during ->exit_batch_rtnl() Kuniyuki Iwashima
2025-02-17 20:37 ` [PATCH v1 net 1/2] gtp: Suppress list corruption splat in gtp_net_exit_batch_rtnl() Kuniyuki Iwashima
2025-02-17 20:37 ` [PATCH v1 net 2/2] geneve: Suppress list corruption splat in geneve_destroy_tunnels() Kuniyuki Iwashima
@ 2025-02-20 3:00 ` patchwork-bot+netdevbpf
2 siblings, 0 replies; 4+ messages in thread
From: patchwork-bot+netdevbpf @ 2025-02-20 3:00 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, spender, kuni1840,
netdev
Hello:
This series was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Mon, 17 Feb 2025 12:37:03 -0800 you wrote:
> The common pattern in tunnel device's ->exit_batch_rtnl() is iterating
> two netdev lists for each netns: (i) for_each_netdev() to clean up
> devices in the netns, and (ii) the device type specific list to clean
> up devices in other netns.
>
> list_for_each_entry(net, net_list, exit_list) {
> for_each_netdev_safe(net, dev, next) {
> /* (i) call unregister_netdevice_queue(dev, list) */
> }
>
> [...]
Here is the summary with links:
- [v1,net,1/2] gtp: Suppress list corruption splat in gtp_net_exit_batch_rtnl().
https://git.kernel.org/netdev/net/c/4ccacf86491d
- [v1,net,2/2] geneve: Suppress list corruption splat in geneve_destroy_tunnels().
https://git.kernel.org/netdev/net/c/62fab6eef61f
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-02-20 3:00 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-17 20:37 [PATCH v1 net 0/2] gtp/geneve: Suppress list_del() splat during ->exit_batch_rtnl() Kuniyuki Iwashima
2025-02-17 20:37 ` [PATCH v1 net 1/2] gtp: Suppress list corruption splat in gtp_net_exit_batch_rtnl() Kuniyuki Iwashima
2025-02-17 20:37 ` [PATCH v1 net 2/2] geneve: Suppress list corruption splat in geneve_destroy_tunnels() Kuniyuki Iwashima
2025-02-20 3:00 ` [PATCH v1 net 0/2] gtp/geneve: Suppress list_del() splat during ->exit_batch_rtnl() patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).