blob: fb635bbe4b53df4ba8f59c04bdeff211d94310a4 [file] [log] [blame]
From 3651c6b7e6c32e4ebea0e8ad19967d8afc915ea0 Mon Sep 17 00:00:00 2001
From: Yun-Hao Chung <howardchung@google.com>
Date: Wed, 4 Oct 2023 10:09:36 +0000
Subject: [PATCH] CHROMIUM: Bluetooth: Use addr instead of hci_conn in LE
Connection complete
Connections may be cleanup while waiting for the commands to complete.
If this happens, it might be the reason we see crashes below which
indicates that the |conn->hdev| is NULL, which can be caused by freeing
the memory of the |hci_conn| earliar.
This fixes the issue by passing the address data instead of the hci_conn
to the HCI command sync work so that we can check if such hci_conn
exists before accessing it.
Call Trace:
? __die_body+0x1f/0x63
? no_context+0x32f/0x506
? exc_page_fault+0x2d8/0x400
? __hci_cmd_sync_sk+0x464/0x4b7 [bluetooth (HASH:202e 2)]
? asm_exc_page_fault+0x1e/0x30
? hci_connect_le_sync+0x49/0x49 [bluetooth (HASH:202e 2)]
? hci_pend_le_action_lookup+0x12/0x68 [bluetooth (HASH:202e 2)]
hci_connect_le_scan_cleanup+0x82/0x252 [bluetooth (HASH:202e 2)]
create_le_conn_complete+0xc9/0xdb [bluetooth (HASH:202e 2)]
hci_cmd_sync_work+0x11a/0x15b [bluetooth (HASH:202e 2)]
process_one_work+0x18d/0x416
worker_thread+0x11a/0x289
kthread+0x13e/0x14f
? process_one_work+0x416/0x416
? kthread_blkcg+0x31/0x31
ret_from_fork+0x1f/0x30
UPSTREAM-TASK=b:303584676
BUG=b:204408624
TEST=run CUJ on hatch v5.15 with MX keys.
TEST=run bluetooth_AdapterLEHealth on hatch v5.15.
Change-Id: Ieb313a0aa7140a8478b3e1e5c0d8c6ccc89d1b6e
Signed-off-by: Yun-Hao Chung <howardchung@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/4914662
Reviewed-by: Archie Pusaka <apusaka@chromium.org>
Tested-by: Yun-Hao Chung <howardchung@chromium.org>
Commit-Queue: Yun-Hao Chung <howardchung@chromium.org>
---
net/bluetooth/hci_conn.c | 51 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 49 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index f9ffcf4602c713366a1551dafdf26b5ad623058e..f1e6367e9e5fe6d03634902c63aa6517462721f7 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -50,6 +50,11 @@ struct conn_handle_t {
__u16 handle;
};
+struct le_conn_data {
+ bdaddr_t dst;
+ u8 dst_type;
+};
+
static const struct sco_param esco_param_cvsd[] = {
{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a, 0x01 }, /* S3 */
{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007, 0x01 }, /* S2 */
@@ -1280,6 +1285,8 @@ u8 hci_conn_set_handle(struct hci_conn *conn, u16 handle)
static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
{
+
+ struct le_conn_data *conn_data = data;
struct hci_conn *conn;
u16 handle = PTR_UINT(data);
@@ -1289,8 +1296,22 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err);
+ if (!conn_data) {
+ bt_dev_err(hdev, "conn_data is NULL");
+ return;
+ }
+
hci_dev_lock(hdev);
+ conn = hci_conn_hash_lookup_le(hdev, &conn_data->dst, conn_data->dst_type);
+
+ if (!conn) {
+ bt_dev_err(hdev,
+ "can't find conn with addr:%pMR,type:%d, skip the connection",
+ &conn_data->dst, conn_data->dst_type);
+ goto done;
+ }
+
if (!err) {
hci_connect_le_scan_cleanup(conn, 0x00);
goto done;
@@ -1305,11 +1326,13 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
hci_conn_failed(conn, bt_status(err));
done:
+ kfree(conn_data);
hci_dev_unlock(hdev);
}
static int hci_connect_le_sync(struct hci_dev *hdev, void *data)
{
+ struct le_conn_data *conn_data = data;
struct hci_conn *conn;
u16 handle = PTR_UINT(data);
@@ -1317,6 +1340,20 @@ static int hci_connect_le_sync(struct hci_dev *hdev, void *data)
if (!conn)
return 0;
+ if (!conn_data) {
+ bt_dev_err(hdev, "conn_data is NULL");
+ return -ECONNABORTED;
+ }
+
+ conn = hci_conn_hash_lookup_le(hdev, &conn_data->dst, conn_data->dst_type);
+
+ if (!conn) {
+ bt_dev_err(hdev,
+ "can't find conn with addr:%pMR,type:%d, skip the connection",
+ &conn_data->dst, conn_data->dst_type);
+ return -ECONNABORTED;
+ }
+
bt_dev_dbg(hdev, "conn %p", conn);
clear_bit(HCI_CONN_SCANNING, &conn->flags);
@@ -1331,6 +1368,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
{
struct hci_conn *conn;
struct smp_irk *irk;
+ struct le_conn_data *conn_data;
int err;
/* Let's make sure that le is enabled.*/
@@ -1391,11 +1429,20 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
conn->sec_level = BT_SECURITY_LOW;
conn->conn_timeout = conn_timeout;
- err = hci_cmd_sync_queue(hdev, hci_connect_le_sync,
- UINT_PTR(conn->handle),
+ conn->state = BT_CONNECT;
+ clear_bit(HCI_CONN_SCANNING, &conn->flags);
+
+ conn_data = kmalloc(sizeof(*conn_data), GFP_KERNEL);
+ if (!conn_data)
+ return ERR_PTR(-ENOMEM);
+ bacpy(&conn_data->dst, dst);
+ conn_data->dst_type = dst_type;
+
+ err = hci_cmd_sync_queue(hdev, hci_connect_le_sync, conn_data,
create_le_conn_complete);
if (err) {
hci_conn_del(conn);
+ kfree(conn_data);
return ERR_PTR(err);
}
--
2.42.0.655.g421f12c284-goog