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

From: Mazin Alhaddad
Date: Thu Dec 05 2024 - 07:20:28 EST


#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
From 986f27666874745aad6b722cb77ceeacb6a62427 Mon Sep 17 00:00:00 2001
From: Mazin AlHaddad <mazin@xxxxxxxxxxxx>
Date: Thu, 5 Dec 2024 04:55:43 +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..b89cad94f 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -5212,6 +5212,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)
hci_conn_hash_flush(hdev);
/* Prevent data races on hdev->smp_data or hdev->smp_bredr_data */
smp_unregister(hdev);
+ hci_cmd_sync_clear(hdev);
hci_dev_unlock(hdev);

hci_sock_dev_event(hdev, HCI_DEV_DOWN);
@@ -5235,7 +5236,9 @@ int hci_dev_close_sync(struct hci_dev *hdev)
}

/* flush cmd work */
- flush_work(&hdev->cmd_work);
+ cancel_work_sync(&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..cbf4fb1ff 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -5519,7 +5519,12 @@ 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 (cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) {
+ return -ECANCELED;
+ }
+ cp = cmd->param;

hci_dev_lock(hdev);

@@ -5540,8 +5545,15 @@ 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;
- struct mgmt_cp_remove_adv_monitor *cp = cmd->param;
- u16 handle = __le16_to_cpu(cp->monitor_handle);
+ struct mgmt_cp_remove_adv_monitor *cp;
+ u16 handle;
+
+ if (cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) {
+ return -ECANCELED;
+ }
+
+ cp = cmd->param;
+ handle == __le16_to_cpu(cp->monitor_handle);

if (!handle)
return hci_remove_all_adv_monitor(hdev);
--
2.46.0