[PATCH] Bluetooth: SCO: Fix use-after-free on listening socket in sco_conn_ready()
From: Sanghyun Park
Date: Fri May 29 2026 - 03:16:15 EST
sco_conn_ready() calls sco_get_sock_listen() which returns a raw
pointer to a listening socket after releasing sco_sk_list.lock, without
taking a reference. A concurrent close() of the listening socket can
free it between the list lookup return and lock_sock(parent), resulting
in a use-after-free.
Fix by taking a reference with sock_hold() immediately after
sco_get_sock_listen() returns, and dropping it with sock_put() after
release_sock(). This matches the pattern used in commit 598dbba9919c
("Bluetooth: SCO: Fix use-after-free in sco_recv_frame() due to missing
sock_hold") for the analogous race in sco_recv_frame().
Race:
CPU0 (HCI event workqueue) CPU1 (userspace)
============================ ==========================
sco_conn_ready():
parent = sco_get_sock_listen()
// returns sk with NO reference
close(listen_fd):
sco_sock_release()
sco_sock_kill()
sock_put(sk) -> frees sk
lock_sock(parent)
// UAF: sk is freed
Reproduction:
1. Build any kernel (bug exists since 2.6.12) with CONFIG_KASAN=y,
CONFIG_BT=y, CONFIG_BT_HCIVHCI=m
2. Boot in a VM, load hci_vhci module
3. Compile: gcc -O2 -o repro -static -pthread repro.c
4. Run as root: ./repro
5. Check dmesg for: BUG: KASAN: slab-use-after-free in __lock_acquire
The reproducer opens /dev/vhci, brings up a virtual HCI device,
creates a SCO listening socket, then races close(listen_fd) against
injected incoming SCO connection events. A 5ms instrumentation delay
at the vulnerable point widens the window for reliable reproduction;
without it the race is tight but still real on multi-core systems.
KASAN report (reproduced on 6.12.91 via /dev/vhci):
BUG: KASAN: slab-use-after-free in __lock_acquire+0x2e19/0x3b50
Read of size 8 at addr ffff888104be5258 by task kworker/u9:0/382
Workqueue: hci0 hci_rx_work
Call Trace:
__lock_acquire+0x2e19/0x3b50
lock_acquire.part.0+0xf7/0x320
lock_sock_nested+0x46/0x100
sco_connect_cfm.cold+0x2e7/0x867
hci_connect_cfm+0x94/0x140
hci_conn_complete_evt+0x825/0x13d0
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Sanghyun Park <sanghyun.park.cnu@xxxxxxxxx>
---
Hi,
I'm Sanghyun Park, a security researcher. I found this while auditing
the Bluetooth SCO code. The bug has existed since the initial git import
(2005) and affects literally every Linux kernel ever shipped. All distros
are affected.
The C reproducer is attached separately (repro.c).
net/bluetooth/sco.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index ad3439bd4d..b5c6d7e8f1 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -1323,6 +1323,7 @@ static void sco_conn_ready(struct sco_conn *conn)
sco_conn_unlock(conn);
return;
}
+ sock_hold(parent);
lock_sock(parent);
@@ -1330,6 +1331,7 @@ static void sco_conn_ready(struct sco_conn *conn)
BTPROTO_SCO, GFP_ATOMIC, 0);
if (!sk) {
release_sock(parent);
+ sock_put(parent);
sco_conn_unlock(conn);
return;
}
@@ -1353,6 +1355,7 @@ static void sco_conn_ready(struct sco_conn *conn)
parent->sk_data_ready(parent);
release_sock(parent);
+ sock_put(parent);
sco_conn_unlock(conn);
}
pointer to a listening socket after releasing sco_sk_list.lock, without
taking a reference. A concurrent close() of the listening socket can
free it between the list lookup return and lock_sock(parent), resulting
in a use-after-free.
Fix by taking a reference with sock_hold() immediately after
sco_get_sock_listen() returns, and dropping it with sock_put() after
release_sock(). This matches the pattern used in commit 598dbba9919c
("Bluetooth: SCO: Fix use-after-free in sco_recv_frame() due to missing
sock_hold") for the analogous race in sco_recv_frame().
Race:
CPU0 (HCI event workqueue) CPU1 (userspace)
============================ ==========================
sco_conn_ready():
parent = sco_get_sock_listen()
// returns sk with NO reference
close(listen_fd):
sco_sock_release()
sco_sock_kill()
sock_put(sk) -> frees sk
lock_sock(parent)
// UAF: sk is freed
Reproduction:
1. Build any kernel (bug exists since 2.6.12) with CONFIG_KASAN=y,
CONFIG_BT=y, CONFIG_BT_HCIVHCI=m
2. Boot in a VM, load hci_vhci module
3. Compile: gcc -O2 -o repro -static -pthread repro.c
4. Run as root: ./repro
5. Check dmesg for: BUG: KASAN: slab-use-after-free in __lock_acquire
The reproducer opens /dev/vhci, brings up a virtual HCI device,
creates a SCO listening socket, then races close(listen_fd) against
injected incoming SCO connection events. A 5ms instrumentation delay
at the vulnerable point widens the window for reliable reproduction;
without it the race is tight but still real on multi-core systems.
KASAN report (reproduced on 6.12.91 via /dev/vhci):
BUG: KASAN: slab-use-after-free in __lock_acquire+0x2e19/0x3b50
Read of size 8 at addr ffff888104be5258 by task kworker/u9:0/382
Workqueue: hci0 hci_rx_work
Call Trace:
__lock_acquire+0x2e19/0x3b50
lock_acquire.part.0+0xf7/0x320
lock_sock_nested+0x46/0x100
sco_connect_cfm.cold+0x2e7/0x867
hci_connect_cfm+0x94/0x140
hci_conn_complete_evt+0x825/0x13d0
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Sanghyun Park <sanghyun.park.cnu@xxxxxxxxx>
---
Hi,
I'm Sanghyun Park, a security researcher. I found this while auditing
the Bluetooth SCO code. The bug has existed since the initial git import
(2005) and affects literally every Linux kernel ever shipped. All distros
are affected.
The C reproducer is attached separately (repro.c).
net/bluetooth/sco.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index ad3439bd4d..b5c6d7e8f1 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -1323,6 +1323,7 @@ static void sco_conn_ready(struct sco_conn *conn)
sco_conn_unlock(conn);
return;
}
+ sock_hold(parent);
lock_sock(parent);
@@ -1330,6 +1331,7 @@ static void sco_conn_ready(struct sco_conn *conn)
BTPROTO_SCO, GFP_ATOMIC, 0);
if (!sk) {
release_sock(parent);
+ sock_put(parent);
sco_conn_unlock(conn);
return;
}
@@ -1353,6 +1355,7 @@ static void sco_conn_ready(struct sco_conn *conn)
parent->sk_data_ready(parent);
release_sock(parent);
+ sock_put(parent);
sco_conn_unlock(conn);
}
Attachment:
repro.c
Description: Binary data