]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ksmbd: fix potential use-after-free in oplock/lease break ack
authorNamjae Jeon <linkinjeon@kernel.org>
Mon, 7 Jul 2025 22:47:40 +0000 (07:47 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Jul 2025 16:44:04 +0000 (18:44 +0200)
commit 50f930db22365738d9387c974416f38a06e8057e upstream.

If ksmbd_iov_pin_rsp return error, use-after-free can happen by
accessing opinfo->state and opinfo_put and ksmbd_fd_put could
called twice.

Reported-by: Ziyan Xu <research@securitygossip.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/smb/server/smb2pdu.c

index ad2b15ec3b561d7254892dc299fdb5516c9cdfcf..f1c7ed1a6ca59d497ee575dc58fa649bf7d427fc 100644 (file)
@@ -8535,11 +8535,6 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
                goto err_out;
        }
 
-       opinfo->op_state = OPLOCK_STATE_NONE;
-       wake_up_interruptible_all(&opinfo->oplock_q);
-       opinfo_put(opinfo);
-       ksmbd_fd_put(work, fp);
-
        rsp->StructureSize = cpu_to_le16(24);
        rsp->OplockLevel = rsp_oplevel;
        rsp->Reserved = 0;
@@ -8547,16 +8542,15 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
        rsp->VolatileFid = volatile_id;
        rsp->PersistentFid = persistent_id;
        ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_oplock_break));
-       if (!ret)
-               return;
-
+       if (ret) {
 err_out:
+               smb2_set_err_rsp(work);
+       }
+
        opinfo->op_state = OPLOCK_STATE_NONE;
        wake_up_interruptible_all(&opinfo->oplock_q);
-
        opinfo_put(opinfo);
        ksmbd_fd_put(work, fp);
-       smb2_set_err_rsp(work);
 }
 
 static int check_lease_state(struct lease *lease, __le32 req_state)
@@ -8686,11 +8680,6 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
        }
 
        lease_state = lease->state;
-       opinfo->op_state = OPLOCK_STATE_NONE;
-       wake_up_interruptible_all(&opinfo->oplock_q);
-       atomic_dec(&opinfo->breaking_cnt);
-       wake_up_interruptible_all(&opinfo->oplock_brk);
-       opinfo_put(opinfo);
 
        rsp->StructureSize = cpu_to_le16(36);
        rsp->Reserved = 0;
@@ -8699,16 +8688,16 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
        rsp->LeaseState = lease_state;
        rsp->LeaseDuration = 0;
        ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_lease_ack));
-       if (!ret)
-               return;
-
+       if (ret) {
 err_out:
+               smb2_set_err_rsp(work);
+       }
+
+       opinfo->op_state = OPLOCK_STATE_NONE;
        wake_up_interruptible_all(&opinfo->oplock_q);
        atomic_dec(&opinfo->breaking_cnt);
        wake_up_interruptible_all(&opinfo->oplock_brk);
-
        opinfo_put(opinfo);
-       smb2_set_err_rsp(work);
 }
 
 /**