* [PATCH v2] Bluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan
@ 2026-08-08 9:08 Pauli Virtanen
2026-08-08 10:02 ` [v2] " bluez.test.bot
2026-08-11 20:10 ` [PATCH v2] " patchwork-bot+bluetooth
0 siblings, 2 replies; 3+ messages in thread
From: Pauli Virtanen @ 2026-08-08 9:08 UTC (permalink / raw)
To: linux-bluetooth
Cc: Pauli Virtanen, marcel, luiz.dentz, oss, linux-kernel, hdanton,
syzbot+e6382a2f53f5fc7453ac
For L2CAP sockets without owning sk->sk_socket, reading
l2cap_pi(sk)->chan may race against concurrent l2cap_sock_kill() ->
l2cap_sock_put_chan(). This excludes simultaneous proto_ops callbacks,
but access in l2cap_sock_cleanup_listen() has unsafe lockless read.
[Task 1] [Task 2 (hdev->workqueue)]
l2cap_sock_release(parent) l2cap_disconn_cfm
l2cap_sock_cleanup_listen l2cap_conn_del
bt_accept_dequeue l2cap_chan_del
lock_sock(sk) l2cap_sock_teardown_cb
bt_accept_unlink
bt_sk(sk)->parent = NULL
release_sock(sk) ----------------> lock_sock(sk)
parent = /* NULL */
lock_sock(sk) <--------------------- release_sock(sk)
sock_set_flag(sk, SOCK_ZAPPED)
l2cap_sock_close_cb
l2cap_sock_kill(sk)
l2cap_sock_put_chan
chan = READ l2cap_pi(sk)->chan l2cap_pi(sk)->chan = NULL
l2cap_chan_hold_unless_zero l2cap_put_chan(chan)
kref_get_unless_zero(&chan->ref)
Task 1 may observe NULL which causes null-ptr-deref.
Fix the race by taking lock_sock() in l2cap_sock_kill() to
synchronize with l2cap_sock_cleanup_listen(). hold_unless_zero() is not
needed here, l2cap_pi(sk)->chan owns reference if it is non-NULL.
Clarify code comments vs. locking.
Fixes: 0e2c0392b9dc ("Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()")
Reported-by: syzbot+e6382a2f53f5fc7453ac@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=e6382a2f53f5fc7453ac
Signed-off-by: Pauli Virtanen <pav@iki.fi>
---
Notes:
v2:
- improve commit message
- no code changes
include/net/bluetooth/l2cap.h | 5 +++++
net/bluetooth/l2cap_sock.c | 23 +++++++++++++----------
2 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index ef6ce1c20a4f..3d9a32094347 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -699,7 +699,12 @@ struct l2cap_rx_busy {
struct l2cap_pinfo {
struct bt_sock bt;
+
+ /* With owning sk_socket chan may be read without lock, other access
+ * should hold lock_sock.
+ */
struct l2cap_chan *chan;
+
struct list_head rx_busy;
};
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 735167f73f31..9540617a0e6c 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1312,7 +1312,12 @@ static void l2cap_sock_kill(struct sock *sk)
BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
+ /* Take lock to synchronize against access without owning sk->sk_socket,
+ * eg. in l2cap_sock_cleanup_listen(). proto_ops etc. don't need lock.
+ */
+ lock_sock(sk);
l2cap_sock_put_chan(sk);
+ release_sock(sk);
/* Kill poor orphan */
sock_set_flag(sk, SOCK_DEAD);
@@ -1516,14 +1521,10 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
* establish sk_lock -> conn->lock and invert the established
* conn->lock -> chan->lock -> sk_lock order (lockdep deadlock).
*
- * Instead, briefly take the child sk lock to fetch and pin its chan.
- * l2cap_conn_del() reaches the chan free only via
- * l2cap_chan_del() -> l2cap_sock_teardown_cb(), which itself takes
- * the child sk lock; holding it across l2cap_chan_hold_unless_zero()
- * therefore guarantees the chan cannot be freed while we read and
- * pin it (hold_unless_zero() additionally skips a chan already past
- * its last reference). We then drop the sk lock before taking
- * chan->lock, so sk and chan locks are never held together.
+ * Instead, briefly take the child sk lock to synchronize vs.
+ * l2cap_sock_kill that puts l2cap_pi(sk)->chan. We then drop the sk
+ * lock before taking chan->lock, so sk and chan locks are never held
+ * together.
*
* Since we cannot call l2cap_chan_close() without conn->lock,
* schedule l2cap_chan_timeout to close the channel; it already
@@ -1533,10 +1534,12 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
struct l2cap_chan *chan;
lock_sock_nested(sk, L2CAP_NESTING_NORMAL);
- chan = l2cap_chan_hold_unless_zero(l2cap_pi(sk)->chan);
+ chan = l2cap_pi(sk)->chan;
+ if (chan)
+ l2cap_chan_hold(chan);
release_sock(sk);
if (!chan) {
- /* l2cap_conn_del() already tearing this child down */
+ /* Already torn down */
sock_put(sk);
continue;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* RE: [v2] Bluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan
2026-08-08 9:08 [PATCH v2] Bluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan Pauli Virtanen
@ 2026-08-08 10:02 ` bluez.test.bot
2026-08-11 20:10 ` [PATCH v2] " patchwork-bot+bluetooth
1 sibling, 0 replies; 3+ messages in thread
From: bluez.test.bot @ 2026-08-08 10:02 UTC (permalink / raw)
To: linux-bluetooth, pav
[-- Attachment #1: Type: text/plain, Size: 1235 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1142603
---Test result---
Test Summary:
CheckPatch PASS 0.84 seconds
VerifyFixes PASS 0.11 seconds
VerifySignedoff PASS 0.09 seconds
GitLint PASS 0.24 seconds
SubjectPrefix PASS 0.08 seconds
BuildKernel PASS 27.63 seconds
CheckAllWarning PASS 30.05 seconds
CheckSparse PASS 28.66 seconds
BuildKernel32 PASS 26.42 seconds
CheckKernelLLVM SKIP 0.00 seconds
TestRunnerSetup PASS 500.74 seconds
TestRunner_l2cap-tester PASS 63.91 seconds
IncrementalBuild PASS 26.20 seconds
Details
##############################
Test: CheckKernelLLVM - SKIP
Desc: Build kernel with LLVM + context analysis
Output:
Clang not found
https://github.com/bluez/bluetooth-next/pull/559
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2] Bluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan
2026-08-08 9:08 [PATCH v2] Bluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan Pauli Virtanen
2026-08-08 10:02 ` [v2] " bluez.test.bot
@ 2026-08-11 20:10 ` patchwork-bot+bluetooth
1 sibling, 0 replies; 3+ messages in thread
From: patchwork-bot+bluetooth @ 2026-08-11 20:10 UTC (permalink / raw)
To: Pauli Virtanen
Cc: linux-bluetooth, marcel, luiz.dentz, oss, linux-kernel, hdanton,
syzbot+e6382a2f53f5fc7453ac
Hello:
This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Sat, 8 Aug 2026 12:08:45 +0300 you wrote:
> For L2CAP sockets without owning sk->sk_socket, reading
> l2cap_pi(sk)->chan may race against concurrent l2cap_sock_kill() ->
> l2cap_sock_put_chan(). This excludes simultaneous proto_ops callbacks,
> but access in l2cap_sock_cleanup_listen() has unsafe lockless read.
>
> [Task 1] [Task 2 (hdev->workqueue)]
> l2cap_sock_release(parent) l2cap_disconn_cfm
> l2cap_sock_cleanup_listen l2cap_conn_del
> bt_accept_dequeue l2cap_chan_del
> lock_sock(sk) l2cap_sock_teardown_cb
> bt_accept_unlink
> bt_sk(sk)->parent = NULL
> release_sock(sk) ----------------> lock_sock(sk)
> parent = /* NULL */
> lock_sock(sk) <--------------------- release_sock(sk)
> sock_set_flag(sk, SOCK_ZAPPED)
> l2cap_sock_close_cb
> l2cap_sock_kill(sk)
> l2cap_sock_put_chan
> chan = READ l2cap_pi(sk)->chan l2cap_pi(sk)->chan = NULL
> l2cap_chan_hold_unless_zero l2cap_put_chan(chan)
> kref_get_unless_zero(&chan->ref)
>
> [...]
Here is the summary with links:
- [v2] Bluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan
https://git.kernel.org/bluetooth/bluetooth-next/c/d67f4a43e7ef
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-08-11 20:11 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-08 9:08 [PATCH v2] Bluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan Pauli Virtanen
2026-08-08 10:02 ` [v2] " bluez.test.bot
2026-08-11 20:10 ` [PATCH v2] " patchwork-bot+bluetooth
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.