* [PATCH 1/1] Bluetooth: Fix parent socket UAF in accept queues
[not found] <cover.1784374481.git.xizh2024@lzu.edu.cn>
@ 2026-07-20 4:19 ` Ren Wei
2026-07-20 7:27 ` [1/1] " bluez.test.bot
0 siblings, 1 reply; 2+ messages in thread
From: Ren Wei @ 2026-07-20 4:19 UTC (permalink / raw)
To: linux-bluetooth
Cc: marcel, luiz.dentz, kees, rollkingzzc, tim.bird, safa.karakus,
leitao, vega, xizh2024, enjou1224z
From: Zihan Xi <xizh2024@lzu.edu.cn>
Bluetooth children queued on a listening socket store the listener in
bt_sk(sk)->parent, but the accept queue did not hold a reference on that
parent socket. The child side can later fetch that pointer and unlink
itself from the accept queue while still needing to notify the listener,
for example from L2CAP, ISO or RFCOMM teardown/state-change callbacks.
If the listener is closed concurrently, removing the child from the
accept queue can drop the last listener reference before those callbacks
call parent->sk_data_ready(parent), leaving a stale parent pointer and a
use-after-free.
Take a reference on the parent when a child is queued and drop it when
the child is unlinked. Since unlinking now drops the accept-queue
parent reference, take a temporary parent reference in the callbacks that
continue to notify the parent after bt_accept_unlink().
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Assisted-by: Codex:gpt-5.4
Signed-off-by: Zihan Xi <xizh2024@lzu.edu.cn>
Reviewed-by: Ren Wei <enjou1224z@gmail.com>
---
net/bluetooth/af_bluetooth.c | 2 ++
net/bluetooth/iso.c | 2 ++
net/bluetooth/l2cap_sock.c | 2 ++
net/bluetooth/rfcomm/sock.c | 2 ++
4 files changed, 8 insertions(+)
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index a2290ffdc2c1..0cb745ce652d 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -217,6 +217,7 @@ void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
BT_DBG("parent %p, sk %p", parent, sk);
sock_hold(sk);
+ sock_hold(parent);
if (bh)
bh_lock_sock_nested(sk);
@@ -265,6 +266,7 @@ void bt_accept_unlink(struct sock *sk)
spin_unlock_bh(&bt_sk(parent)->accept_q_lock);
bt_sk(sk)->parent = NULL;
sock_put(sk);
+ sock_put(parent);
}
EXPORT_SYMBOL(bt_accept_unlink);
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index 2e95a153912c..a2ed9da0e42d 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -253,8 +253,10 @@ static void iso_chan_del(struct sock *sk, int err)
parent = bt_sk(sk)->parent;
if (parent) {
+ sock_hold(parent);
bt_accept_unlink(sk);
parent->sk_data_ready(parent);
+ sock_put(parent);
} else {
sk->sk_state_change(sk);
}
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 4058ff50cc27..3cd69cf26335 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1707,8 +1707,10 @@ static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
sk->sk_err = err;
if (parent) {
+ sock_hold(parent);
bt_accept_unlink(sk);
parent->sk_data_ready(parent);
+ sock_put(parent);
} else {
sk->sk_state_change(sk);
}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index feb302a491fa..4195816b4236 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -77,11 +77,13 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
parent = bt_sk(sk)->parent;
if (parent) {
+ sock_hold(parent);
if (d->state == BT_CLOSED) {
sock_set_flag(sk, SOCK_ZAPPED);
bt_accept_unlink(sk);
}
parent->sk_data_ready(parent);
+ sock_put(parent);
} else {
if (d->state == BT_CONNECTED)
rfcomm_session_getaddr(d->session,
--
2.43.0
^ permalink raw reply related [flat|nested] 2+ messages in thread