Bluetooth: Fix data-races in SCO/ISO connect paths
Subsystems (2)
v2 cover Bluetooth: Fix data-races in SCO/ISO connect paths
The connect paths read socket address and config fields without lock_sock() and pass them to hci_get_route() and hci_connect_*(), while connect()/bind()/setsockopt() can update them concurrently.
Patch 1 covers ISO (iso_connect_bis/cis, iso_listen_bis, iso_conn_big_sync), patch 2 covers SCO (sco_connect).
The added lock_sock() sections are reached with the lock not held and released before hci_get_route()/hci_dev_lock(), so no recursive locking or new lock ordering is introduced.
Tested on KCSAN + PROVE_LOCKING with VHCI reproducers on the SCO and ISO CIS connect paths; the hci_get_route() race no longer reproduces and no lockdep splat is seen.
Changes in v2:
- ISO: cache bc_sid too, and pass cached src/dst/bc_sid to __iso_get_sock_listen_by_sid() in iso_listen_bis() (missed in v1)
- ISO: use cached bc_sid in BT_DBG() in iso_connect_bis()
- SCO: also snapshot src, setting and codec; v1 only did dst
- reword: the fix stops torn reads, it does not close the TOCTOU window
- fix the SCO Fixes: tag title
SeungJu Cheon (2):
Bluetooth: ISO: Fix data-race on iso_pi fields in hci_get_route calls
Bluetooth: SCO: Fix data-race on sco_pi fields in sco_connect
net/bluetooth/iso.c | 60 +++++++++++++++++++++++++++++++++------------ net/bluetooth/sco.c | 20 +++++++++++---- 2 files changed, 59 insertions(+), 21 deletions(-)
Signature · 1 line
2.52.0
PATCH v2 1/2 Bluetooth: ISO: Fix data-race on iso_pi fields in hci_get_route calls
iso_connect_bis(), iso_connect_cis(), iso_listen_bis(), and iso_conn_big_sync() call hci_get_route() using iso_pi(sk)->dst, iso_pi(sk)->src, and iso_pi(sk)->src_type without holding lock_sock().
These fields may be modified concurrently by connect() or setsockopt() on the same socket, resulting in data-races reported by KCSAN.
Fix this by snapshotting the required fields under lock_sock() before calling hci_get_route().
BUG: KCSAN: data-race in memcmp+0x45/0xb0
race at unknown origin, with read to 0xffff8880122135cf of 1 bytes by task 333 on cpu 1:
memcmp+0x45/0xb0 hci_get_route+0x27e/0x490 iso_connect_cis+0x4c/0xa10 iso_sock_connect+0x60e/0xb30 __sys_connect_file+0xbd/0xe0 __sys_connect+0xe0/0x110 __x64_sys_connect+0x40/0x50 x64_sys_call+0xcad/0x1c60 do_syscall_64+0x133/0x590 entry_SYSCALL_64_after_hwframe+0x77/0x7f
--- net/bluetooth/iso.c | 60 +++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 16 deletions(-)
net/bluetooth/iso.c +44 -16
@@ -337,12 +337,20 @@ static int iso_connect_bis(struct sock *sk)struct iso_conn *conn;struct hci_conn *hcon;struct hci_dev *hdev; +bdaddr_t src, dst; +u8 src_type, bc_sid;int err; -BT_DBG ("%pMR (SID 0x%2.2x)" , &iso_pi (sk)->src,iso_pi (sk)->bc_sid); +lock_sock (sk); +bacpy (&src, &iso_pi (sk)->src); +bacpy (&dst, &iso_pi (sk)->dst); + src_type =iso_pi (sk)->src_type; + bc_sid =iso_pi (sk)->bc_sid; +release_sock (sk); - hdev =hci_get_route (&iso_pi (sk)->dst, &iso_pi (sk)->src, -iso_pi (sk)->src_type); +BT_DBG ("%pMR (SID 0x%2.2x)" , &src, bc_sid); + + hdev =hci_get_route (&dst, &src, src_type);if (!hdev)return -EHOSTUNREACH ;
@@ -430,12 +438,19 @@ static int iso_connect_cis(struct sock *sk)struct iso_conn *conn;struct hci_conn *hcon;struct hci_dev *hdev; +bdaddr_t src, dst; +u8 src_type;int err; -BT_DBG ("%pMR -> %pMR" , &iso_pi (sk)->src, &iso_pi (sk)->dst); +lock_sock (sk); +bacpy (&src, &iso_pi (sk)->src); +bacpy (&dst, &iso_pi (sk)->dst); + src_type =iso_pi (sk)->src_type; +release_sock (sk); + +BT_DBG ("%pMR -> %pMR" , &src, &dst); - hdev =hci_get_route (&iso_pi (sk)->dst, &iso_pi (sk)->src, -iso_pi (sk)->src_type); + hdev =hci_get_route (&dst, &src, src_type);if (!hdev)return -EHOSTUNREACH ;
@@ -1208,18 +1223,25 @@ static int iso_sock_connect(struct socket *sock, struct sockaddr_unsized *addr,static int iso_listen_bis (struct sock *sk) { -struct hci_dev *hdev; -int err =0 ;struct iso_conn *conn;struct hci_conn *hcon; +struct hci_dev *hdev; +bdaddr_t src, dst; +u8 src_type, bc_sid; +int err =0 ; + +lock_sock (sk); +bacpy (&src, &iso_pi (sk)->src); +bacpy (&dst, &iso_pi (sk)->dst); + src_type =iso_pi (sk)->src_type; + bc_sid =iso_pi (sk)->bc_sid; +release_sock (sk); -BT_DBG ("%pMR -> %pMR (SID 0x%2.2x)" , &iso_pi (sk)->src, - &iso_pi (sk)->dst,iso_pi (sk)->bc_sid); +BT_DBG ("%pMR -> %pMR (SID 0x%2.2x)" , &src, &dst, bc_sid);write_lock (&iso_sk_list.lock); -if (__iso_get_sock_listen_by_sid (&iso_pi (sk)->src, &iso_pi (sk)->dst, -iso_pi (sk)->bc_sid)) +if (__iso_get_sock_listen_by_sid (&src, &dst, bc_sid)) err = -EADDRINUSE ;write_unlock (&iso_sk_list.lock);
@@ -1227,8 +1249,7 @@ static int iso_listen_bis(struct sock *sk)if (err)return err; - hdev =hci_get_route (&iso_pi (sk)->dst, &iso_pi (sk)->src, -iso_pi (sk)->src_type); + hdev =hci_get_route (&dst, &src, src_type);if (!hdev)return -EHOSTUNREACH ;
@@ -1564,9 +1585,16 @@ static void iso_conn_big_sync(struct sock *sk) {int err;struct hci_dev *hdev; +bdaddr_t src, dst; +u8 src_type; + +lock_sock (sk); +bacpy (&src, &iso_pi (sk)->src); +bacpy (&dst, &iso_pi (sk)->dst); + src_type =iso_pi (sk)->src_type; +release_sock (sk); - hdev =hci_get_route (&iso_pi (sk)->dst, &iso_pi (sk)->src, -iso_pi (sk)->src_type); + hdev =hci_get_route (&dst, &src, src_type);if (!hdev)return ;
Signature · 1 line
2.52.0
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/project/bluetooth/list/?series=1103971
---Test result---
Test Summary:
CheckPatch PASS 1.45 seconds VerifyFixes PASS 0.13 seconds VerifySignedoff PASS 0.13 seconds GitLint PASS 0.65 seconds SubjectPrefix PASS 0.25 seconds BuildKernel PASS 25.56 seconds CheckAllWarning PASS 28.06 seconds CheckSparse PASS 26.62 seconds BuildKernel32 PASS 24.57 seconds TestRunnerSetup PASS 524.16 seconds TestRunner_iso-tester PASS 79.34 seconds TestRunner_sco-tester PASS 32.06 seconds IncrementalBuild PASS 26.22 seconds
https://github.com/bluez/bluetooth-next/pull/265
---
Regards,
Linux Bluetooth
PATCH v2 2/2 Bluetooth: SCO: Fix data-race on sco_pi fields in sco_connect
In reply to SeungJu Cheonsco_sock_connect() copies the destination address into sco_pi(sk)->dst under lock_sock(), then releases the lock and calls sco_connect(), which reads dst, src, setting, and codec without holding lock_sock() in hci_get_route() and hci_connect_sco().
These fields may be modified concurrently by connect(), bind(), or setsockopt() on the same socket, resulting in data-races reported by KCSAN.
Fix this by snapshotting dst, src, setting, and codec under lock_sock() at the start of sco_connect() before passing them to hci_get_route() and hci_connect_sco().
BUG: KCSAN: data-race in memcmp+0x45/0xb0
race at unknown origin, with read to 0xffff88800e6b0dd0 of 1 bytes by task 315 on cpu 0:
memcmp+0x45/0xb0 hci_connect_acl+0x1b7/0x6b0 hci_connect_sco+0x4d/0xb30 sco_sock_connect+0x27b/0xd60 __sys_connect_file+0xbd/0xe0 __sys_connect+0xe0/0x110 __x64_sys_connect+0x40/0x50 x64_sys_call+0xcad/0x1c60 do_syscall_64+0x133/0x590 entry_SYSCALL_64_after_hwframe+0x77/0x7f
--- net/bluetooth/sco.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
net/bluetooth/sco.c +15 -5
@@ -312,11 +312,21 @@ static int sco_connect(struct sock *sk)struct sco_conn *conn;struct hci_conn *hcon;struct hci_dev *hdev; +bdaddr_t src, dst; +struct bt_codec codec; +__u16 setting;int err, type; -BT_DBG ("%pMR -> %pMR" , &sco_pi (sk)->src, &sco_pi (sk)->dst); +lock_sock (sk); +bacpy (&src, &sco_pi (sk)->src); +bacpy (&dst, &sco_pi (sk)->dst); + setting =sco_pi (sk)->setting; + codec =sco_pi (sk)->codec; +release_sock (sk); + +BT_DBG ("%pMR -> %pMR" , &src, &dst); - hdev =hci_get_route (&sco_pi (sk)->dst, &sco_pi (sk)->src,BDADDR_BREDR ); + hdev =hci_get_route (&dst, &src,BDADDR_BREDR );if (!hdev)return -EHOSTUNREACH ;
@@ -327,7 +337,7 @@ static int sco_connect(struct sock *sk)else type =SCO_LINK ; -switch (sco_pi (sk)->setting &SCO_AIRMODE_MASK ) { +switch (setting &SCO_AIRMODE_MASK ) {case SCO_AIRMODE_TRANSP :if (!lmp_transp_capable (hdev) || !lmp_esco_capable (hdev)) { err = -EOPNOTSUPP ;
@@ -336,8 +346,8 @@ static int sco_connect(struct sock *sk)break ; } - hcon =hci_connect_sco (hdev, type, &sco_pi (sk)->dst, -sco_pi (sk)->setting, &sco_pi (sk)->codec, + hcon =hci_connect_sco (hdev, type, &dst, + setting, &codec,READ_ONCE (sk->sk_sndtimeo));if (IS_ERR (hcon)) { err =PTR_ERR (hcon);
Signature · 1 line
2.52.0
This series was applied to bluetooth/bluetooth-next.git (master) by Luiz Augusto von Dentz <[email protected]>:
Hello:
This series was applied to bluetooth/bluetooth-next.git (master) by Luiz Augusto von Dentz <[email protected]>:
Quoted 8 lines · On Mon, 1 Jun 2026 20:19:06 +0900 you wrote:
The connect paths read socket address and config fields without
lock_sock()and pass them tohci_get_route()and hci_connect_*(), while connect()/bind()/setsockopt() can update them concurrently.Patch 1 covers ISO (iso_connect_bis/cis,
iso_listen_bis,iso_conn_big_sync), patch 2 covers SCO (sco_connect).[...]
Here is the summary with links:
- [v2,1/2] Bluetooth: ISO: Fix data-race on iso_pi fields in hci_get_route calls
https://git.kernel.org/bluetooth/bluetooth-next/c/961ea93b3ceb - [v2,2/2] Bluetooth: SCO: Fix data-race on sco_pi fields in sco_connect https://git.kernel.org/bluetooth/bluetooth-next/c/4a17208f1b99
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html