summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeungJu Cheon <suunj1331@gmail.com>2026-06-01 20:19:08 +0900
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2026-06-03 11:23:52 -0400
commit4847c5bca22227100ae69e96af86618b6fd2671f (patch)
treee96a7688c0301f88f68a4579d05adc989a92f999
parent9ca7053d6215d89c33f28893bfd1625a32919d3f (diff)
downloadlinux-4847c5bca22227100ae69e96af86618b6fd2671f.tar.gz
linux-4847c5bca22227100ae69e96af86618b6fd2671f.zip
Bluetooth: SCO: Fix data-race on sco_pi fields in sco_connect
sco_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 Fixes: 9a8ec9e8ebb5 ("Bluetooth: SCO: Fix possible circular locking dependency on sco_connect_cfm") Signed-off-by: SeungJu Cheon <suunj1331@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-rw-r--r--net/bluetooth/sco.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index f1799c6a6f87..140869e5b2df 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -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);