diff options
| author | Guangshuo Li <lgs201920130244@gmail.com> | 2026-06-05 12:30:16 +0800 |
|---|---|---|
| committer | Steve French <stfrench@microsoft.com> | 2026-06-16 18:57:21 -0500 |
| commit | 65b655f65c3ca1ab5d598d3832bb0ff531725858 (patch) | |
| tree | 7c2200e4f69baf8c8a4be91b33c566d526e23f0b /fs | |
| parent | 1ef06004ed4bd6d3ed8c840d9d1a376b66d4935b (diff) | |
ksmbd: fix use-after-free in same_client_has_lease()
same_client_has_lease() returns an opinfo pointer from ci->m_op_list
after dropping ci->m_lock without taking a reference.
smb_grant_oplock() then dereferences that pointer in copy_lease() and
when checking breaking_cnt. A concurrent close can remove the old lease
from ci->m_op_list and drop the last reference before the caller uses
the returned pointer, leading to a use-after-free.
Take a reference when same_client_has_lease() selects an existing lease,
drop any previous match while scanning, and release the returned
reference in smb_grant_oplock() after copying the lease state.
Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/smb/server/oplock.c | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c index b193dde4810d..60e7e821c245 100644 --- a/fs/smb/server/oplock.c +++ b/fs/smb/server/oplock.c @@ -528,7 +528,12 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci, ret = compare_guid_key(opinfo, client_guid, lctx->lease_key); if (ret) { + if (!atomic_inc_not_zero(&opinfo->refcount)) + continue; + if (m_opinfo) + opinfo_put(m_opinfo); m_opinfo = opinfo; + /* skip upgrading lease about breaking lease */ if (atomic_read(&opinfo->breaking_cnt)) continue; @@ -1246,6 +1251,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid, if (atomic_read(&m_opinfo->breaking_cnt)) opinfo->o_lease->flags = SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE; + opinfo_put(m_opinfo); goto out; } } |
