]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ksmbd: pin conn during async oplock break notification
authorQihang <q.h.hack.winter@gmail.com>
Thu, 9 Jul 2026 14:49:55 +0000 (22:49 +0800)
committerSteve French <stfrench@microsoft.com>
Thu, 16 Jul 2026 15:18:25 +0000 (10:18 -0500)
smb2_oplock_break_noti() and smb2_lease_break_noti() store a ksmbd_conn
pointer in an async ksmbd_work and then queue that work on ksmbd-io.  The
work only increments conn->r_count, which prevents teardown from passing
the pending-request wait after the increment, but it does not pin the
struct ksmbd_conn object.

If connection teardown races with an oplock break notification, the last
conn reference can be dropped before the queued worker finishes.  The
worker then uses the freed conn in ksmbd_conn_write() and
ksmbd_conn_r_count_dec().

Take a real conn reference when publishing the conn pointer to the async
work item, and drop it after the notification work has decremented
r_count.  Apply the same lifetime rule to lease break notification, which
uses the same work->conn pattern.

Fixes: 3aa660c05924 ("ksmbd: prevent connection release during oplock break notification")
Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/oplock.c

index 3c55ae5d6a11b68bc9712199c101ebfecd861778..79787099afdc68c0a4afb20f6535f45e89695ba9 100644 (file)
@@ -875,6 +875,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
 out:
        ksmbd_free_work_struct(work);
        ksmbd_conn_r_count_dec(conn);
+       ksmbd_conn_put(conn);
 }
 
 /**
@@ -910,7 +911,7 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo)
        br_info->open_trunc = opinfo->open_trunc;
 
        work->request_buf = (char *)br_info;
-       work->conn = conn;
+       work->conn = ksmbd_conn_get(conn);
        work->sess = opinfo->sess;
 
        ksmbd_conn_r_count_inc(conn);
@@ -985,6 +986,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
 out:
        ksmbd_free_work_struct(work);
        ksmbd_conn_r_count_dec(conn);
+       ksmbd_conn_put(conn);
 }
 
 /**
@@ -1034,7 +1036,7 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo, bool wait_ack,
        memcpy(br_info->lease_key, lease->lease_key, SMB2_LEASE_KEY_SIZE);
 
        work->request_buf = (char *)br_info;
-       work->conn = conn;
+       work->conn = ksmbd_conn_get(conn);
        work->sess = opinfo->sess;
 
        ksmbd_conn_r_count_inc(conn);