mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [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

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®