* [PATCH] Bluetooth: L2CAP: Hold the listener while notifying child teardown
@ 2026-10-08 4:26 Cen Zhang
2026-10-09 14:20 ` patchwork-bot+bluetooth
0 siblings, 1 reply; 2+ messages in thread
From: Cen Zhang @ 2026-10-08 4:26 UTC (permalink / raw)
To: marcel, luiz.dentz
Cc: linux-bluetooth, linux-kernel, baijiaju1990, jjzuming, zzzccc427
A pending child's listener must remain alive until the child's teardown
callback finishes notifying it. l2cap_sock_teardown_cb() saves the raw
bt_sk(sk)->parent pointer, calls bt_accept_unlink(), then invokes
parent->sk_data_ready(). The accept queue holds a reference to the
child, but the callback takes no reference to the listener across
unlink.
When an incoming child has not been accepted, HCI disconnection can
reach l2cap_conn_del() and the child's teardown callback while another
task closes the listener. The listener channel has no connection, so the
child's connection and channel locks do not serialize listener release.
The following ordering is possible:
HCI child teardown Listener release
lock the child socket
save parent
bt_accept_unlink(sk)
drain the empty accept queue
bt_sock_unlink()
shut down the listener channel
sock_orphan()
l2cap_sock_kill()
parent->sk_data_ready(parent)
If no other reference delays freeing the listener, the final
notification reads sk_data_ready through freed socket storage. The child
lock cannot stop listener release once the child is no longer on the
accept queue.
Take a listener socket reference before unlinking the child and release
it after sk_data_ready() returns. While the child remains queued, its
socket lock prevents listener cleanup from completing the dequeue, so
the listener is still alive when the reference is acquired. The
reference then protects the notification after unlink without changing
lock order or the ordering of queue removal and wakeup.
KASAN report as below:
==================================================================
BUG: KASAN: slab-use-after-free in l2cap_sock_teardown_cb+0x467/0x490
Read of size 8 at addr ffff88810b99b188 by task kworker/u17:3/516
Workqueue: hci1 hci_rx_work
Call Trace:
<TASK>
dump_stack_lvl+0x93/0xd0
print_report+0xce/0x630
? l2cap_sock_teardown_cb+0x467/0x490
? srso_alias_return_thunk+0x5/0xfbef5
? __virt_addr_valid+0x20d/0x410
? l2cap_sock_teardown_cb+0x467/0x490
kasan_report+0xe0/0x110
? l2cap_sock_teardown_cb+0x467/0x490
l2cap_sock_teardown_cb+0x467/0x490
l2cap_chan_del+0x123/0x8f0
l2cap_conn_del+0x31b/0x740
? hci_cmd_sync_submit+0x264/0x320
? __pfx_l2cap_disconn_cfm+0x10/0x10
l2cap_disconn_cfm+0x87/0xd0
hci_disconn_complete_evt+0x30f/0x990
? srso_alias_return_thunk+0x5/0xfbef5
hci_event_packet+0x894/0xc70
? __pfx_hci_disconn_complete_evt+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? __pfx_hci_event_packet+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? free_zapped_rcu+0xd0/0x1e0
? srso_alias_return_thunk+0x5/0xfbef5
? lockdep_hardirqs_on_prepare+0xea/0x1a0
? __pfx_hci_cmd_sync_complete+0x10/0x10
? trace_hardirqs_on+0x18/0x160
? srso_alias_return_thunk+0x5/0xfbef5
hci_rx_work+0x367/0xf00
? srso_alias_return_thunk+0x5/0xfbef5
process_one_work+0x908/0x19c0
? __pfx_process_one_work+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? lock_is_held_type+0x8f/0x100
? srso_alias_return_thunk+0x5/0xfbef5
worker_thread+0x65c/0xe40
? __pfx_worker_thread+0x10/0x10
kthread+0x34f/0x460
? srso_alias_return_thunk+0x5/0xfbef5
? __pfx_kthread+0x10/0x10
ret_from_fork+0x659/0x940
? __pfx_ret_from_fork+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? __switch_to+0x74f/0xf80
? __pfx_kthread+0x10/0x10
ret_from_fork_asm+0x1a/0x30
</TASK>
Allocated by task 502:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0xaa/0xb0
__kmalloc_noprof+0x2d7/0x770
sk_prot_alloc+0x13e/0x260
sk_alloc+0x37/0xb40
bt_sock_alloc+0x40/0x3b0
l2cap_sock_create+0x116/0x310
bt_sock_create+0x171/0x330
__sock_create+0x2c4/0x730
__sys_socket+0x141/0x210
__x64_sys_socket+0x77/0xc0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 502:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
kasan_save_free_info+0x3b/0x60
__kasan_slab_free+0x5f/0x80
kfree+0x307/0x580
__sk_destruct+0x64f/0x790
sk_destruct+0xb3/0xd0
__sk_free+0xdd/0x370
sk_free+0x51/0x80
l2cap_sock_kill+0x17a/0x2a0
l2cap_sock_release+0x1d0/0x310
__sock_release+0xb8/0x270
sock_close+0x21/0x30
__fput+0x39f/0xa60
fput_close_sync+0xff/0x200
__x64_sys_close+0x8c/0xf0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The buggy address belongs to the object at ffff88810b99b000
which
belongs to the cache kmalloc-2k of size
2048
The buggy address is located 392 bytes inside of
freed
2048-byte region [ffff88810b99b000,
ffff88810b99b800)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0
pfn:0x10b998
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x200000000000040(head|node=0|zone=2)
page_type: f5(slab)
raw: 0200000000000040 ffff888100042f00 dead000000000100
dead000000000122
raw: 0000000000000000 0000000000080008 00000000f5000000
0000000000000000
head: 0200000000000040 ffff888100042f00 dead000000000100
dead000000000122
head: 0000000000000000 0000000000080008 00000000f5000000
0000000000000000
head: 0200000000000003 fffffffffffffe01 00000000ffffffff
00000000ffffffff
head: 0000000000000000 0000000000000000 00000000ffffffff
0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff88810b99b080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88810b99b100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88810b99b180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff88810b99b200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88810b99b280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index c92f31b997ddb0e2290194e30117cd81e1851949..c86f8d8691d1aeb002cbf5f9aeb321f9d308fa1a 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1751,8 +1751,14 @@
sk->sk_err = err;
if (parent) {
+ /*
+ * Keep the listener alive after unlinking the
+ * child.
+ */
+ sock_hold(parent);
bt_accept_unlink(sk);
parent->sk_data_ready(parent);
+ sock_put(parent);
} else {
sk->sk_state_change(sk);
}
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [PATCH] Bluetooth: L2CAP: Hold the listener while notifying child teardown
2026-10-08 4:26 [PATCH] Bluetooth: L2CAP: Hold the listener while notifying child teardown Cen Zhang
@ 2026-10-09 14:20 ` patchwork-bot+bluetooth
0 siblings, 0 replies; 2+ messages in thread
From: patchwork-bot+bluetooth @ 2026-10-09 14:20 UTC (permalink / raw)
To: Cen Zhang
Cc: marcel, luiz.dentz, linux-bluetooth, linux-kernel, baijiaju1990,
jjzuming
Hello:
This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Thu, 8 Oct 2026 12:26:26 +0800 you wrote:
> A pending child's listener must remain alive until the child's teardown
> callback finishes notifying it. l2cap_sock_teardown_cb() saves the raw
> bt_sk(sk)->parent pointer, calls bt_accept_unlink(), then invokes
> parent->sk_data_ready(). The accept queue holds a reference to the
> child, but the callback takes no reference to the listener across
> unlink.
>
> [...]
Here is the summary with links:
- Bluetooth: L2CAP: Hold the listener while notifying child teardown
https://git.kernel.org/bluetooth/bluetooth-next/c/0d5d090d235d
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] 2+ messages in thread
end of thread, other threads:[~2026-10-09 14:20 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-08 4:26 [PATCH] Bluetooth: L2CAP: Hold the listener while notifying child teardown Cen Zhang
2026-10-09 14:20 ` patchwork-bot+bluetooth
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®