[PATCH RFC] bluetooth: hci: Fix null-ptr-deref in hci_conn_timeout
From: Sungwoo Kim
Date: Tue Jun 16 2026 - 23:55:12 EST
RFC only.
The hci_conn_timeout() function dereferences hdev->sent_cmd when handling
connection timeouts. However, an HCI_EV_HARDWARE_ERROR can trigger an
asynchronous reset sequence that sets hdev->sent_cmd to NULL via
hci_dev_close_sync().
hdev->sent_cmd is dereferenced when conn->disc_work timeout:
hci_conn_timeout()
hci_abort_conn()
switch (hci_skb_event(hdev->sent_cmd)) {
...
However, an HCI hardware error event (HCI_EV_HARDWARE_ERROR) resets the
hci device, setting hdev->sent_cmd = NULL asynchornously:
hci_hardware_error_evt()
hci_error_reset() (async)
hci_dev_do_close()
hci_dev_close_sync()
hdev->sent_cmd = NULL;
As a result, a race condition exists between conn->disc_work execution
and the reset path, which can lead to a NULL pointer dereference when
hci_abort_conn() accesses hdev->sent_cmd.
To fix this, this patch ensures that all pending conn->disc_work
instances are canceled and completed before hdev->sent_cmd is cleared
during the reset path.
This is a provisional fix. Better design suggestions are welcome.
Oops:
Bluetooth: hci4: hardware error 0x00
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000007: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
CPU: 2 UID: 0 PID: 408 Comm: kworker/u17:4 Not tainted 7.1.0-dirty #96 PREEMPT(lazy)
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014
Workqueue: hci1 hci_conn_timeout
RIP: 0010:hci_abort_conn+0x291/0x350 net/bluetooth/hci_conn.c:3196
Fixes: d0b137062b2d ("Bluetooth: hci_sync: Rework init stages")
Acked-by: Dave Tian <daveti@xxxxxxxxxx>
Signed-off-by: Sungwoo Kim <iam@xxxxxxxxxxxx>
---
net/bluetooth/hci_sync.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index df23245d6ccd..dab709448a02 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -5419,6 +5419,14 @@ int hci_dev_close_sync(struct hci_dev *hdev)
/* Drop last sent command */
if (hdev->sent_cmd) {
+ struct hci_conn *c;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(c, &hdev->conn_hash.list, list) {
+ cancel_delayed_work_sync(&c->disc_work);
+ }
+ rcu_read_unlock();
+
cancel_delayed_work_sync(&hdev->cmd_timer);
kfree_skb(hdev->sent_cmd);
hdev->sent_cmd = NULL;
--
2.47.3