* [PATCH] Bluetooth: hci_sync: Copy the LE accept list under hdev->lock
@ 2026-10-22 12:16 Cen Zhang
2026-10-22 13:13 ` bluez.test.bot
0 siblings, 1 reply; 2+ messages in thread
From: Cen Zhang @ 2026-10-22 12:16 UTC (permalink / raw)
To: marcel, luiz.dentz
Cc: linux-bluetooth, linux-kernel, baijiaju1990, jjzuming, zzzccc427
The LE accept-list mirror consists of bdaddr_list entries that are
added, removed and freed under hdev->lock. The ordinary branch of
hci_update_accept_list_sync() traverses this list without that lock.
The request worker's req_lock does not serialize raw HCI completions,
and the RCU sections protect connection and pending-action lookups,
not the accept-list nodes.
Changing connectability can reach this iterator through
set_connectable_sync(), hci_update_connectable_sync(),
hci_update_passive_scan_sync() and hci_passive_scan_sync(). With a
populated mirror, a privileged raw HCI sender can issue
HCI_OP_LE_CLEAR_ACCEPT_LIST while request work is reconciling it:
Request work HCI event work
select b and successor t
hci_cc_le_clear_accept_list()
hci_dev_lock(hdev)
hci_bdaddr_list_clear()
unlink nodes and kfree(b)
hci_dev_unlock(hdev)
read b->bdaddr_type
The clear completion can therefore free the selected node before its
field read, or the saved successor before the iterator advances.
KASAN reported a one-byte read of bdaddr_type from the freed node.
Copy each entry's address and type under hdev->lock and reconcile the
private array instead. Release the mutex before issuing synchronous
commands, since their completion handlers also acquire it. Free the
copy after iteration and use the existing error path to disable
accept-list filtering if allocation fails.
This change has not been runtime-tested.
KASAN report as below:
==================================================================
BUG: KASAN: slab-use-after-free in hci_passive_scan_sync+0x1cc4/0x1f80
Read of size 1 at addr ffff888105ee6c56 by task kworker/u17:1/499
Workqueue: hci0 hci_cmd_sync_work
Call Trace:
<TASK>
dump_stack_lvl+0x93/0xd0
print_report+0xce/0x630
? hci_passive_scan_sync+0x1cc4/0x1f80
? srso_alias_return_thunk+0x5/0xfbef5
? __virt_addr_valid+0x20d/0x410
? hci_passive_scan_sync+0x1cc4/0x1f80
kasan_report+0xe0/0x110
? hci_passive_scan_sync+0x1cc4/0x1f80
hci_passive_scan_sync+0x1cc4/0x1f80
? pmbd_gate_site_armed+0x31/0x1c0
? __pfx_hci_passive_scan_sync+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? pmbd_probe_hit_cookie+0x10/0x1c0
? __pfx_pmbd_probe_hit_cookie+0x10/0x10
? hci_update_passive_scan_sync+0x43f/0x9e0
? srso_alias_return_thunk+0x5/0xfbef5
? lock_release+0xc8/0x280
hci_update_passive_scan_sync+0x473/0x9e0
hci_update_connectable_sync+0x13c/0x250
set_connectable_sync+0x39/0xb0
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 511:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0xaa/0xb0
__kmalloc_cache_noprof+0x251/0x610
hci_bdaddr_list_add+0x179/0x390
hci_cc_le_add_to_accept_list+0x189/0x2d0
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 511:
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_accept_list+0x80/0x1f0
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 ffff888105ee6c40
which
belongs to the cache kmalloc-32 of size 32
The buggy address is located 22 bytes inside of
freed
32-byte region [ffff888105ee6c40,
ffff888105ee6c60)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000
index:0xffff888105ee69c0 pfn:0x105ee6
flags: 0x200000000000200(workingset|node=0|zone=2)
page_type: f5(slab)
raw: 0200000000000200 ffff888100042780 ffffea0004187150
ffffea00042534d0
raw: ffff888105ee69c0 000000000040003f 00000000f5000000
0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888105ee6b00: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
ffff888105ee6b80: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
>ffff888105ee6c00: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
^
ffff888105ee6c80: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
ffff888105ee6d00: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
==================================================================
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 outer-iterator lifetime issue raised by Sashiko:
https://sashiko.dev/#/patchset/88963
- Copy accept-list addresses before issuing synchronous commands.
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
@@ -2872,6 +2872,31 @@
*n = i;
return p;
+}
+
+static struct conn_params *le_accept_list_copy(struct hci_dev *hdev,
+ size_t *n)
+{
+ struct bdaddr_list *entry;
+ struct conn_params *params;
+ size_t i = 0;
+
+ hci_dev_lock(hdev);
+
+ *n = list_count_nodes(&hdev->le_accept_list);
+ params = kvzalloc_objs(struct conn_params, *n);
+ if (!params)
+ goto unlock;
+
+ list_for_each_entry(entry, &hdev->le_accept_list, list) {
+ bacpy(¶ms[i].addr, &entry->bdaddr);
+ params[i].addr_type = entry->bdaddr_type;
+ i++;
+ }
+
+unlock:
+ hci_dev_unlock(hdev);
+ return params;
}
/* Clear LE Accept List */
@@ -2904,7 +2929,6 @@
static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
{
struct conn_params *params;
- struct bdaddr_list *b, *t;
u8 num_entries = 0;
bool pend_conn, pend_report;
u8 filter_policy;
@@ -2969,20 +2993,27 @@
* report. If not present in either list, then remove it from
* the controller.
*/
- list_for_each_entry_safe(b, t, &hdev->le_accept_list, list) {
+ params = le_accept_list_copy(hdev, &n);
+ if (!params) {
+ err = -ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < n; i++) {
rcu_read_lock();
- if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type)) {
+ if (hci_conn_hash_lookup_le(hdev, ¶ms[i].addr,
+ params[i].addr_type)) {
rcu_read_unlock();
continue;
}
pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns,
- &b->bdaddr,
- b->bdaddr_type);
- pend_report = hci_pend_le_action_lookup(&hdev->pend_le_reports,
- &b->bdaddr,
- b->bdaddr_type);
+ ¶ms[i].addr,
+ params[i].addr_type);
+ pend_report = hci_pend_le_action_lookup(
+ &hdev->pend_le_reports, ¶ms[i].addr,
+ params[i].addr_type);
rcu_read_unlock();
@@ -2990,13 +3021,15 @@
* remove it from the acceptlist.
*/
if (!pend_conn && !pend_report) {
- hci_le_del_accept_list_sync(hdev, &b->bdaddr,
- b->bdaddr_type);
+ hci_le_del_accept_list_sync(hdev, ¶ms[i].addr,
+ params[i].addr_type);
continue;
}
num_entries++;
}
+
+ kvfree(params);
/* Since all no longer valid accept list entries have been
* removed, walk through the list of pending connections
^ permalink raw reply [flat|nested] 2+ messages in thread
* RE: Bluetooth: hci_sync: Copy the LE accept list under hdev->lock
2026-10-22 12:16 [PATCH] Bluetooth: hci_sync: Copy the LE accept list under hdev->lock Cen Zhang
@ 2026-10-22 13:13 ` bluez.test.bot
0 siblings, 0 replies; 2+ messages in thread
From: bluez.test.bot @ 2026-10-22 13:13 UTC (permalink / raw)
To: linux-bluetooth, zzzccc427
[-- Attachment #1: Type: text/plain, Size: 1605 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/series/1191277/
---Test result---
Test Summary:
CheckPatch PASS 0.59 seconds
VerifyFixes PASS 0.11 seconds
VerifySignedoff PASS 0.11 seconds
GitLint PASS 0.37 seconds
SubjectPrefix PASS 0.10 seconds
BuildKernel PASS 29.72 seconds
CheckAllWarning PASS 32.59 seconds
CheckSparse PASS 34.35 seconds
BuildKernel32 PASS 28.54 seconds
CheckKernelLLVM PASS 29.12 seconds
TestRunnerSetup PASS 643.77 seconds
TestRunner_l2cap-tester PASS 14.29 seconds
TestRunner_iso-tester PASS 10.27 seconds
TestRunner_bnep-tester PASS 2.94 seconds
TestRunner_mgmt-tester PASS 85.11 seconds
TestRunner_rfcomm-tester PASS 4.22 seconds
TestRunner_sco-tester PASS 5.35 seconds
TestRunner_ioctl-tester PASS 4.44 seconds
TestRunner_mesh-tester PASS 5.29 seconds
TestRunner_smp-tester PASS 4.83 seconds
TestRunner_userchan-tester PASS 3.01 seconds
TestRunner_6lowpan-tester PASS 4.19 seconds
IncrementalBuild PASS 26.39 seconds
https://github.com/bluez/bluetooth-next/pull/981
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-22 13:13 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-22 12:16 [PATCH] Bluetooth: hci_sync: Copy the LE accept list under hdev->lock Cen Zhang
2026-10-22 13:13 ` bluez.test.bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.