scsi: qla2xxx: Fix FCE trace use-after-free during firmware dump

qla2x00_free_fce_trace() freed and cleared ha->fce while holding only
fce_mutex. The firmware-dump consumers qla27xx_fwdt_entry_t264() and
qla25xx_copy_fce() read ha->fce (NULL check followed by a copy of the
buffer) under hardware_lock and never take fce_mutex. A debugfs FCE
disable could therefore free the DMA buffer between a dump's NULL check
and its copy, resulting in a use-after-free.

Unpublish ha->fce under hardware_lock, then release the lock and free
the DMA buffer (dma_free_coherent() may sleep). A concurrent dump either
completes its check and copy with the buffer still valid, or observes
ha->fce == NULL and skips it.

Fixes: 841df27d61 ("scsi: qla2xxx: Move FCE Trace buffer allocation to user control")
Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-dev@google.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Link: https://patch.msgid.link/20260730155838.2119230-11-njavali@marvell.com
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
Nilesh Javali
2026-07-30 21:28:15 +05:30
committed by Martin K. Petersen (Oracle)
parent b7368687e3
commit 53298efcbb

View File

@@ -3752,11 +3752,27 @@ int qla2x00_alloc_fce_trace(scsi_qla_host_t *vha)
void qla2x00_free_fce_trace(struct qla_hw_data *ha)
{
if (!ha->fce)
void *fce;
dma_addr_t fce_dma;
unsigned long flags;
/*
* Unpublish ha->fce under hardware_lock so a firmware dump in
* progress (which reads ha->fce under the same lock) cannot race
* with the buffer being freed.
*/
spin_lock_irqsave(&ha->hardware_lock, flags);
if (!ha->fce) {
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return;
dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce, ha->fce_dma);
}
fce = ha->fce;
fce_dma = ha->fce_dma;
ha->fce = NULL;
ha->fce_dma = 0;
spin_unlock_irqrestore(&ha->hardware_lock, flags);
dma_free_coherent(&ha->pdev->dev, FCE_SIZE, fce, fce_dma);
}
static void