]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ksmbd: fix NULL-deref of opinfo->conn in oplock/lease break notifiers
authorGil Portnoy <dddhkts1@gmail.com>
Thu, 28 May 2026 00:00:00 +0000 (00:00 +0000)
committerSteve French <stfrench@microsoft.com>
Mon, 1 Jun 2026 00:13:48 +0000 (19:13 -0500)
smb2_oplock_break_noti() and smb2_lease_break_noti() read opinfo->conn
into a local with neither READ_ONCE() nor a NULL check.  Both run from
oplock_break() after opinfo_get_list() has dropped ci->m_lock, so a
concurrent SMB2 LOGOFF (session_fd_check()) can set op->conn = NULL
under ci->m_lock within that window.  ksmbd_conn_r_count_inc(conn) then
writes through NULL at offset 0xc4 -- a remotely triggerable oops.

Guard both reads the way compare_guid_key() already does: read
opinfo->conn with READ_ONCE() and return early if it is NULL, before
allocating the work struct so nothing leaks.  A NULL conn means the
client is gone and the break is moot, so return 0; oplock_break() treats
that as success and runs the normal teardown.

Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2")
Assisted-by: Henry (Claude):claude-opus-4
Signed-off-by: Gil Portnoy <dddhkts1@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/oplock.c

index 0f5c18520eff0695abe758270a7740c6671375f3..b193dde4810dca34037bba75d374089fae9b3177 100644 (file)
@@ -711,11 +711,16 @@ out:
  */
 static int smb2_oplock_break_noti(struct oplock_info *opinfo)
 {
-       struct ksmbd_conn *conn = opinfo->conn;
+       struct ksmbd_conn *conn;
        struct oplock_break_info *br_info;
        int ret = 0;
-       struct ksmbd_work *work = ksmbd_alloc_work_struct();
+       struct ksmbd_work *work;
+
+       conn = READ_ONCE(opinfo->conn);
+       if (!conn)
+               return 0;
 
+       work = ksmbd_alloc_work_struct();
        if (!work)
                return -ENOMEM;
 
@@ -815,11 +820,15 @@ out:
  */
 static int smb2_lease_break_noti(struct oplock_info *opinfo)
 {
-       struct ksmbd_conn *conn = opinfo->conn;
+       struct ksmbd_conn *conn;
        struct ksmbd_work *work;
        struct lease_break_info *br_info;
        struct lease *lease = opinfo->o_lease;
 
+       conn = READ_ONCE(opinfo->conn);
+       if (!conn)
+               return 0;
+
        work = ksmbd_alloc_work_struct();
        if (!work)
                return -ENOMEM;