* [PATCH] Bluetooth: hci_conn: Initialize the device before hash insertion
@ 2026-10-24 15:27 Cen Zhang
0 siblings, 0 replies; only message in thread
From: Cen Zhang @ 2026-10-24 15:27 UTC (permalink / raw)
To: marcel, luiz.dentz
Cc: linux-bluetooth, linux-kernel, baijiaju1990, jjzuming, zzzccc427
An hci_conn must have an initialized embedded device before an RCU
reader can acquire a reference to it. __hci_conn_add() instead adds
the connection to conn_hash before hci_conn_init_sysfs() calls
device_initialize(). Holding hdev->lock during creation does not
exclude hci_disconnect_all_sync(), which looks up the connection and
calls hci_conn_get() under RCU without that lock.
When a new incoming ACL request overlaps controller poweroff before
the connection is registered in sysfs, the separate event and request
workqueues can execute this sequence:
1. The event worker holds hdev->lock and publishes a new connection
in __hci_conn_add(), before device_initialize().
2. The request worker finds that connection under RCU, calls
hci_conn_get() and leaves its RCU read-side critical section.
3. The event worker runs hci_conn_init_sysfs(), sets BT_CONNECT in
hci_conn_request_evt() and releases hdev->lock.
4. The request worker calls hci_abort_conn_sync(), which acquires
hdev->lock and reaches hci_conn_failed(), hci_conn_del() and
hci_conn_del_sysfs() to delete the pending connection.
5. After abort returns, the request worker calls hci_conn_put().
device_initialize() resets the kobject reference count to one,
discarding the walker's premature get. If no other device references
exist, deletion of the unregistered device drops that one reference
and bt_link_release() frees the hci_conn. The walker's trailing put
then accesses the freed kobject, as shown by the KASAN report below.
The RCU grace period in hci_conn_hash_del() cannot preserve the walker
after it has left its read-side critical section.
Initialize the device before hci_conn_hash_add() publishes the
connection. The existing RCU publication then makes the initialized
device visible to readers, so the walker takes a valid reference that
survives deletion until its matching put.
KASAN report as below:
==================================================================
BUG: KASAN: slab-use-after-free in kobject_put+0x4f3/0x610
Read of size 1 at addr ffff88811e6fcd2c by task kworker/u17:0/559
Workqueue: hci0 hci_cmd_sync_work
Call Trace:
<TASK>
dump_stack_lvl+0x93/0xd0
print_report+0xce/0x630
? kobject_put+0x4f3/0x610
? srso_alias_return_thunk+0x5/0xfbef5
? __virt_addr_valid+0x20d/0x410
? kobject_put+0x4f3/0x610
kasan_report+0xe0/0x110
? kobject_put+0x4f3/0x610
? hci_disconnect_all_sync.constprop.0+0xd8/0x520
kobject_put+0x4f3/0x610
? hci_disconnect_all_sync.constprop.0+0xd8/0x520
put_device+0x24/0x30
hci_disconnect_all_sync.constprop.0+0x176/0x520
? hci_disconnect_all_sync.constprop.0+0xcd/0x520
? __pfx_hci_disconnect_all_sync.constprop.0+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
hci_set_powered_sync+0x48f/0x680
? __pfx_hci_set_powered_sync+0x10/0x10
? __pfx___mutex_unlock_slowpath+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? lock_is_held_type+0x8f/0x100
set_powered_sync+0xaa/0x150
hci_cmd_sync_work+0x1b3/0x450
? 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 561:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0xaa/0xb0
__kmalloc_cache_noprof+0x251/0x610
__hci_conn_add+0x10c/0x1f70
hci_conn_add_unset+0x72/0x120
hci_conn_request_evt+0xb2b/0xd40
hci_event_packet+0x894/0xc70
hci_rx_work+0x367/0xf00
process_one_work+0x908/0x19c0
worker_thread+0x65c/0xe40
kthread+0x34f/0x460
ret_from_fork+0x659/0x940
ret_from_fork_asm+0x1a/0x30
Freed by task 559:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
kasan_save_free_info+0x3b/0x60
__kasan_slab_free+0x5f/0x80
kfree+0x307/0x580
bt_link_release+0x4a/0xb0
device_release+0xd7/0x280
kobject_put+0x1ad/0x610
put_device+0x24/0x30
hci_conn_del_sysfs+0x15d/0x190
hci_conn_del+0x684/0x1100
hci_abort_conn_sync+0x7d6/0xae0
hci_disconnect_all_sync.constprop.0+0x164/0x520
hci_set_powered_sync+0x48f/0x680
set_powered_sync+0xaa/0x150
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 ffff88811e6fc000
which
belongs to the cache kmalloc-8k of size
8192
The buggy address is located 3372 bytes inside of
freed
8192-byte region [ffff88811e6fc000,
ffff88811e6fe000)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0
pfn:0x11e6f8
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 ffff888100043180 dead000000000122
0000000000000000
raw: 0000000000000000 0000000000020002 00000000f5000000
0000000000000000
head: 0200000000000040 ffff888100043180 dead000000000122
0000000000000000
head: 0000000000000000 0000000000020002 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:
ffff88811e6fcc00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88811e6fcc80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88811e6fcd00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff88811e6fcd80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88811e6fce00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
Fixes: 94d9ba9f9888 ("Bluetooth: hci_sync: Fix UAF in hci_disconnect_all_sync")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index b007f623b2ecc..439ecde8f4d71 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1160,6 +1160,9 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type,
hci_dev_hold(hdev);
+ /* Initialize the device before publishing it to RCU readers. */
+ hci_conn_init_sysfs(conn);
+
hci_conn_hash_add(hdev, conn);
/* The SCO and eSCO connections will only be notified when their
@@ -1171,7 +1174,6 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type,
hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
}
- hci_conn_init_sysfs(conn);
return conn;
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-24 15:27 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-24 15:27 [PATCH] Bluetooth: hci_conn: Initialize the device before hash insertion 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®