Skip to content

Commit 9dba9a4

Browse files
John Evansmartinkpetersen
authored andcommitted
scsi: lpfc: Fix buffer free/clear order in deferred receive path
Fix a use-after-free window by correcting the buffer release sequence in the deferred receive path. The code freed the RQ buffer first and only then cleared the context pointer under the lock. Concurrent paths (e.g., ABTS and the repost path) also inspect and release the same pointer under the lock, so the old order could lead to double-free/UAF. Note that the repost path already uses the correct pattern: detach the pointer under the lock, then free it after dropping the lock. The deferred path should do the same. Fixes: 472e146 ("scsi: lpfc: Correct upcalling nvmet_fc transport during io done downcall") Cc: [email protected] Signed-off-by: John Evans <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Justin Tee <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 6300d5c commit 9dba9a4

File tree

1 file changed

+6
-4
lines changed

1 file changed

+6
-4
lines changed

drivers/scsi/lpfc/lpfc_nvmet.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,31 +1243,33 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport,
12431243
struct lpfc_nvmet_tgtport *tgtp;
12441244
struct lpfc_async_xchg_ctx *ctxp =
12451245
container_of(rsp, struct lpfc_async_xchg_ctx, hdlrctx.fcp_req);
1246-
struct rqb_dmabuf *nvmebuf = ctxp->rqb_buffer;
1246+
struct rqb_dmabuf *nvmebuf;
12471247
struct lpfc_hba *phba = ctxp->phba;
12481248
unsigned long iflag;
12491249

12501250

12511251
lpfc_nvmeio_data(phba, "NVMET DEFERRCV: xri x%x sz %d CPU %02x\n",
12521252
ctxp->oxid, ctxp->size, raw_smp_processor_id());
12531253

1254+
spin_lock_irqsave(&ctxp->ctxlock, iflag);
1255+
nvmebuf = ctxp->rqb_buffer;
12541256
if (!nvmebuf) {
1257+
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
12551258
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
12561259
"6425 Defer rcv: no buffer oxid x%x: "
12571260
"flg %x ste %x\n",
12581261
ctxp->oxid, ctxp->flag, ctxp->state);
12591262
return;
12601263
}
1264+
ctxp->rqb_buffer = NULL;
1265+
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
12611266

12621267
tgtp = phba->targetport->private;
12631268
if (tgtp)
12641269
atomic_inc(&tgtp->rcv_fcp_cmd_defer);
12651270

12661271
/* Free the nvmebuf since a new buffer already replaced it */
12671272
nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
1268-
spin_lock_irqsave(&ctxp->ctxlock, iflag);
1269-
ctxp->rqb_buffer = NULL;
1270-
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
12711273
}
12721274

12731275
/**

0 commit comments

Comments
 (0)