| From 3608ccdeade9228007348851204fff29d4628498 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 13 Mar 2026 05:26:16 +0900 |
| Subject: Bluetooth: SCO: Fix use-after-free in sco_recv_frame() due to missing |
| sock_hold |
| |
| From: Hyunwoo Kim <imv4bel@gmail.com> |
| |
| [ Upstream commit 598dbba9919c5e36c54fe1709b557d64120cb94b ] |
| |
| sco_recv_frame() reads conn->sk under sco_conn_lock() but immediately |
| releases the lock without holding a reference to the socket. A concurrent |
| close() can free the socket between the lock release and the subsequent |
| sk->sk_state access, resulting in a use-after-free. |
| |
| Other functions in the same file (sco_sock_timeout(), sco_conn_del()) |
| correctly use sco_sock_hold() to safely hold a reference under the lock. |
| |
| Fix by using sco_sock_hold() to take a reference before releasing the |
| lock, and adding sock_put() on all exit paths. |
| |
| Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") |
| Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com> |
| Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/bluetooth/sco.c | 10 +++++++--- |
| 1 file changed, 7 insertions(+), 3 deletions(-) |
| |
| diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c |
| index cccfaf5603174..6741b067d28b5 100644 |
| --- a/net/bluetooth/sco.c |
| +++ b/net/bluetooth/sco.c |
| @@ -401,7 +401,7 @@ static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) |
| struct sock *sk; |
| |
| sco_conn_lock(conn); |
| - sk = conn->sk; |
| + sk = sco_sock_hold(conn); |
| sco_conn_unlock(conn); |
| |
| if (!sk) |
| @@ -410,11 +410,15 @@ static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) |
| BT_DBG("sk %p len %u", sk, skb->len); |
| |
| if (sk->sk_state != BT_CONNECTED) |
| - goto drop; |
| + goto drop_put; |
| |
| - if (!sock_queue_rcv_skb(sk, skb)) |
| + if (!sock_queue_rcv_skb(sk, skb)) { |
| + sock_put(sk); |
| return; |
| + } |
| |
| +drop_put: |
| + sock_put(sk); |
| drop: |
| kfree_skb(skb); |
| } |
| -- |
| 2.51.0 |
| |