]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Bluetooth: hci_sync: hold conn in hci_connect_acl/le_sync() callbacks
authorPauli Virtanen <pav@iki.fi>
Sat, 25 Jul 2026 09:59:18 +0000 (12:59 +0300)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Tue, 28 Jul 2026 20:13:13 +0000 (16:13 -0400)
There is theoretical UAF if the conn is freed while the hci_sync task
is running.

Hold refcount to avoid that.

Fixes: 881559af5f5c ("Bluetooth: hci_sync: Attempt to dequeue connection attempt")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/hci_sync.c

index aa3d5381881245c7b3890a394a2431b0cf4b2f2e..79cd52974eb030ab7b1e9530585040eeb63f67be 100644 (file)
@@ -7152,12 +7152,23 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
        return err;
 }
 
+static void hci_acl_create_conn_sync_complete(struct hci_dev *hdev, void *data,
+                                             int err)
+{
+       struct hci_conn *conn = data;
+
+       hci_conn_put(conn);
+}
+
 int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn)
 {
        int err;
 
-       err = hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn,
-                                     NULL);
+       err = hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync,
+                                     hci_conn_get(conn),
+                                     hci_acl_create_conn_sync_complete);
+       if (err)
+               hci_conn_put(conn);
        return (err == -EEXIST) ? 0 : err;
 }
 
@@ -7168,36 +7179,41 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
        bt_dev_dbg(hdev, "err %d", err);
 
        if (err == -ECANCELED)
-               return;
+               goto done;
 
        hci_dev_lock(hdev);
 
        if (!hci_conn_valid(hdev, conn))
-               goto done;
+               goto unlock;
 
        if (!err) {
                hci_connect_le_scan_cleanup(conn, 0x00);
-               goto done;
+               goto unlock;
        }
 
        /* Check if connection is still pending */
        if (conn != hci_lookup_le_connect(hdev))
-               goto done;
+               goto unlock;
 
        /* Flush to make sure we send create conn cancel command if needed */
        flush_delayed_work(&conn->le_conn_timeout);
        hci_conn_failed(conn, bt_status(err));
 
-done:
+unlock:
        hci_dev_unlock(hdev);
+done:
+       hci_conn_put(conn);
 }
 
 int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn)
 {
        int err;
 
-       err = hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync, conn,
+       err = hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync,
+                                     hci_conn_get(conn),
                                      create_le_conn_complete);
+       if (err)
+               hci_conn_put(conn);
        return (err == -EEXIST) ? 0 : err;
 }