[Linux Kernel Bug] possible deadlock in l2cap_chan_connect
From: Jiaming Zhang
Date: Fri Sep 11 2026 - 13:23:08 EST
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