* [Linux Kernel Bug] possible deadlock in l2cap_chan_connect
@ 2026-09-11 16:59 Jiaming Zhang
2026-09-11 18:38 ` Ali Ahmet Memiş
0 siblings, 1 reply; 4+ messages in thread
From: Jiaming Zhang @ 2026-09-11 16:59 UTC (permalink / raw)
To: marcel, luiz.dentz, linux-bluetooth
Cc: ali, kees, kuba, linux-kernel, nicoyip.dev, suunj1331, syzkaller,
r772577952
Dear Linux kernel developers and maintainers,
We are writing to report an issue discovered in the Bluetooth subsystem. The
issue is reproducible on the latest version of linux (v7.3-rc2, commit
df2908090cda368b01ff43709f51890076c56157). Below is the kernel report:
======================================================
WARNING: possible circular locking dependency detected
7.3.0-rc2 #42 Not tainted
------------------------------------------------------
syz-executor108/9473 is trying to acquire lock:
ffff8880467900b8 (&hdev->lock){+.+.}-{4:4}, at:
l2cap_chan_connect+0xa0/0x1130 net/bluetooth/l2cap_core.c:7281
but task is already holding lock:
ffffffff8fdbc6c0 (rfcomm_mutex){+.+.}-{4:4}, at:
rfcomm_dlc_open+0x95/0xee0 net/bluetooth/rfcomm/core.c:426
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (rfcomm_mutex){+.+.}-{4:4}:
lock_acquire+0x116/0x350 kernel/locking/lockdep.c:5942
__mutex_lock_common kernel/locking/mutex.c:646 [inline]
__mutex_lock+0x184/0x1590 kernel/locking/mutex.c:821
rfcomm_security_cfm+0x41/0x450 net/bluetooth/rfcomm/core.c:2222
hci_encrypt_cfm+0x384/0x500 include/net/bluetooth/hci_core.h:2242
hci_encrypt_change_evt+0x5fa/0xce0 net/bluetooth/hci_event.c:3674
hci_event_func net/bluetooth/hci_event.c:7887 [inline]
hci_event_packet+0x665/0xec0 net/bluetooth/hci_event.c:7938
hci_rx_work+0x3ee/0x1070 net/bluetooth/hci_core.c:4041
process_one_work kernel/workqueue.c:3396 [inline]
process_scheduled_works+0xc85/0x18f0 kernel/workqueue.c:3479
worker_thread+0x8a3/0xda0 kernel/workqueue.c:3560
kthread+0x38c/0x480 kernel/kthread.c:436
ret_from_fork+0x509/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
-> #1 (hci_cb_list_lock){+.+.}-{4:4}:
lock_acquire+0x116/0x350 kernel/locking/lockdep.c:5942
__mutex_lock_common kernel/locking/mutex.c:646 [inline]
__mutex_lock+0x184/0x1590 kernel/locking/mutex.c:821
hci_connect_cfm include/net/bluetooth/hci_core.h:2163 [inline]
hci_remote_features_evt+0x51c/0x920 net/bluetooth/hci_event.c:3786
hci_event_func net/bluetooth/hci_event.c:7887 [inline]
hci_event_packet+0x665/0xec0 net/bluetooth/hci_event.c:7938
hci_rx_work+0x3ee/0x1070 net/bluetooth/hci_core.c:4041
process_one_work kernel/workqueue.c:3396 [inline]
process_scheduled_works+0xc85/0x18f0 kernel/workqueue.c:3479
worker_thread+0x8a3/0xda0 kernel/workqueue.c:3560
kthread+0x38c/0x480 kernel/kthread.c:436
ret_from_fork+0x509/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
-> #0 (&hdev->lock){+.+.}-{4:4}:
check_prev_add kernel/locking/lockdep.c:3209 [inline]
check_prevs_add kernel/locking/lockdep.c:3328 [inline]
validate_chain+0xa41/0x2560 kernel/locking/lockdep.c:3952
__lock_acquire+0xbe0/0xf10 kernel/locking/lockdep.c:5288
lock_acquire+0x116/0x350 kernel/locking/lockdep.c:5942
__mutex_lock_common kernel/locking/mutex.c:646 [inline]
__mutex_lock+0x184/0x1590 kernel/locking/mutex.c:821
l2cap_chan_connect+0xa0/0x1130 net/bluetooth/l2cap_core.c:7281
l2cap_sock_connect+0x5c8/0x7d0 net/bluetooth/l2cap_sock.c:255
kernel_connect+0x116/0x180 net/socket.c:3755
rfcomm_session_create net/bluetooth/rfcomm/core.c:808 [inline]
__rfcomm_dlc_open net/bluetooth/rfcomm/core.c:385 [inline]
rfcomm_dlc_open+0x924/0xee0 net/bluetooth/rfcomm/core.c:428
rfcomm_sock_connect+0x2f7/0x650 net/bluetooth/rfcomm/sock.c:421
connect_socket net/socket.c:2141 [inline]
__sys_connect_file net/socket.c:2166 [inline]
__sys_connect+0x30e/0x430 net/socket.c:2183
__do_sys_connect net/socket.c:2189 [inline]
__se_sys_connect net/socket.c:2186 [inline]
__x64_sys_connect+0x7a/0x90 net/socket.c:2186
do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
do_syscall_64+0x170/0x540 arch/x86/entry/syscall_64.c:84
entry_SYSCALL_64_after_hwframe+0x77/0x7f
other info that might help us debug this:
Chain exists of:
&hdev->lock --> hci_cb_list_lock --> rfcomm_mutex
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(rfcomm_mutex);
lock(hci_cb_list_lock);
lock(rfcomm_mutex);
lock(&hdev->lock);
*** DEADLOCK ***
locks held by syz-executor108/9473: 1, last CPU#0:
#0: ffffffff8fdbc6c0 (rfcomm_mutex){+.+.}-{4:4}, at:
rfcomm_dlc_open+0x95/0xee0 net/bluetooth/rfcomm/core.c:426
stack backtrace:
CPU: 0 UID: 0 PID: 9473 Comm: syz-executor108 Not tainted 7.3.0-rc2
#42 PREEMPT(full)
Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix,
1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:94 [inline]
dump_stack_lvl+0x10e/0x190 lib/dump_stack.c:120
print_circular_bug+0x37e/0x3a0 kernel/locking/lockdep.c:2087
check_noncircular+0x12f/0x150 kernel/locking/lockdep.c:2219
check_prev_add kernel/locking/lockdep.c:3209 [inline]
check_prevs_add kernel/locking/lockdep.c:3328 [inline]
validate_chain+0xa41/0x2560 kernel/locking/lockdep.c:3952
__lock_acquire+0xbe0/0xf10 kernel/locking/lockdep.c:5288
lock_acquire+0x116/0x350 kernel/locking/lockdep.c:5942
__mutex_lock_common kernel/locking/mutex.c:646 [inline]
__mutex_lock+0x184/0x1590 kernel/locking/mutex.c:821
l2cap_chan_connect+0xa0/0x1130 net/bluetooth/l2cap_core.c:7281
l2cap_sock_connect+0x5c8/0x7d0 net/bluetooth/l2cap_sock.c:255
kernel_connect+0x116/0x180 net/socket.c:3755
rfcomm_session_create net/bluetooth/rfcomm/core.c:808 [inline]
__rfcomm_dlc_open net/bluetooth/rfcomm/core.c:385 [inline]
rfcomm_dlc_open+0x924/0xee0 net/bluetooth/rfcomm/core.c:428
rfcomm_sock_connect+0x2f7/0x650 net/bluetooth/rfcomm/sock.c:421
connect_socket net/socket.c:2141 [inline]
__sys_connect_file net/socket.c:2166 [inline]
__sys_connect+0x30e/0x430 net/socket.c:2183
__do_sys_connect net/socket.c:2189 [inline]
__se_sys_connect net/socket.c:2186 [inline]
__x64_sys_connect+0x7a/0x90 net/socket.c:2186
do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
do_syscall_64+0x170/0x540 arch/x86/entry/syscall_64.c:84
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f86d4e40b4d
Code: b3 66 2e 0f 1f 84 00 00 00 00 00 66 90 f3 0f 1e fa 48 89 f8 48
89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d
01 f0 ff ff 73 01 c3 48 c7 c1 b8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fff9b4b4618 EFLAGS: 00000246 ORIG_RAX: 000000000000002a
RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007f86d4e40b4d
RDX: 000000000000000a RSI: 0000200000000240 RDI: 0000000000000004
RBP: 0000000000000003 R08: 000000ff00ff7000 R09: 000000ff00ff7000
R10: 000000ff00ff7000 R11: 0000000000000246 R12: 000055558c9a6378
R13: 0000000000000010 R14: 00007f86d4ec50ce R15: 0000000000000001
</TASK>
Following is the root cause analysis for this issue, note that the
analysis is performed with the assistance of LLM, but we try our best to
ensure the accuracy.
lockdep reports a cycle between three mutexes: hdev->lock, hci_cb_list_lock,
and rfcomm_mutex. Two paths take the locks in opposite orders. A connect()
on an RFCOMM socket runs the whole session setup under rfcomm_mutex, and the
L2CAP connection it opens along the way takes hdev->lock:
rfcomm_dlc_open() <-- takes rfcomm_mutex
rfcomm_session_create()
kernel_connect()
l2cap_chan_connect() <-- takes hdev->lock
The other path starts at the controller. hci_encrypt_cfm() and
hci_auth_cfm() are only ever called from HCI event handlers, which hold
hdev->lock, and the RFCOMM security callback takes rfcomm_mutex from there:
hci_encrypt_change_evt() <-- takes hdev->lock
hci_encrypt_cfm() <-- takes hci_cb_list_lock
rfcomm_security_cfm() <-- takes rfcomm_mutex
When the two paths overlap, hci_rx_work() blocks on rfcomm_mutex while
holding hdev->lock, and the connecting task blocks on hdev->lock while
holding rfcomm_mutex. Neither can make progress, leading to a deadlock.
Following is our suggested solution: The confirmation callback only records
per-channel state that the krfcommd thread acts on later, so it does not
have to run in the event path at all. Deferring it to an ordered workqueue
keeps that work serialized under rfcomm_mutex and takes rfcomm_mutex out of
the hdev->lock nesting.
We are actively working on a patch, if the above solution is acceptable,
I would be happy to submit a formal patch for review.
The kernel console output, kernel config, syzkaller reproducer, and C
reproducer are available at google drive:
https://drive.google.com/drive/folders/1Q-Eu5dpQCMH80lEtunLGvK-_oheGkT2O?usp=sharing
Please let us know if any further information is required.
Best Regards,
Jiaming Zhang
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Linux Kernel Bug] possible deadlock in l2cap_chan_connect
2026-09-11 16:59 [Linux Kernel Bug] possible deadlock in l2cap_chan_connect Jiaming Zhang
@ 2026-09-11 18:38 ` Ali Ahmet Memiş
2026-09-29 7:25 ` Mikhail Gavrilov
0 siblings, 1 reply; 4+ messages in thread
From: Ali Ahmet Memiş @ 2026-09-11 18:38 UTC (permalink / raw)
To: Jiaming Zhang
Cc: marcel, luiz.dentz, linux-bluetooth, linux-kernel, kees, kuba,
nicoyip.dev, suunj1331, syzkaller, Mikhail Gavrilov,
Pauli Virtanen
On Sat, Sep 12, 2026 at 12:59:09AM +0800, Jiaming Zhang wrote:
> We are actively working on a patch, if the above solution is acceptable,
> I would be happy to submit a formal patch for review.
This is the same lock inversion syzbot reported as 74071deb, and Mikhail
already has a fix for it under review:
https://lore.kernel.org/linux-bluetooth/20260904012028.77590-1-mikhail.v.gavrilov@gmail.com/
It uses the same approach you describe, queue the confirmation and let
krfcommd handle it under rfcomm_mutex.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Linux Kernel Bug] possible deadlock in l2cap_chan_connect
2026-09-11 18:38 ` Ali Ahmet Memiş
@ 2026-09-29 7:25 ` Mikhail Gavrilov
2026-09-29 7:41 ` Jiaming Zhang
0 siblings, 1 reply; 4+ messages in thread
From: Mikhail Gavrilov @ 2026-09-29 7:25 UTC (permalink / raw)
To: Ali Ahmet Memiş
Cc: Jiaming Zhang, marcel, luiz.dentz, linux-bluetooth, linux-kernel,
kees, kuba, nicoyip.dev, suunj1331, syzkaller, Pauli Virtanen
On Fri, Sep 11, 2026 at 11:38 PM Ali Ahmet Memiş <aliamemis@disroot.org> wrote:
>
> On Sat, Sep 12, 2026 at 12:59:09AM +0800, Jiaming Zhang wrote:
> > We are actively working on a patch, if the above solution is acceptable,
> > I would be happy to submit a formal patch for review.
>
> This is the same lock inversion syzbot reported as 74071deb, and Mikhail
> already has a fix for it under review:
>
> https://lore.kernel.org/linux-bluetooth/20260904012028.77590-1-mikhail.v.gavrilov@gmail.com/
>
> It uses the same approach you describe, queue the confirmation and let
> krfcommd handle it under rfcomm_mutex.
Hi Jiaming, Ali,
thanks for the report and for putting the reproducer up, and thanks
Ali for connecting the two threads.
The deferral Jiaming suggests is what v2 of my patch did - that is the
version Ali linked - but that approach was dropped during review. Pauli
pointed out that delaying the confirmation makes it hard to rule out new
races against DLC setup, and Luiz asked to break the cycle on the connect
side instead.
v3 does that. The session socket is created and connected without
rfcomm_mutex held, and the lock is only taken again to put the new
session on the list:
https://lore.kernel.org/linux-bluetooth/20260912100315.151674-1-mikhail.v.gavrilov@gmail.com/
That removes exactly the edge in your trace, rfcomm_dlc_open() holding
rfcomm_mutex while l2cap_chan_connect() takes hdev->lock. syzbot's own
reproducer no longer triggers with it:
https://lore.kernel.org/all/6ab100d7.71f81b7d.15fa6d.0029.GAE@google.com/
v4 will follow shortly. It adds a check for the socket being closed while
it is being connected, which Luiz and the Sashiko review raised on v3.
I will Cc you and add your report as Reported-by and Closes.
Could you run your C reproducer against v4 once it is out? A Tested-by
from your side would be worth a lot, since your trace hits the cycle from
the connect side, which is the edge the patch removes.
--
Thanks,
Mikhail
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Linux Kernel Bug] possible deadlock in l2cap_chan_connect
2026-09-29 7:25 ` Mikhail Gavrilov
@ 2026-09-29 7:41 ` Jiaming Zhang
0 siblings, 0 replies; 4+ messages in thread
From: Jiaming Zhang @ 2026-09-29 7:41 UTC (permalink / raw)
To: Mikhail Gavrilov
Cc: Ali Ahmet Memiş,
marcel, luiz.dentz, linux-bluetooth, linux-kernel, kees, kuba,
nicoyip.dev, suunj1331, syzkaller, Pauli Virtanen
Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com> 于2026年9月29日周二 15:26写道:
>
> On Fri, Sep 11, 2026 at 11:38 PM Ali Ahmet Memiş <aliamemis@disroot.org> wrote:
> >
> > On Sat, Sep 12, 2026 at 12:59:09AM +0800, Jiaming Zhang wrote:
> > > We are actively working on a patch, if the above solution is acceptable,
> > > I would be happy to submit a formal patch for review.
> >
> > This is the same lock inversion syzbot reported as 74071deb, and Mikhail
> > already has a fix for it under review:
> >
> > https://lore.kernel.org/linux-bluetooth/20260904012028.77590-1-mikhail.v.gavrilov@gmail.com/
> >
> > It uses the same approach you describe, queue the confirmation and let
> > krfcommd handle it under rfcomm_mutex.
>
> Hi Jiaming, Ali,
>
> thanks for the report and for putting the reproducer up, and thanks
> Ali for connecting the two threads.
>
> The deferral Jiaming suggests is what v2 of my patch did - that is the
> version Ali linked - but that approach was dropped during review. Pauli
> pointed out that delaying the confirmation makes it hard to rule out new
> races against DLC setup, and Luiz asked to break the cycle on the connect
> side instead.
>
> v3 does that. The session socket is created and connected without
> rfcomm_mutex held, and the lock is only taken again to put the new
> session on the list:
>
> https://lore.kernel.org/linux-bluetooth/20260912100315.151674-1-mikhail.v.gavrilov@gmail.com/
>
> That removes exactly the edge in your trace, rfcomm_dlc_open() holding
> rfcomm_mutex while l2cap_chan_connect() takes hdev->lock. syzbot's own
> reproducer no longer triggers with it:
>
> https://lore.kernel.org/all/6ab100d7.71f81b7d.15fa6d.0029.GAE@google.com/
>
> v4 will follow shortly. It adds a check for the socket being closed while
> it is being connected, which Luiz and the Sashiko review raised on v3.
> I will Cc you and add your report as Reported-by and Closes.
>
> Could you run your C reproducer against v4 once it is out? A Tested-by
> from your side would be worth a lot, since your trace hits the cycle from
> the connect side, which is the edge the patch removes.
>
Hi Mikhail,
Sure, I will run my reproducer when the v4 patch is out, and report
the test result as soon as possible.
Thank you for your contribution to fix this issue.
Best Regards,
Jiaming Zhang
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-29 7:42 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-11 16:59 [Linux Kernel Bug] possible deadlock in l2cap_chan_connect Jiaming Zhang
2026-09-11 18:38 ` Ali Ahmet Memiş
2026-09-29 7:25 ` Mikhail Gavrilov
2026-09-29 7:41 ` Jiaming Zhang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®