mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] Bluetooth: mgmt: Remove mesh cleanup from the socket destructor
@ 2026-10-12  1:58 Cen Zhang
  0 siblings, 0 replies; only message in thread
From: Cen Zhang @ 2026-10-12  1:58 UTC (permalink / raw)
  To: marcel, luiz.dentz, brian.gix
  Cc: linux-bluetooth, linux-kernel, baijiaju1990, jjzuming, zzzccc427

mgmt_mesh_add() takes a socket reference before linking a mesh
transmission, and mgmt_mesh_remove() unlinks it before dropping that
reference. A socket reaching hci_sock_destruct() therefore cannot own
any entries in mesh_pending. Nevertheless, the destructor calls
mgmt_cleanup(), which scans every controller's mesh_pending list without
protecting the entries against request completion.

With mesh enabled on an LE controller, a pending transmission owned by
socket B can complete while an unrelated socket A is being destroyed.
For a successful send, mesh_send_start_complete() schedules
mesh_send_done(), which queues mesh_send_done_sync() on the controller's
request workqueue. While the controller remains registered, the paths
can interleave as follows:

1. A enters hci_sock_destruct() -> mgmt_cleanup(), and mgmt_mesh_next()
   obtains a pointer to B's linked mesh_tx.
2. B's worker runs mesh_send_done_sync() -> mesh_send_complete() ->
   mgmt_mesh_remove(), unlinks mesh_tx, drops B's socket reference and
   frees the entry.
3. A reads mesh_tx->sk to compare it with A's socket, accessing freed
   memory.

The hci_dev_list_lock held by A protects controller membership, but B's
completion does not acquire it and can free the entry before A's read.
The socket reference held by the entry keeps B alive, but does not keep
B's mesh_tx alive for A's traversal. Start-error completion can remove
the same entry through mesh_send_start_complete() as well.

Remove the destructor's mesh cleanup call. The existing socket
references ensure that all of that socket's mesh entries are unlinked
before destruction. Mesh completion and cancellation already manage
the entries' lifetime, so the destructor need only purge its queues.

KASAN report as below:

    ==================================================================
    BUG: KASAN: slab-use-after-free in mgmt_mesh_next+0x119/0x140
    Read of size 8 at addr ffff88810c25cf20 by task python3/490

    CPU: 3 UID: 0 PID: 490 Comm: python3 Not tainted
    7.2.0-rc6-pmb-bt-functional-v1+ #1 PREEMPT(lazy)
    Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix,
    1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
    Call Trace:
     <TASK>
     dump_stack_lvl+0x93/0xd0
     print_report+0xce/0x630
     ? mgmt_mesh_next+0x119/0x140
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __virt_addr_valid+0x20d/0x410
     ? mgmt_mesh_next+0x119/0x140
     kasan_report+0xe0/0x110
     ? mgmt_mesh_next+0x119/0x140
     ? __pfx_sock_close+0x10/0x10
     mgmt_mesh_next+0x119/0x140
     mgmt_cleanup+0x6c/0xe0
     ? __pfx_hci_sock_destruct+0x10/0x10
     hci_sock_destruct+0x1a/0x50
     __sk_destruct+0x85/0x790
     ? __pfx_sock_close+0x10/0x10
     sk_destruct+0xb3/0xd0
     __sk_free+0xdd/0x370
     sk_free+0x51/0x80
     hci_sock_release+0x339/0x550
     __sock_release+0xb8/0x270
     sock_close+0x21/0x30
     __fput+0x39f/0xa60
     fput_close_sync+0xff/0x200
     ? __pfx_fput_close_sync+0x10/0x10
     ? dnotify_flush+0x22/0x4b0
     __x64_sys_close+0x8c/0xf0
     do_syscall_64+0x115/0x6a0
     entry_SYSCALL_64_after_hwframe+0x77/0x7f
    RIP: 0033:0x7f057299a687
    Code: 48 89 fa 4c 89 df e8 58 b3 00 00 8b 93 08 03 00 00 59 5e 48 83 f8
    fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f
    1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff
    RSP: 002b:00007fffcf66d4a0 EFLAGS: 00000202 ORIG_RAX: 0000000000000003
    RAX: ffffffffffffffda RBX: 00007f0572906780 RCX: 00007f057299a687
    RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000005
    RBP: 0000000000000005 R08: 0000000000000000 R09: 0000000000000000
    R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000a83590
    R13: 0000000000a83590 R14: 0000000000000000 R15: 00007f0572744188
     </TASK>

    Allocated by task 490:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     __kasan_kmalloc+0xaa/0xb0
     __kmalloc_cache_noprof+0x251/0x610
     mgmt_mesh_add+0x5d/0x3e0
     mesh_send+0x22d/0x6c0
     hci_sock_sendmsg+0x128b/0x22e0
     __sys_sendto+0x425/0x470
     __x64_sys_sendto+0xe5/0x1c0
     do_syscall_64+0x115/0x6a0
     entry_SYSCALL_64_after_hwframe+0x77/0x7f

    Freed by task 492:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     kasan_save_free_info+0x3b/0x60
     __kasan_slab_free+0x5f/0x80
     kfree+0x307/0x580
     mesh_send_done_sync+0x115/0x180
     hci_cmd_sync_work+0x1b3/0x450
     process_one_work+0x908/0x19c0
     worker_thread+0x65c/0xe40
     kthread+0x34f/0x460
     ret_from_fork+0x659/0x940
     ret_from_fork_asm+0x1a/0x30

    The buggy address belongs to the object at ffff88810c25cf00
     which belongs to the cache kmalloc-96 of size 96
    The buggy address is located 32 bytes inside of
     freed 96-byte region [ffff88810c25cf00, ffff88810c25cf60)

    The buggy address belongs to the physical page:
    page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0
    pfn:0x10c25c
    flags: 0x200000000000000(node=0|zone=2)
    page_type: f5(slab)
    raw: 0200000000000000 ffff888100042280 dead000000000100
    dead000000000122
    raw: 0000000000000000 0000000000200020 00000000f5000000
    0000000000000000
    page dumped because: kasan: bad access detected

    Memory state around the buggy address:
     ffff88810c25ce00: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
     ffff88810c25ce80: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
    >ffff88810c25cf00: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
                                   ^
     ffff88810c25cf80: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
     ffff88810c25d000: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
    ==================================================================

Fixes: b338d91703fa ("Bluetooth: Implement support for Mesh")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---

diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index b26f065d0c18ff3a7cd4b2be1f3fc44d1d2a0605..24cfa6db7654255e5192be75fad49478db251817 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -2186,7 +2186,6 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
 
 static void hci_sock_destruct(struct sock *sk)
 {
-	mgmt_cleanup(sk);
 	skb_queue_purge(&sk->sk_receive_queue);
 	skb_queue_purge(&sk->sk_write_queue);
 	skb_queue_purge(&sk->sk_error_queue);

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-10-12  1:58 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-12  1:58 [PATCH] Bluetooth: mgmt: Remove mesh cleanup from the socket destructor Cen Zhang

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®