diff options
| author | Ali Khaledi <ali.khaledi1989@gmail.com> | 2026-03-02 10:15:48 +0900 |
|---|---|---|
| committer | Steve French <stfrench@microsoft.com> | 2026-03-08 21:28:39 -0500 |
| commit | 40955015fae4908157ac6c959ea696d05e6e9b31 (patch) | |
| tree | fb7cbad1d16f8a63a0d13946e47d1321c77fe7f2 | |
| parent | c15e7c62feb3751cbdd458555819df1d70374890 (diff) | |
ksmbd: fix use-after-free in proc_show_files due to early rcu_read_unlock
The opinfo pointer obtained via rcu_dereference(fp->f_opinfo) is
dereferenced after rcu_read_unlock(), creating a use-after-free
window. A concurrent opinfo_put() can free the opinfo between the
unlock and the subsequent access to opinfo->is_lease,
opinfo->o_lease->state, and opinfo->level.
Fix this by deferring rcu_read_unlock() until after all opinfo
field accesses are complete. The values needed (const_names, count,
level) are copied into local variables under the RCU read lock,
and the potentially-sleeping seq_printf calls happen after the
lock is released.
Found by AI-assisted code review (Claude Opus 4.6, Anthropic)
in collaboration with Ali Khaledi.
Cc: stable@vger.kernel.org
Fixes: b38f99c1217a ("ksmbd: add procfs interface for runtime monitoring and statistics")
Signed-off-by: Ali Khaledi <ali.khaledi1989@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
| -rw-r--r-- | fs/smb/server/vfs_cache.c | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c index ff4ea412d900..168f2dd7e200 100644 --- a/fs/smb/server/vfs_cache.c +++ b/fs/smb/server/vfs_cache.c @@ -87,11 +87,7 @@ static int proc_show_files(struct seq_file *m, void *v) rcu_read_lock(); opinfo = rcu_dereference(fp->f_opinfo); - rcu_read_unlock(); - - if (!opinfo) { - seq_printf(m, " %-15s", " "); - } else { + if (opinfo) { const struct ksmbd_const_name *const_names; int count; unsigned int level; @@ -105,8 +101,12 @@ static int proc_show_files(struct seq_file *m, void *v) count = ARRAY_SIZE(ksmbd_oplock_const_names); level = opinfo->level; } + rcu_read_unlock(); ksmbd_proc_show_const_name(m, " %-15s", const_names, count, level); + } else { + rcu_read_unlock(); + seq_printf(m, " %-15s", " "); } seq_printf(m, " %#010x %#010x %s\n", |
