Skip to contentSkip to conversation

Bluetooth: hci_conn: Lock parent access during enhanced SCO setup

PATCH Applied Chengfeng Ye 3 participants 3 messages Sep 27 – Sep 28

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Bluetooth: hci_conn: Lock parent access during enhanced SCO setup

Bluetooth: hci_conn: Lock parent access during enhanced SCO setup

hci_enhanced_setup_sync() runs on the request workqueue without the hci_dev_lock held by its caller when setup was queued. Its CVSD capability check and find_next_esco_param() dereference conn->parent while the receive workqueue can unlink and release that parent.

The following interleaving can cause a use-after-free:

hci_enhanced_setup_sync() hci_disconn_complete_evt()
load conn->parent
hci_dev_lock() hci_conn_del(ACL parent)
unlink SCO child drop link's parent reference clear child->parent release ACL parent
bt_link_release()
kfree(parent)
hci_dev_unlock()
read parent->features[0][3]

The reference held for the queued SCO child does not keep its ACL parent alive after unlinking. Commit 42de40abe25d ("Bluetooth: hci_conn: fix the SCO setup context lifetime") protects the child stored in the queued context, but leaves these parent accesses unprotected.

With a 40 ms diagnostic delay after loading conn->parent, an instrumented kernel based on fd179f8a05be, which already contains 42de40abe25d, reported:

  BUG: KASAN: slab-use-after-free in hci_enhanced_setup_sync+0xda5/0xdf0
  Read of size 1 at addr ffff888102204047 by task kworker/u17:0/93
  Call Trace:
   hci_enhanced_setup_sync+0xda5/0xdf0
   hci_cmd_sync_work+0x13c/0x290
   process_one_work+0x6b4/0x10e0

  Allocated by task 92:
   __hci_conn_add+0x304/0x1df0
   hci_connect_acl+0x349/0x3e0
   hci_connect_sco+0x3b/0x9a0
   sco_sock_connect+0x475/0xca0

  Freed by task 94:
   kfree+0x121/0x3c0
   bt_link_release+0x79/0xa0
   device_release+0xc8/0x240
   kobject_put+0x14d/0x280
   hci_conn_del+0x524/0xe30
   hci_disconn_complete_evt+0x403/0x8c0
   hci_event_packet+0x71b/0xb20
   hci_rx_work+0x293/0x730

The accessed address is 71 bytes into the freed ACL parent, at its features[0][3] byte; the queued SCO child is a different object. The diagnostic preserves the loaded parent across the delay, matching the unmodified compiled capability check, and does not change the parent references or teardown path.

Hold hci_dev_lock() across the codec switch, including every call to find_next_esco_param(), and release it on all selection errors. Keep configure_datapath_sync() outside the critical section because it waits for HCI events. Preserve parameter selection and existing return values.

Fixes e07a06b4eb41 ("Bluetooth: Convert SCO configure_datapath to hci_sync")
Assisted-by GPT-6-Astra
---
 net/bluetooth/hci_conn.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)
net/bluetooth/hci_conn.c +13 -5
index 96195d2fd10f..cf44452e0766 100644
@@ -302,11 +302,13 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
 	cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
 	cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
 
+	hci_dev_lock(hdev);
+
 	switch (conn->codec.id) {
 	case BT_CODEC_MSBC:
 		if (!find_next_esco_param(conn, esco_param_msbc,
 					  ARRAY_SIZE(esco_param_msbc)))
-			return -EINVAL;
+			goto unlock;
 
 		param = &esco_param_msbc[conn->attempt - 1];
 		cp.tx_coding_format.id = 0x05;
@@ -332,7 +334,7 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
 	case BT_CODEC_TRANSPARENT:
 		if (!find_next_esco_param(conn, esco_param_msbc,
 					  ARRAY_SIZE(esco_param_msbc)))
-			return -EINVAL;
+			goto unlock;
 
 		param = &esco_param_msbc[conn->attempt - 1];
 		cp.tx_coding_format.id = 0x03;
@@ -359,11 +361,11 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
 		if (conn->parent && lmp_esco_capable(conn->parent)) {
 			if (!find_next_esco_param(conn, esco_param_cvsd,
 						  ARRAY_SIZE(esco_param_cvsd)))
-				return -EINVAL;
+				goto unlock;
 			param = &esco_param_cvsd[conn->attempt - 1];
 		} else {
 			if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
-				return -EINVAL;
+				goto unlock;
 			param = &sco_param_cvsd[conn->attempt - 1];
 		}
 		cp.tx_coding_format.id = 2;
@@ -386,9 +388,11 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
 		cp.out_transport_unit_size = 16;
 		break;
 	default:
-		return -EINVAL;
+		goto unlock;
 	}
 
+	hci_dev_unlock(hdev);
+
 	cp.retrans_effort = param->retrans_effort;
 	cp.pkt_type = __cpu_to_le16(param->pkt_type);
 	cp.max_latency = __cpu_to_le16(param->max_latency);
@@ -397,6 +401,10 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
 		return -EIO;
 
 	return 0;
+
+unlock:
+	hci_dev_unlock(hdev);
+	return -EINVAL;
 }
 
 static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
Signature · 1 line
2.43.0
#1 lore raw

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list. This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/series/1174575/

---Test result---

Test Summary:

CheckPatch                    PASS      0.82 seconds
VerifyFixes                   PASS      0.13 seconds
VerifySignedoff               PASS      0.13 seconds
GitLint                       PASS      0.36 seconds
SubjectPrefix                 PASS      0.13 seconds
BuildKernel                   PASS      31.13 seconds
CheckAllWarning               PASS      35.37 seconds
CheckSparse                   PASS      38.27 seconds
BuildKernel32                 PASS      31.31 seconds
CheckKernelLLVM               PASS      35.17 seconds
TestRunnerSetup               PASS      806.02 seconds
TestRunner_l2cap-tester       PASS      16.77 seconds
TestRunner_iso-tester         PASS      29.01 seconds
TestRunner_bnep-tester        PASS      3.18 seconds
TestRunner_mgmt-tester        PASS      61.71 seconds
TestRunner_rfcomm-tester      PASS      4.49 seconds
TestRunner_sco-tester         PASS      7.70 seconds
TestRunner_ioctl-tester       PASS      4.69 seconds
TestRunner_mesh-tester        FAIL      7.85 seconds
TestRunner_smp-tester         PASS      4.35 seconds
TestRunner_userchan-tester    PASS      3.20 seconds
TestRunner_6lowpan-tester     PASS      4.43 seconds
IncrementalBuild              PASS      29.71 seconds

Details
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0

Failed Test Cases

Mesh - Send cancel - 1                               Timed out    2.409 seconds
Mesh - Send cancel - 2                               Timed out    2.000 seconds

https://github.com/bluez/bluetooth-next/pull/829

---
Regards,
Linux Bluetooth

#2 lore raw
In reply to Chengfeng Ye
This patch was applied to bluetooth/bluetooth-next.git (master) by Luiz Augusto von Dentz <[email protected]>:

Hello:

This patch was applied to bluetooth/bluetooth-next.git (master) by Luiz Augusto von Dentz <[email protected]>:

Quoted 8 lines · On Sun, 27 Sep 2026 19:04:50 +0800 you wrote:

Bluetooth: hci_conn: Lock parent access during enhanced SCO setup

hci_enhanced_setup_sync() runs on the request workqueue without the hci_dev_lock held by its caller when setup was queued. Its CVSD capability check and find_next_esco_param() dereference conn->parent while the receive workqueue can unlink and release that parent.

[...]

Here is the summary with links:
- Bluetooth: hci_conn: Lock parent access during enhanced SCO setup

    https://git.kernel.org/bluetooth/bluetooth-next/c/024e05f73a4c

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html