* [PATCH] Bluetooth: hci_sync: Drain LE timeouts before disconnecting
@ 2026-10-13 16:31 Cen Zhang
0 siblings, 0 replies; only message in thread
From: Cen Zhang @ 2026-10-13 16:31 UTC (permalink / raw)
To: marcel, luiz.dentz, pav
Cc: linux-bluetooth, linux-kernel, baijiaju1990, jjzuming, zzzccc427
A pending LE peripheral connection can be deleted by power-off while its
le_conn_timeout callback is running on hdev->workqueue. The callback uses
a raw hci_conn pointer and waits for hdev->lock before calling
hci_conn_failed(). On the request workqueue, hci_disconnect_all_sync() can
abort the same connection first. hci_conn_del() cancels the timeout
without waiting for a running callback, and the walker's final
hci_conn_put() can free the connection before the timeout resumes. The
subsequent conn->hdev read in hci_conn_failed() is a use-after-free.
Disable and drain le_conn_timeout in hci_disconnect_all_sync() before
hci_abort_conn_sync(), while the walker's existing reference still keeps
the connection alive. Do this outside RCU and before taking hdev->lock so
the callback can finish, and prevent the timeout from being requeued
during teardown. If the callback removes the connection, the existing
hash check in hci_abort_conn_sync() avoids deleting it again.
A matching KASAN report from an instrumented kernel showed:
BUG: KASAN: slab-use-after-free in hci_conn_failed+0x3f8/0x410
Read of size 8 at addr ffff888119e391b0 by task
Workqueue: hci0 le_conn_timeout
[...]
hci_conn_failed+0x3f8/0x410
le_conn_timeout+0x286/0x360
[...]
Freed by task 509:
[...]
bt_link_release+0x87/0x180
[...]
put_device+0x24/0x30
hci_disconnect_all_sync.constprop.0+0x163/0x460
hci_set_powered_sync+0x48f/0x680
[...]
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_sync.c b/net/bluetooth/hci_sync.c
index efbd2e5387c0b..ba573aeebba88 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -6083,6 +6083,15 @@ static int hci_disconnect_all_sync(struct hci_dev *hdev, u8 reason)
/* Make sure the connection is not freed while unlocking */
conn = hci_conn_get(conn);
rcu_read_unlock();
+
+ /*
+ * The LE timeout takes hdev->lock, so drain it before
+ * deleting the connection. The reference above keeps it
+ * alive while waiting.
+ */
+ if (conn->type == LE_LINK)
+ disable_delayed_work_sync(&conn->le_conn_timeout);
+
/* Disregard possible errors since hci_conn_del shall have been
* called even in case of errors had occurred since it would
* then cause hci_conn_failed to be called which calls
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-13 16:32 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-13 16:31 [PATCH] Bluetooth: hci_sync: Drain LE timeouts before disconnecting 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®