* [PATCH] ksmbd: release ksmbd_inode ref via ksmbd_inode_put on lookup paths
@ 2026-05-25 18:50 Aleksandr Golovnya
2026-05-26 0:16 ` Namjae Jeon
0 siblings, 1 reply; 2+ messages in thread
From: Aleksandr Golovnya @ 2026-05-25 18:50 UTC (permalink / raw)
To: Namjae Jeon, Steve French
Cc: Sergey Senozhatsky, Tom Talpey, linux-cifs, linux-kernel
ksmbd_query_inode_status() and ksmbd_lookup_fd_inode() both take a
reference on a ksmbd_inode via __ksmbd_inode_lookup() (which performs
atomic_inc_not_zero()) and later release it using a bare
atomic_dec(&ci->m_count). Unlike ksmbd_inode_put(), a bare
atomic_dec() does not check whether the reference count has reached
zero, so if the caller happens to drop the last reference, the
ksmbd_inode is leaked: it stays in the global inode hash table with
m_count == 0, future __ksmbd_inode_lookup() calls reject it via
atomic_inc_not_zero(), and ksmbd_inode_free() is never invoked.
The race is:
T1: __ksmbd_inode_lookup() -> atomic_inc_not_zero(): m_count = 2
T2: ksmbd_inode_put() -> atomic_dec_and_test(): m_count = 1
(not freed)
T1: atomic_dec(&ci->m_count) -> m_count = 0
return (LEAK)
In ksmbd_lookup_fd_inode() the matched-fp path (which now also uses
ksmbd_inode_put()) cannot currently reach m_count == 0 because the
matched ksmbd_file holds its own reference on ci, but converting it to
the proper API keeps the three call sites consistent and avoids
future regressions if the locking changes.
Because ksmbd_inode_put() may free the ksmbd_inode if this drops the
last reference, the call must happen after up_read(&ci->m_lock) on the
two affected paths in ksmbd_lookup_fd_inode(). On the no-match path
this is a pure reordering; on the matched path ksmbd_fp_get() is
moved above the unlock so that the returned ksmbd_file is pinned
before the inode reference is released.
Signed-off-by: Aleksandr Golovnya <cofedish@gmail.com>
---
fs/smb/server/vfs_cache.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
index 5a232d9..4d2d33d 100644
--- a/fs/smb/server/vfs_cache.c
+++ b/fs/smb/server/vfs_cache.c
@@ -217,7 +217,7 @@ int ksmbd_query_inode_status(struct dentry *dentry)
ret = KSMBD_INODE_STATUS_OK;
up_read(&ci->m_lock);
- atomic_dec(&ci->m_count);
+ ksmbd_inode_put(ci);
return ret;
}
@@ -719,14 +719,14 @@ struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry)
down_read(&ci->m_lock);
list_for_each_entry(lfp, &ci->m_fp_list, node) {
if (inode == file_inode(lfp->filp)) {
- atomic_dec(&ci->m_count);
lfp = ksmbd_fp_get(lfp);
up_read(&ci->m_lock);
+ ksmbd_inode_put(ci);
return lfp;
}
}
- atomic_dec(&ci->m_count);
up_read(&ci->m_lock);
+ ksmbd_inode_put(ci);
return NULL;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH] ksmbd: release ksmbd_inode ref via ksmbd_inode_put on lookup paths
2026-05-25 18:50 [PATCH] ksmbd: release ksmbd_inode ref via ksmbd_inode_put on lookup paths Aleksandr Golovnya
@ 2026-05-26 0:16 ` Namjae Jeon
0 siblings, 0 replies; 2+ messages in thread
From: Namjae Jeon @ 2026-05-26 0:16 UTC (permalink / raw)
To: Aleksandr Golovnya
Cc: Steve French, Sergey Senozhatsky, Tom Talpey, linux-cifs,
linux-kernel
On Tue, May 26, 2026 at 3:50 AM Aleksandr Golovnya <cofedish@gmail.com> wrote:
>
> ksmbd_query_inode_status() and ksmbd_lookup_fd_inode() both take a
> reference on a ksmbd_inode via __ksmbd_inode_lookup() (which performs
> atomic_inc_not_zero()) and later release it using a bare
> atomic_dec(&ci->m_count). Unlike ksmbd_inode_put(), a bare
> atomic_dec() does not check whether the reference count has reached
> zero, so if the caller happens to drop the last reference, the
> ksmbd_inode is leaked: it stays in the global inode hash table with
> m_count == 0, future __ksmbd_inode_lookup() calls reject it via
> atomic_inc_not_zero(), and ksmbd_inode_free() is never invoked.
>
> The race is:
>
> T1: __ksmbd_inode_lookup() -> atomic_inc_not_zero(): m_count = 2
> T2: ksmbd_inode_put() -> atomic_dec_and_test(): m_count = 1
> (not freed)
> T1: atomic_dec(&ci->m_count) -> m_count = 0
> return (LEAK)
>
> In ksmbd_lookup_fd_inode() the matched-fp path (which now also uses
> ksmbd_inode_put()) cannot currently reach m_count == 0 because the
> matched ksmbd_file holds its own reference on ci, but converting it to
> the proper API keeps the three call sites consistent and avoids
> future regressions if the locking changes.
>
> Because ksmbd_inode_put() may free the ksmbd_inode if this drops the
> last reference, the call must happen after up_read(&ci->m_lock) on the
> two affected paths in ksmbd_lookup_fd_inode(). On the no-match path
> this is a pure reordering; on the matched path ksmbd_fp_get() is
> moved above the unlock so that the returned ksmbd_file is pinned
> before the inode reference is released.
>
> Signed-off-by: Aleksandr Golovnya <cofedish@gmail.com>
Applied it to #ksmbd-for-next-next.
Thanks!
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-05-26 0:16 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-25 18:50 [PATCH] ksmbd: release ksmbd_inode ref via ksmbd_inode_put on lookup paths Aleksandr Golovnya
2026-05-26 0:16 ` Namjae Jeon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox