Re: [syzbot] [bluetooth?] KASAN: slab-use-after-free Read in mgmt_remove_adv_monitor_sync

Mazin Alhaddad
2024-12-08T21:44:34Z

[-- Attachment #1.1: Type: text/plain, Size: 84 bytes --]

#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master

[-- Attachment #2: 0001-TEST.patch --]
[-- Type: text/plain, Size: 2485 bytes --]

From c4f2ebd743c6196b9c25e829c07a82d5aef80349 Mon Sep 17 00:00:00 2001
From: Mazin AlHaddad <mazin@getstate.dev>
Date: Sun, 8 Dec 2024 18:52:54 +0300
Subject: [PATCH] TEST

---
net/bluetooth/hci_sync.c | 5 +++--
net/bluetooth/mgmt.c | 18 ++++++++++++++++--
2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index c86f4e42e..aa5aa3fed 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -5197,6 +5197,9 @@ int hci_dev_close_sync(struct hci_dev *hdev)
*/
drain_workqueue(hdev->workqueue);

+ /* flush cmd work */
+ flush_work(&hdev->cmd_work);
+
hci_dev_lock(hdev);

hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
@@ -5234,8 +5237,6 @@ int hci_dev_close_sync(struct hci_dev *hdev)
clear_bit(HCI_INIT, &hdev->flags);
}

- /* flush cmd work */
- flush_work(&hdev->cmd_work);

/* Drop queues */
skb_queue_purge(&hdev->rx_q);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index b31192d47..fa369b845 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -5519,9 +5519,18 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
{
struct mgmt_rp_remove_adv_monitor rp;
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_cp_remove_adv_monitor *cp = cmd->param;
+ struct mgmt_cp_remove_adv_monitor *cp;
+
+ if (status == -EINVAL || cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)){
+ return;
+ }

hci_dev_lock(hdev);
+ // if called while device is closing, status will be invalid.
+ // and cmd is cleared by __mgmt_power_off
+
+
+ cp = cmd->param;

rp.monitor_handle = cp->monitor_handle;

@@ -5540,6 +5549,8 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
static int mgmt_remove_adv_monitor_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
+ if (cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev))
+ return -EINVAL;
struct mgmt_cp_remove_adv_monitor *cp = cmd->param;
u16 handle = __le16_to_cpu(cp->monitor_handle);

@@ -9544,8 +9555,11 @@ void __mgmt_power_off(struct hci_dev *hdev)
*/
if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
match.mgmt_status = MGMT_STATUS_INVALID_INDEX;
- else
+ else {
+ match.mgmt_status = MGMT_STATUS_BUSY;
+ mgmt_pending_foreach(MGMT_OP_REMOVE_ADV_MONITOR, hdev, cmd_status_rsp, &match);
match.mgmt_status = MGMT_STATUS_NOT_POWERED;
+ }

mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match);

--
2.46.0