[PATCH 6.6 049/160] Bluetooth: hci_event: fix potential UAF in hci_le_remote_conn_param_req_evt

Greg Kroah-Hartman
2026-04-08T18:22:28Z

From: Pauli Virtanen <pav@iki.fi>

[ Upstream commit b255531b27da336571411248c2a72a350662bd09 ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/hci_event.c | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 4aa445e7f56bc..8b184839b013a 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -6555,25 +6555,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) {
@@ -6586,8 +6592,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);
}
@@ -6601,6 +6605,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,
--
2.53.0