[PATCH] Bluetooth: fix memory leaks in error path of hci_alloc_dev()
From: Bharath Reddy
Date: Sun May 31 2026 - 10:41:56 EST
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git f377d0025eb0
Syzbot caught a percpu memory leak in the SRCU struct when Bluetooth
HCI UART configuration fails early.
The problem boils down to a bypassed destructor. If device setup fails
before hci_register_dev() completes, the HCI_UNREGISTER flag is never
set. Later, when the device is freed, bt_host_release() sees this flag
is missing, skips hci_release_dev(), and jumps straight to kfree(hdev).
This leaks the SRCU memory, which was also incorrectly being cleaned up
in hci_unregister_dev() which is also skipped during an early abort.
To fix this and properly balance the allocation and teardown paths:
1. Move cleanup_srcu_struct() into hci_release_dev() so it directly
mirrors the allocation in hci_alloc_dev().
2. Unconditionally call hci_release_dev() from bt_host_release() by
dropping the HCI_UNREGISTER check. This is safe for unregistered
devices since it only cleans up resources initialized early on in
hci_alloc_dev().
Reported-by: syzbot+535ecc844591e50588a5@xxxxxxxxxxxxxxxxxxxxxxxxx
Signed-off-by: Bharath Reddy <kbreddy.rpbc@xxxxxxxxx>
---
net/bluetooth/hci_core.c | 3 ++-
net/bluetooth/hci_sysfs.c | 6 ++----
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c46c1236ebfa..f6bc7cb3e55c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2701,7 +2701,6 @@ void hci_unregister_dev(struct hci_dev *hdev)
write_unlock(&hci_dev_list_lock);
synchronize_srcu(&hdev->srcu);
- cleanup_srcu_struct(&hdev->srcu);
disable_work_sync(&hdev->rx_work);
disable_work_sync(&hdev->cmd_work);
@@ -2774,6 +2773,8 @@ void hci_release_dev(struct hci_dev *hdev)
kfree_skb(hdev->sent_cmd);
kfree_skb(hdev->req_skb);
kfree_skb(hdev->recv_event);
+
+ cleanup_srcu_struct(&hdev->srcu);
kfree(hdev);
}
EXPORT_SYMBOL(hci_release_dev);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 041ce9adc378..261b28a25b02 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -83,10 +83,8 @@ static void bt_host_release(struct device *dev)
{
struct hci_dev *hdev = to_hci_dev(dev);
- if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
- hci_release_dev(hdev);
- else
- kfree(hdev);
+ hci_release_dev(hdev);
+
module_put(THIS_MODULE);
}
--
2.34.1