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)
committerSteve French <stfrench@microsoft.com>
Tue, 8 Jul 2025 16:25:44 +0000 (11:25 -0500)
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>
fs/smb/server/smb2pdu.c

index fafa86273f1216d4ef68d4a62107470615553322..63d17cea2e95f93fad36f34d89a112fce7fd16a5 100644 (file)
@@ -8573,11 +8573,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;
@@ -8585,16 +8580,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)
@@ -8724,11 +8718,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;
@@ -8737,16 +8726,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);
 }
 
 /**