]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: fix use-after-free in same_client_has_lease()
authorGuangshuo Li <lgs201920130244@gmail.com>
Fri, 5 Jun 2026 04:30:16 +0000 (12:30 +0800)
committerSteve French <stfrench@microsoft.com>
Tue, 16 Jun 2026 23:57:21 +0000 (18:57 -0500)
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>
fs/smb/server/oplock.c

index b193dde4810dca34037bba75d374089fae9b3177..60e7e821c2455db2f073b1c8bc2089d246f16639 100644 (file)
@@ -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;
                }
        }