mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] Bluetooth: hci_sync: Protect resolving-list lookups
@ 2026-10-22 12:05 Cen Zhang
  0 siblings, 0 replies; only message in thread
From: Cen Zhang @ 2026-10-22 12:05 UTC (permalink / raw)
  To: marcel, luiz.dentz
  Cc: linux-bluetooth, linux-kernel, baijiaju1990, jjzuming, zzzccc427

The host resolving list is updated under hdev->lock, and each
bdaddr_list_with_irk entry must remain alive throughout a lookup.
hci_le_del_resolve_list_sync() and hci_le_add_resolve_list_sync()
traverse that list without taking the lock.

On an LE privacy-capable controller with a programmed entry, passive
scan reconciliation can reach hci_le_del_resolve_list_sync() while a
privileged HCI_RAW client sends LE Clear Resolving List. The raw
command does not take req_lock, and its successful completion runs
on the controller workqueue independently of request work:

  Request work                     Raw HCI / event work
  hci_le_del_resolve_list_sync()
    lookup loads a list node
                                   hci_sock_sendmsg()
                                     queue LE Clear Resolving List
                                   hci_cc_le_clear_resolv_list()
                                     take hdev->lock
                                     unlink and free the node
                                     release hdev->lock
    read the node's address/type

The clear can free the node after the lookup loads it and before its
address/type read, causing a use-after-free. The report below shows
this access with the delete helper on the faulting stack. The add
helper uses the same unprotected lookup.

Take hdev->lock around each resolving-list membership lookup and
retain only a boolean result. This serializes traversal with clear
completion and keeps entry pointers inside the protected section.
Release the lock before issuing a synchronous HCI command, whose
completion also needs the lock.

KASAN report as below:

    ==================================================================
    BUG: KASAN: slab-use-after-free in
    hci_bdaddr_list_lookup_with_irk+0x106/0x120
    Read of size 1 at addr ffff88810b036e16 by task kworker/u17:0/495

    CPU: 2 UID: 0 PID: 495 Comm: kworker/u17:0 Not tainted
    7.2.0-rc6-pmb-bt-functional-v1+ #3 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
    Workqueue: hci0 hci_cmd_sync_work
    Call Trace:
     <TASK>
     dump_stack_lvl+0x93/0xd0
     print_report+0xce/0x630
     ? hci_bdaddr_list_lookup_with_irk+0x106/0x120
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __virt_addr_valid+0x20d/0x410
     ? hci_bdaddr_list_lookup_with_irk+0x106/0x120
     kasan_report+0xe0/0x110
     ? hci_bdaddr_list_lookup_with_irk+0x106/0x120
     hci_bdaddr_list_lookup_with_irk+0x106/0x120
     hci_le_del_resolve_list_sync.isra.0+0xd6/0x3f0
     ? __pfx_hci_le_del_resolve_list_sync.isra.0+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     hci_le_del_accept_list_sync.isra.0+0x11c/0x290
     ? __pfx_hci_le_del_accept_list_sync.isra.0+0x10/0x10
     ? hci_passive_scan_sync+0x551/0x1e80
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_release+0xc8/0x280
     hci_passive_scan_sync+0x71c/0x1e80
     ? __pfx_hci_passive_scan_sync+0x10/0x10
     ? find_held_lock+0x2b/0x80
     ? hci_lookup_le_connect+0xe1/0x3c0
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? find_held_lock+0x2b/0x80
     ? hci_update_passive_scan_sync+0x437/0x950
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? lock_release+0xc8/0x280
     hci_update_passive_scan_sync+0x461/0x950
     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 495:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     __kasan_kmalloc+0xaa/0xb0
     __kmalloc_cache_noprof+0x251/0x610
     hci_bdaddr_list_add_with_irk+0x183/0x3e0
     hci_cc_le_add_to_resolv_list+0x18c/0x240
     hci_cmd_complete_evt+0x373/0xab0
     hci_event_packet+0x4e8/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 497:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     kasan_save_free_info+0x3b/0x60
     __kasan_slab_free+0x5f/0x80
     kfree+0x307/0x580
     hci_bdaddr_list_clear+0x134/0x230
     hci_cc_le_clear_resolv_list+0x13d/0x240
     hci_cmd_complete_evt+0x373/0xab0
     hci_event_packet+0x4e8/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

    The buggy address belongs to the object at ffff88810b036e00
    which belongs to the cache kmalloc-64 of size 64
    The buggy address is located 22 bytes inside of
    freed 64-byte region [ffff88810b036e00, ffff88810b036e40)

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

    Memory state around the buggy address:
     ffff88810b036d00: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc
     ffff88810b036d80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
    >ffff88810b036e00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
                             ^
     ffff88810b036e80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
     ffff88810b036f00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
    ==================================================================
    Disabling lock debugging due to kernel taint

Fixes: e8907f76544f ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 3")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
Sashiko review follow-up: earlier accept-list patch
  - Address the resolving-list lookup issue raised by Sashiko:
    https://sashiko.dev/#/patchset/88963
  - Protect both resolving-list membership lookups with hdev->lock.

Related accept-list membership fix:
https://lore.kernel.org/r/pm-bluetooth-objects-candidate-0118-v7-e6b713327ef914d6d02a@gmail.com

diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -2448,15 +2448,17 @@
 					bdaddr_t *bdaddr, u8 bdaddr_type)
 {
 	struct hci_cp_le_del_from_resolv_list cp;
-	struct bdaddr_list_with_irk *entry;
+	bool exists;
 
 	if (!ll_privacy_capable(hdev))
 		return 0;
 
 	/* Check if the IRK has been programmed */
-	entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list, bdaddr,
-						bdaddr_type);
-	if (!entry)
+	hci_dev_lock(hdev);
+	exists = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list,
+						 bdaddr, bdaddr_type);
+	hci_dev_unlock(hdev);
+	if (!exists)
 		return 0;
 
 	cp.bdaddr_type = bdaddr_type;
@@ -2512,8 +2514,8 @@
 {
 	struct hci_cp_le_add_to_resolv_list cp;
 	struct smp_irk *irk;
-	struct bdaddr_list_with_irk *entry;
 	struct hci_conn_params *p;
+	bool exists;
 
 	if (!ll_privacy_capable(hdev))
 		return 0;
@@ -2536,10 +2538,11 @@
 		return 0;
 
 	/* Check if the IK has _not_ been programmed yet. */
-	entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list,
-						&params->addr,
-						params->addr_type);
-	if (entry)
+	hci_dev_lock(hdev);
+	exists = hci_bdaddr_list_lookup_with_irk(
+		&hdev->le_resolv_list, &params->addr, params->addr_type);
+	hci_dev_unlock(hdev);
+	if (exists)
 		return 0;
 
 	cp.bdaddr_type = params->addr_type;

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

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

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-22 12:05 [PATCH] Bluetooth: hci_sync: Protect resolving-list lookups 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®