]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Bluetooth: hci_event: fix potential UAF in hci_le_remote_conn_param_req_evt
authorPauli Virtanen <pav@iki.fi>
Sun, 29 Mar 2026 13:43:02 +0000 (16:43 +0300)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 1 Apr 2026 20:46:55 +0000 (16:46 -0400)
hci_conn lookup and field access must be covered by hdev lock in
hci_le_remote_conn_param_req_evt, otherwise it's possible it is freed
concurrently.

Extend the hci_dev_lock critical section to cover all conn usage.

Fixes: 95118dd4edfec ("Bluetooth: hci_event: Use of a function table to handle LE subevents")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/hci_event.c

index 81d2f9a3eec96711757d3dfb38b9bf56200e0c07..3ebc5e6d45d98a061809d90847a13894d27518be 100644 (file)
@@ -6784,25 +6784,31 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
        latency = le16_to_cpu(ev->latency);
        timeout = le16_to_cpu(ev->timeout);
 
+       hci_dev_lock(hdev);
+
        hcon = hci_conn_hash_lookup_handle(hdev, handle);
-       if (!hcon || hcon->state != BT_CONNECTED)
-               return send_conn_param_neg_reply(hdev, handle,
-                                                HCI_ERROR_UNKNOWN_CONN_ID);
+       if (!hcon || hcon->state != BT_CONNECTED) {
+               send_conn_param_neg_reply(hdev, handle,
+                                         HCI_ERROR_UNKNOWN_CONN_ID);
+               goto unlock;
+       }
 
-       if (max > hcon->le_conn_max_interval)
-               return send_conn_param_neg_reply(hdev, handle,
-                                                HCI_ERROR_INVALID_LL_PARAMS);
+       if (max > hcon->le_conn_max_interval) {
+               send_conn_param_neg_reply(hdev, handle,
+                                         HCI_ERROR_INVALID_LL_PARAMS);
+               goto unlock;
+       }
 
-       if (hci_check_conn_params(min, max, latency, timeout))
-               return send_conn_param_neg_reply(hdev, handle,
-                                                HCI_ERROR_INVALID_LL_PARAMS);
+       if (hci_check_conn_params(min, max, latency, timeout)) {
+               send_conn_param_neg_reply(hdev, handle,
+                                         HCI_ERROR_INVALID_LL_PARAMS);
+               goto unlock;
+       }
 
        if (hcon->role == HCI_ROLE_MASTER) {
                struct hci_conn_params *params;
                u8 store_hint;
 
-               hci_dev_lock(hdev);
-
                params = hci_conn_params_lookup(hdev, &hcon->dst,
                                                hcon->dst_type);
                if (params) {
@@ -6815,8 +6821,6 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
                        store_hint = 0x00;
                }
 
-               hci_dev_unlock(hdev);
-
                mgmt_new_conn_param(hdev, &hcon->dst, hcon->dst_type,
                                    store_hint, min, max, latency, timeout);
        }
@@ -6830,6 +6834,9 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
        cp.max_ce_len = 0;
 
        hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(cp), &cp);
+
+unlock:
+       hci_dev_unlock(hdev);
 }
 
 static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, void *data,