* [PATCH] Bluetooth: MGMT: Reject LTK loads while connections exist
@ 2026-10-13 16:26 Cen Zhang
2026-10-13 20:08 ` bluez.test.bot
0 siblings, 1 reply; 2+ messages in thread
From: Cen Zhang @ 2026-10-13 16:26 UTC (permalink / raw)
To: marcel, luiz.dentz, johan.hedberg, vinicius.gomes
Cc: linux-bluetooth, linux-kernel, baijiaju1990, jjzuming, zzzccc427
SMP channels retain LTK pointers from the controller's long_term_keys
list until key notification or pairing teardown. load_long_term_keys()
clears that list under hdev->lock without invalidating the channels'
saved pointers. The SMP channel lock does not serialize the management
clear; kfree_rcu() does not keep a key alive for the rest of pairing.
An ongoing pairing and management LTK loads permit this ordering:
1. smp_cmd_initiator_ident() or sc_add_ltk() saves the hci_add_ltk()
result A in smp->ltk.
2. load_long_term_keys() takes hdev->lock, and hci_smp_ltks_clear()
unlinks A and queues its RCU free. The pairing retains its alias.
3. After the RCU grace period, A is freed. A later management load
allocates LTK B at the same address, possibly on another controller.
4. The old pairing reaches smp_chan_destroy() and reads smp->ltk->type
through the saved address.
If B is still live, the old pairing can read its type and remove it
through the stale alias; smp_notify_keys() can also overwrite and report
its fields. If B has already been freed, the access is a use-after-free.
The KASAN report below shows the latter ordering: the stale teardown
read follows allocation and RCU release of the replacement LTK.
Reject MGMT_OP_LOAD_LONG_TERM_KEYS with MGMT_STATUS_BUSY while LE or
BR/EDR ACL connections exist. Both transports can have SMP channels
retaining LTKs, including keys derived over BR/EDR. Check the connection
counts under hdev->lock and keep that lock through clearing and loading.
Connections are published under the same lock, and disconnect tears
down SMP before removing the connection from the hash. A successful
load therefore runs without pairing aliases, and a new connection
cannot acquire one until the replacement finishes.
KASAN report as below:
==================================================================
BUG: KASAN: slab-use-after-free in smp_chan_destroy.isra.0+0xc8b/0x1060
Read of size 1 at addr ffff88810a45eb28 by task kworker/u17:3/506
Workqueue: hci1 hci_rx_work
Call Trace:
<TASK>
dump_stack_lvl+0x93/0xd0
print_report+0xce/0x630
? smp_chan_destroy.isra.0+0xc8b/0x1060
? srso_alias_return_thunk+0x5/0xfbef5
? __virt_addr_valid+0x20d/0x410
? smp_chan_destroy.isra.0+0xc8b/0x1060
kasan_report+0xe0/0x110
? smp_chan_destroy.isra.0+0xc8b/0x1060
smp_chan_destroy.isra.0+0xc8b/0x1060
smp_teardown_cb+0xc7/0x230
l2cap_chan_del+0x123/0x8f0
l2cap_conn_del+0x31b/0x740
? reacquire_held_locks+0x1e7/0x1f0
? __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 523:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0xaa/0xb0
__kmalloc_cache_noprof+0x251/0x610
hci_add_ltk+0x285/0x4c0
load_long_term_keys+0x74a/0x8d0
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 523:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
kasan_save_free_info+0x3b/0x60
__kasan_slab_free+0x5f/0x80
__rcu_free_sheaf_prepare+0x65/0x2a0
rcu_free_sheaf+0x1f/0xe0
rcu_core+0x661/0x1d10
handle_softirqs+0x201/0x930
__irq_exit_rcu+0x110/0x1e0
irq_exit_rcu+0xe/0x20
sysvec_apic_timer_interrupt+0x37/0x80
asm_sysvec_apic_timer_interrupt+0x1a/0x20
The buggy address belongs to the object at ffff88810a45eb00
which belongs to the cache kmalloc-96 of size 96
The buggy address is located 40 bytes inside of
freed 96-byte region [ffff88810a45eb00, ffff88810a45eb60)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0
pfn:0x10a45e
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:
ffff88810a45ea00: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
ffff88810a45ea80: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
>ffff88810a45eb00: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
^
ffff88810a45eb80: 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc fc
ffff88810a45ec00: 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc
==================================================================
Fixes: 346af67b8d11 ("Bluetooth: Add MGMT handlers for dealing with SMP LTK's")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 9f65863e7457d..c3e8ca48a0337 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7460,6 +7460,16 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
hci_dev_lock(hdev);
+ /*
+ * SMP over LE or BR/EDR may retain pointers to the current LTKs.
+ */
+ if (hci_conn_num(hdev, LE_LINK) || hci_conn_num(hdev, ACL_LINK)) {
+ err = mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_LOAD_LONG_TERM_KEYS,
+ MGMT_STATUS_BUSY);
+ goto unlock;
+ }
+
hci_smp_ltks_clear(hdev);
for (i = 0; i < key_count; i++) {
@@ -7513,6 +7523,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
NULL, 0);
+unlock:
hci_dev_unlock(hdev);
return err;
^ permalink raw reply related [flat|nested] 2+ messages in thread
* RE: Bluetooth: MGMT: Reject LTK loads while connections exist
2026-10-13 16:26 [PATCH] Bluetooth: MGMT: Reject LTK loads while connections exist Cen Zhang
@ 2026-10-13 20:08 ` bluez.test.bot
0 siblings, 0 replies; 2+ messages in thread
From: bluez.test.bot @ 2026-10-13 20:08 UTC (permalink / raw)
To: linux-bluetooth, zzzccc427
[-- Attachment #1: Type: text/plain, Size: 1126 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/1184929/
---Test result---
Test Summary:
CheckPatch PASS 0.48 seconds
VerifyFixes PASS 0.45 seconds
VerifySignedoff PASS 0.07 seconds
GitLint PASS 0.31 seconds
SubjectPrefix PASS 0.43 seconds
BuildKernel PASS 18.09 seconds
CheckAllWarning PASS 21.23 seconds
CheckSparse PASS 22.86 seconds
BuildKernel32 PASS 18.59 seconds
CheckKernelLLVM PASS 19.78 seconds
TestRunnerSetup PASS 414.80 seconds
TestRunner_mgmt-tester PASS 80.06 seconds
TestRunner_mesh-tester PASS 4.96 seconds
IncrementalBuild PASS 18.03 seconds
https://github.com/bluez/bluetooth-next/pull/920
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-13 20:08 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-13 16:26 [PATCH] Bluetooth: MGMT: Reject LTK loads while connections exist Cen Zhang
2026-10-13 20:08 ` bluez.test.bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox