[PATCH] Bluetooth: SCO: Fix use-after-free in sco_conn_ready() connect path
From: Sanghyun Park
Date: Wed Jun 10 2026 - 02:44:10 EST
sco_conn_ready() reads conn->sk without holding the connection lock or
taking a socket reference. A concurrent close() can detach and free that
socket before sco_conn_ready() calls lock_sock(sk), resulting in a
use-after-free.
Fix this by taking the connection lock and using sco_sock_hold() to read
conn->sk with a reference held before calling lock_sock(). Drop the
reference with sock_put() after releasing the socket lock.
Race:
CPU0 (hci_rx_work) CPU1 (userspace close)
============================ ==========================
sco_conn_ready(conn):
sk = conn->sk
close(sco_fd)
sco_sock_release()
sco_sock_close()
__sco_sock_close()
sco_chan_del()
conn->sk = NULL
sock_orphan()
sco_sock_kill()
sock_put(sk) -> frees sk
lock_sock(sk)
// UAF: sk may already be freed
Signed-off-by: Sanghyun Park <sanghyun.park.cnu@xxxxxxxxx>
---
net/bluetooth/sco.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 6383db54657..c2c4b5a5b82 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -1306,16 +1306,21 @@ static int sco_sock_release(struct socket *sock)
static void sco_conn_ready(struct sco_conn *conn)
{
struct sock *parent;
- struct sock *sk = conn->sk;
+ struct sock *sk;
BT_DBG("conn %p", conn);
+ sco_conn_lock(conn);
+ sk = sco_sock_hold(conn);
+ sco_conn_unlock(conn);
+
if (sk) {
lock_sock(sk);
sco_sock_clear_timer(sk);
sk->sk_state = BT_CONNECTED;
sk->sk_state_change(sk);
release_sock(sk);
+ sock_put(sk);
} else {
sco_conn_lock(conn);
--
2.48.1