]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Bluetooth: mgmt: fix locking in unpair_device/disconnect_sync
authorPauli Virtanen <pav@iki.fi>
Fri, 10 Jul 2026 08:23:41 +0000 (11:23 +0300)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 13 Jul 2026 14:08:46 +0000 (10:08 -0400)
Dereferencing RCU-protected pointers outside critical sections is
invalid and may lead to UAF.

Take hdev->lock for hci_conn lookup and hci_abort_conn().  Don't use RCU
to ensure the conn is fully initialized at this point.

Fixes: 227a0cdf4a028 ("Bluetooth: MGMT: Fix not generating command complete for MGMT_OP_DISCONNECT")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/mgmt.c

index a0a491e5311e10f82eb2abbe576c3f8780c1c2df..f3437a3fe4a15bd541046c68381e1814bd8d8a10 100644 (file)
@@ -3091,6 +3091,8 @@ static int unpair_device_sync(struct hci_dev *hdev, void *data)
        struct mgmt_cp_unpair_device *cp = cmd->param;
        struct hci_conn *conn;
 
+       hci_dev_lock(hdev);
+
        if (cp->addr.type == BDADDR_BREDR)
                conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
                                               &cp->addr.bdaddr);
@@ -3098,6 +3100,11 @@ static int unpair_device_sync(struct hci_dev *hdev, void *data)
                conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
                                               le_addr_type(cp->addr.type));
 
+       if (conn)
+               hci_conn_get(conn);
+
+       hci_dev_unlock(hdev);
+
        if (!conn)
                return 0;
 
@@ -3105,6 +3112,7 @@ static int unpair_device_sync(struct hci_dev *hdev, void *data)
         * will clean up the connection no matter the error.
         */
        hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
+       hci_conn_put(conn);
 
        return 0;
 }
@@ -3252,6 +3260,8 @@ static int disconnect_sync(struct hci_dev *hdev, void *data)
        struct mgmt_cp_disconnect *cp = cmd->param;
        struct hci_conn *conn;
 
+       hci_dev_lock(hdev);
+
        if (cp->addr.type == BDADDR_BREDR)
                conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
                                               &cp->addr.bdaddr);
@@ -3259,6 +3269,11 @@ static int disconnect_sync(struct hci_dev *hdev, void *data)
                conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
                                               le_addr_type(cp->addr.type));
 
+       if (conn)
+               hci_conn_get(conn);
+
+       hci_dev_unlock(hdev);
+
        if (!conn)
                return -ENOTCONN;
 
@@ -3266,6 +3281,7 @@ static int disconnect_sync(struct hci_dev *hdev, void *data)
         * will clean up the connection no matter the error.
         */
        hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
+       hci_conn_put(conn);
 
        return 0;
 }