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

From: Mazin Alhaddad
Date: Sun Dec 08 2024 - 10:56:48 EST


#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
From 4f5407c8474ed6747d61412b915c949d9d9c6805 Mon Sep 17 00:00:00 2001
From: Mazin AlHaddad <mazin@xxxxxxxxxxxx>
Date: Sun, 8 Dec 2024 18:52:54 +0300
Subject: [PATCH] TEST

---
net/bluetooth/hci_sync.c | 5 +++--
net/bluetooth/mgmt.c | 12 +++++++++++-
2 files changed, 14 insertions(+), 3 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..b417756ac 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -5519,9 +5519,17 @@ 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;

hci_dev_lock(hdev);
+ // if called while device is closing, status will be invalid.
+ // and cmd is cleared by __mgmt_power_off
+ if (status == -EINVAL || cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)){
+ hci_dev_unlock(hdev);
+ return;
+ }
+
+ cp = cmd->param;

rp.monitor_handle = cp->monitor_handle;

@@ -5540,6 +5548,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);

--
2.46.0