CVE-2026-45924
Description
In the Linux kernel, the following vulnerability has been resolved:
ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
There are two places where ksmbd_vfs_kern_path_end_removing() needs to be called in order to balance what the corresponding successful call to ksmbd_vfs_kern_path_start_removing() has done, i.e. drop inode locks and put the taken references. Otherwise there might be potential deadlocks and unbalanced locks which are caught like:
BUG: workqueue leaked lock or atomic: kworker/5:21/0x00000000/7596 last function: handle_ksmbd_work 2 locks held by kworker/5:21/7596: #0: ffff8881051ae448 (sb_writers#3){.+.+}-{0:0}, at: ksmbd_vfs_kern_path_locked+0x142/0x660 #1: ffff888130e966c0 (&type->i_mutex_dir_key#3/1){+.+.}-{4:4}, at: ksmbd_vfs_kern_path_locked+0x17d/0x660 CPU: 5 PID: 7596 Comm: kworker/5:21 Not tainted 6.1.162-00456-gc29b353f383b #138 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 Workqueue: ksmbd-io handle_ksmbd_work Call Trace:
dump_stack_lvl+0x44/0x5b process_one_work.cold+0x57/0x5c worker_thread+0x82/0x600 kthread+0x153/0x190 ret_from_fork+0x22/0x30
Found by Linux Verification Center (linuxtesting.org).
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A missing call to ksmbd_vfs_kern_path_end_removing() in two error paths of the Linux ksmbd server can lead to deadlocks and unbalanced locks.
Vulnerability
In the Linux kernel ksmbd (SMB/CIFS file server) component, there are two error paths where ksmbd_vfs_kern_path_end_removing() is not called after a successful ksmbd_vfs_kern_path_start_removing(), causing an imbalance in inode locks and reference counts. Affected versions include those prior to the fix in kernel 6.1.162, as indicated by the commit referenced [1]. The issue was introduced when the start/end functions were added for path removal operations.
Exploitation
An attacker with the ability to trigger ksmbd path operations that hit these error paths (likely through crafted SMB requests) can cause the kernel to leak locks and references. This results in warnings such as "BUG: workqueue leaked lock or atomic" and can lead to a denial of service due to deadlocks. The attack requires network access to the ksmbd service and knowledge of how to trigger the specific error conditions.
Impact
A successful exploitation leads to resource leak (locks and references) in the kernel, potentially causing a deadlock that freezes the ksmbd workqueue and denies service to legitimate SMB clients. The impact is primarily availability (denial of service), as no code execution or privilege escalation is described.
Mitigation
The fix is available in the Linux kernel stable tree commit a09dc10d1353f0e92c21eae2a79af1b1ddcde8 [1]. Users should apply the patch or update to a kernel version that includes it. No workaround is mentioned; systems running unpatched kernels are advised to disable ksmbd if not needed.
AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2Patches
148e3a3192ef78ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/ksmbd/smb2pdu.c+2 −3 modifieddiff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c index b5ff4c855f9cb0..9e1d2095b14743 100644 --- a/fs/ksmbd/smb2pdu.c +++ b/fs/ksmbd/smb2pdu.c @@ -5652,14 +5652,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_unlock(&parent_path, &path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
f221baa80e59ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/smb/server/smb2pdu.c+2 −3 modifieddiff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 2feaebb941108b..32b04f85f33c81 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -5693,14 +5693,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_unlock(&parent_path, &path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
cf29329a13dfksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/smb/server/smb2pdu.c+2 −3 modifieddiff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index f19703aad44e5a..70218d90a1dfc7 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6067,14 +6067,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_unlock(&parent_path, &path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
34d669193368ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/smb/server/smb2pdu.c+2 −3 modifieddiff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 35e0d8875089b6..2f396d5bf0c0a1 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6090,14 +6090,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_unlock(&parent_path, &path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
0c578e8065c4ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/smb/server/smb2pdu.c+2 −3 modifieddiff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index bf8c4805943672..e52b9136abbff6 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6117,14 +6117,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_unlock(&path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
a09dc10d1353ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/smb/server/smb2pdu.c+2 −3 modifieddiff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index cbb31efdbaa2e3..2782eea214d0d6 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6115,14 +6115,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_end_removing(&path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
4c38600feb81ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/smb/server/smb2pdu.c+2 −3 modifieddiff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 4c361c6c566ecf..1022d794bd2327 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6114,14 +6114,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_end_removing(&path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
8e3a3192ef78ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/ksmbd/smb2pdu.c+2 −3 modifieddiff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c index b5ff4c855f9cb0..9e1d2095b14743 100644 --- a/fs/ksmbd/smb2pdu.c +++ b/fs/ksmbd/smb2pdu.c @@ -5652,14 +5652,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_unlock(&parent_path, &path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
f221baa80e59ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/smb/server/smb2pdu.c+2 −3 modifieddiff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 2feaebb941108b..32b04f85f33c81 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -5693,14 +5693,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_unlock(&parent_path, &path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
cf29329a13dfksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/smb/server/smb2pdu.c+2 −3 modifieddiff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index f19703aad44e5a..70218d90a1dfc7 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6067,14 +6067,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_unlock(&parent_path, &path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
34d669193368ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/smb/server/smb2pdu.c+2 −3 modifieddiff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 35e0d8875089b6..2f396d5bf0c0a1 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6090,14 +6090,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_unlock(&parent_path, &path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
0c578e8065c4ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/smb/server/smb2pdu.c+2 −3 modifieddiff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index bf8c4805943672..e52b9136abbff6 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6117,14 +6117,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_unlock(&path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
4c38600feb81ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/smb/server/smb2pdu.c+2 −3 modifieddiff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 4c361c6c566ecf..1022d794bd2327 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6114,14 +6114,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_end_removing(&path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
a09dc10d1353ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths
1 file changed · +2 −3
fs/smb/server/smb2pdu.c+2 −3 modifieddiff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index cbb31efdbaa2e3..2782eea214d0d6 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6115,14 +6115,14 @@ static int smb2_create_link(struct ksmbd_work *work, rc = -EINVAL; ksmbd_debug(SMB, "cannot delete %s\n", link_name); - goto out; } } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); - goto out; } ksmbd_vfs_kern_path_end_removing(&path); + if (rc) + goto out; } rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Missing cleanup call to ksmbd_vfs_kern_path_end_removing() on two error paths in smb2_create_link, causing unbalanced locks and references."
Attack vector
An attacker who can send SMB2 create-link requests to the ksmbd server can trigger this bug. When the server processes a link creation where the target already exists (ReplaceIfExists path) or the link name cannot be deleted, the code sets an error code (`-EEXIST` or `-EINVAL`) and previously jumped directly to `out` without releasing the locks and references acquired by `ksmbd_vfs_kern_path_start_removing()`. This leaves inode locks (`i_mutex_dir_key`) and superblock write locks (`sb_writers`) permanently held, leading to a kernel lock leak and potential deadlock.
Affected code
The vulnerability is in the `smb2_create_link` function within `fs/smb/server/smb2pdu.c` (and the older `fs/ksmbd/smb2pdu.c` path). The error-handling logic after a successful `ksmbd_vfs_kern_path_start_removing()` call fails to invoke the balancing `ksmbd_vfs_kern_path_end_removing()` (or `ksmbd_vfs_kern_path_unlock`) on two specific error branches, leaving locks and references held [patch_id=2661289].
What the fix does
The patch removes the two premature `goto out;` statements that were taken when `rc` was set to `-EINVAL` or `-EEXIST`. Instead, the code now falls through to `ksmbd_vfs_kern_path_end_removing(&path)` (or `ksmbd_vfs_kern_path_unlock` in some backports) to properly release the locks and references, and only then checks `if (rc) goto out;` to exit. This ensures the lock/unlock pairing is always balanced on error paths [patch_id=2661289].
Preconditions
- networkAttacker must be able to send SMB2 create-link requests to the ksmbd server
- inputThe target file for the link must already exist (triggering -EEXIST) or the link name must be undeletable (triggering -EINVAL)
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- git.kernel.org/stable/c/0c578e8065c4b08d5635a4cbc0f6321df9d20f79nvd
- git.kernel.org/stable/c/34d6691933682f0516259a31b39d2cebcedec0a5nvd
- git.kernel.org/stable/c/4c38600feb81c670edb82e49d201d3d2d00cd4c3nvd
- git.kernel.org/stable/c/8e3a3192ef78d8302916408d62813b1fddfc8972nvd
- git.kernel.org/stable/c/a09dc10d1353f0e92c21eae2a79af1c2b1ddcde8nvd
- git.kernel.org/stable/c/cf29329a13df79c198b45dfc92577638d30b56fanvd
- git.kernel.org/stable/c/f221baa80e5959a0c08a7e34abbf2a4d3cf0e1c2nvd
News mentions
0No linked articles in our index yet.