mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 14:33:24 -04:00
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:
committed by
Martin K. Petersen (Oracle)
parent
b7368687e3
commit
53298efcbb
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user