[BUG] Linux Kernel ksmbd Oplock Break vs Session Teardown Circular Deadlock
From: ven0mfuzzer
Date: Thu Apr 02 2026 - 07:09:48 EST
Linux Kernel ksmbd Oplock Break vs Session Teardown Circular Deadlock
1. Vulnerability Title
Linux Kernel ksmbd Server Circular Locking Deadlock in Oplock Break Notification vs Session Teardown (via truncate/set_info)
2. High-Level Overview
A circular locking dependency exists in the Linux kernel ksmbd (in-kernel SMB server) between the oplock break notification path and the session teardown path. When `smb2_set_info` performs a file truncate via `ksmbd_vfs_truncate()`, it calls `smb_break_all_levII_oplock()` which holds `ci->m_lock` and then attempts to send an oplock break notification via `ksmbd_conn_write()`, which requires `conn->srv_mutex`. Simultaneously, the session teardown path holds `srv_mutex` (via `ksmbd_conn_handler_loop`) and walks through `ksmbd_sessions_deregister → ksmbd_session_destroy → __close_file_table_ids`, which requires `ci->m_lock`. This creates a 3-level circular lock chain (`srv_mutex → session_lock → m_lock → srv_mutex`). When the deadlock fires, ksmbd worker threads enter D-state and the SMB server becomes completely unresponsive — a denial-of-service condition.
This vulnerability was discovered using ven0mfuzzer, our custom-designed MITM-based network filesystem fuzzer developed by our team. Following the common syzkaller practice, we submit the kernel crash trace as the primary reproduction artifact.
3. Affected Product and Version Information
Product: Linux Kernel (upstream mainline)
Affected Component: `fs/smb/server/oplock.c` — `smb_break_all_levII_oplock()`, `oplock_break()`
Supporting Components:
- `fs/smb/server/connection.c` — `ksmbd_conn_write()` (acquires `srv_mutex`)
- `fs/smb/server/vfs.c` — `ksmbd_vfs_truncate()` (triggers oplock break)
- `fs/smb/server/mgmt/user_session.c` — `ksmbd_session_destroy()` (acquires `m_lock` under `session_lock`)
- `fs/smb/server/smb2pdu.c` — `smb2_set_info()`, `smb2_sess_setup()`
Tested Versions (confirmed vulnerable)
- Linux kernel 6.19.0 (mainline, commit `44331bd6a610`, gcc 11.4.0, built 2026-02-13)
- Linux kernel 6.12.74 (LTS, used in Google kernelCTF COS target)
Affected Version Range
All kernels with ksmbd oplock support (approximately 5.15 through 6.19) are believed affected.
Affected Distributions and Products
| Vendor / Product | Notes |
| --- | --- |
| Red Hat Enterprise Linux (RHEL 9.x) | Ships kernels >= 5.14 with ksmbd module |
| Ubuntu (22.04 LTS, 24.04 LTS) | HWE kernels 6.x include ksmbd |
| SUSE Linux Enterprise Server (SLES 15 SP5+) | Kernel 6.x based |
| Debian (Bookworm, Trixie) | Kernels 6.1+ |
| Fedora (39+) | Kernels 6.5+ |
| Amazon Linux 2023 | Kernel 6.1 LTS based |
| Google ChromeOS / COS | kernelCTF target, confirmed vulnerable on 6.12.74 |
4. Root Cause Analysis
4.a. Detailed Description
The deadlock involves three locks forming a circular dependency chain:
Path A (oplock break, triggered by truncate):
`smb2_set_info()` → `ksmbd_vfs_truncate()` → `smb_break_all_levII_oplock()` acquires `ci->m_lock` (read lock at offset +0x12a), then calls `oplock_break()` → `__smb2_oplock_break_noti()` → `ksmbd_conn_write()` which attempts to acquire `conn->srv_mutex` (at offset +0x100).
Path B (session teardown):
`ksmbd_conn_handler_loop()` → `ksmbd_server_terminate_conn()` → `ksmbd_sessions_deregister()` implicitly holds `srv_mutex`, acquires `session_lock`, then calls `ksmbd_session_destroy()` → `ksmbd_destroy_file_table()` → `__close_file_table_ids()` which attempts `down_write(ci->m_lock)`.
Path C (session setup — establishes the `srv_mutex → session_lock` ordering):
`smb2_sess_setup()` → `ksmbd_session_lookup()` acquires `session_lock`.
The deadlock occurs when Path A and Path B execute concurrently on different CPUs with overlapping inodes.
4.b. Code Flow
---
Path A (oplock break — holds m_lock, wants srv_mutex):
smb2_set_info+0x16d4/0x30e0
→ ksmbd_vfs_truncate+0x46/0x230
→ smb_break_all_levII_oplock+0x12a/0x940 [acquires ci->m_lock]
→ oplock_break+0xda9/0x15d0
→ __smb2_oplock_break_noti+0x8ac/0xba0
→ ksmbd_conn_write+0x100/0x400 [wants srv_mutex]
Path B (session teardown — holds srv_mutex, wants m_lock):
ksmbd_conn_handler_loop+0xaf1/0xfd0
→ ksmbd_server_terminate_conn+0x15/0x30
→ ksmbd_sessions_deregister+0x41d/0x750 [holds srv_mutex]
→ ksmbd_session_destroy+0x105/0x3e0
→ ksmbd_destroy_file_table+0x4a/0xe0
→ __close_file_table_ids+0x1ad/0x430 [wants ci->m_lock]
Deadlock scenario:
CPU0 CPU1
---- ----
rlock(&ci->m_lock)
lock(&conn->session_lock)
lock(&ci->m_lock) ← waits CPU0
lock(&conn->srv_mutex) ← waits CPU1
DEADLOCK
---
4.c. Crash Trace
This vulnerability was discovered by ven0mfuzzer. The following kernel trace is submitted following syzkaller's common practice of providing the raw crash trace as the primary reproduction evidence:
---
[ 3286.027108] WARNING: possible circular locking dependency detected
[ 3286.027585] 6.19.0-g44331bd6a610-dirty #5 Not tainted
[ 3286.027961] ------------------------------------------------------
[ 3286.028420] kworker/0:2/975 is trying to acquire lock:
[ 3286.028810] ffff88810dc43888 (&conn->srv_mutex){+.+.}-{4:4}, at: ksmbd_conn_write+0x100/0x400
but task is already holding lock:
[ 3286.030012] ffff88811016e570 (&ci->m_lock){++++}-{4:4}, at: smb_break_all_levII_oplock+0x12a/0x940
the existing dependency chain (in reverse order) is:
-> #2 (&ci->m_lock){++++}-{4:4}:
[ 3286.032186] lock_acquire+0x150/0x2c0
[ 3286.032539] down_write+0x92/0x1f0
[ 3286.032868] __close_file_table_ids+0x1ad/0x430
[ 3286.033284] ksmbd_destroy_file_table+0x4a/0xe0
[ 3286.033675] ksmbd_session_destroy+0x105/0x3e0
[ 3286.034053] ksmbd_sessions_deregister+0x41d/0x750
[ 3286.034453] ksmbd_server_terminate_conn+0x15/0x30
[ 3286.034864] ksmbd_conn_handler_loop+0xaf1/0xfd0
[ 3286.035286] kthread+0x378/0x490
-> #1 (&conn->session_lock){++++}-{4:4}:
[ 3286.036859] lock_acquire+0x150/0x2c0
[ 3286.037198] down_read+0x9b/0x450
[ 3286.037528] ksmbd_session_lookup+0x22/0xd0
[ 3286.037944] smb2_sess_setup+0x5aa/0x5fb0
[ 3286.038310] handle_ksmbd_work+0x4f5/0x1330
[ 3286.038709] process_one_work+0x962/0x1a40
-> #0 (&conn->srv_mutex){+.+.}-{4:4}:
[ 3286.040983] check_prev_add+0xeb/0xd00
[ 3286.041313] __lock_acquire+0x1641/0x2260
[ 3286.041645] lock_acquire+0x150/0x2c0
[ 3286.041956] __mutex_lock+0x19f/0x2330
[ 3286.042268] ksmbd_conn_write+0x100/0x400
[ 3286.042625] __smb2_oplock_break_noti+0x8ac/0xba0
[ 3286.043002] oplock_break+0xda9/0x15d0
[ 3286.043234] smb_break_all_levII_oplock+0x6a7/0x940
[ 3286.043506] ksmbd_vfs_truncate+0x46/0x230
[ 3286.043744] smb2_set_info+0x16d4/0x30e0
[ 3286.043974] handle_ksmbd_work+0x4f5/0x1330
[ 3286.044208] process_one_work+0x962/0x1a40
Chain exists of:
&conn->srv_mutex --> &conn->session_lock --> &ci->m_lock
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
rlock(&ci->m_lock);
lock(&conn->session_lock);
lock(&ci->m_lock);
lock(&conn->srv_mutex);
DEADLOCK
[ 3286.049466] 3 locks held by kworker/0:2/975:
[ 3286.049756] #0: ffff888103737b48 ((wq_completion)ksmbd-io){+.+.}-{0:0}, at: process_one_work+0x11d8/0x1a40
[ 3286.050395] #1: ffffc900014d7d00 ((work_completion)(&work->work)){+.+.}-{0:0}, at: process_one_work+0x8d8/0x1a40
[ 3286.051136] #2: ffff88811016e570 (&ci->m_lock){++++}-{4:4}, at: smb_break_all_levII_oplock+0x12a/0x940
[ 3286.052242] CPU: 0 UID: 0 PID: 975 Comm: kworker/0:2 Not tainted 6.19.0-g44331bd6a610-dirty #5
[ 3286.052304] Workqueue: ksmbd-io handle_ksmbd_work
---
4.d. Suggested Fix
The root cause is that `smb_break_all_levII_oplock()` calls `ksmbd_conn_write()` while holding `ci->m_lock`. The fix should either:
1. Preferred: Asynchronous oplock break — Queue the oplock break notification to a workqueue instead of sending inline during handler execution. This is the cleanest solution.
2. Drop `ci->m_lock` before calling `ksmbd_conn_write()` in the oplock break path
3. Use a separate lock for the oplock break write that does not conflict with the session teardown ordering
Related source files:
- `fs/smb/server/oplock.c` — `smb_break_all_levII_oplock()`, `oplock_break()`
- `fs/smb/server/connection.c` — `ksmbd_conn_write()`
- `fs/smb/server/mgmt/user_session.c` — `ksmbd_session_destroy()`
- `fs/smb/server/smb2pdu.c` — `smb2_set_info()`, `smb2_sess_setup()`
5. Discovery Method and Reproduction
5.a. Discovery
This vulnerability was discovered using ven0mfuzzer, a custom-designed MITM-based network filesystem fuzzer developed by our team. The fuzzer operates by positioning an AF_PACKET/TCP transparent proxy between a Linux kernel filesystem client (VM-A) and its server (VM-B), then mutating network protocol messages in-flight.
Following the common syzkaller practice, we submit the kernel crash trace as the primary reproduction artifact. The trace above was captured with LOCKDEP (CONFIG_PROVE_LOCKING) enabled on kernel 6.19.0.
5.b. Reproduction Setup
---
VM-A (CIFS client) ──SMB2──► Host:44446 (MITM proxy) ──TCP──► Host:44445 ──hostfwd──► VM-B:445 (ksmbd)
---
Trigger conditions:
- ksmbd server with oplocks and leases enabled (default)
- Multiple concurrent SMB sessions with open files on overlapping inodes
- One session performs truncate/set_info (triggers oplock break)
- Another connection is simultaneously setting up or tearing down
---
Reported-by: ven0mfuzzer <ven0mkernelfuzzer@xxxxxxxxx>
Link: https://github.com/KernelStackFuzz/KernelStackFuzz