mirror of
https://github.com/torvalds/linux.git
synced 2026-09-13 06:23:02 +02:00
pds_core: fix cmd_regs access racing BAR unmap on reset
pdsc_reset_prepare() and pdsc_reset_done()'s pdsc_map_bars() error path
clear/iounmap cmd_regs without devcmd_lock, and
pdsc_legacy_firmware_update()'s download loop derefs cmd_regs after
dropping and retaking the lock without re-checking. An FLR concurrent
with a devlink flash can unmap cmd_regs under an in-flight devcmd,
causing a NULL deref or a write to unmapped MMIO.
Take devcmd_lock across the BAR unmap/remap, and re-check cmd_regs in
the download loop. Only the PF maps cmd_regs and runs devcmd, so skip
the unmap on a VF, as pdsc_remove() and pdsc_reset_done() already do.
A reset that completes entirely within the unlocked window is not a
correctness problem for the image: the device clears its update session,
so a resumed download is rejected, and it verifies the staged image
before writing a flash slot, reporting PDS_RC_BAD_FW rather than
activating it.
pdsc_unmap_bars() also clears info_regs, intr_status and intr_ctrl. The
interrupt and start/stop readers of those are quiesced before the unmap
by pdsc_fw_down(), which frees the interrupts and tears down the queues.
The debugfs readers are not, since those files outlive a reset; that is
pre-existing and out of scope here.
Fixes: e96094c1d1 ("pds_core: Clear BARs on reset")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260708212222.296202-1-nikhil.rao%40amd.com?part=3
Signed-off-by: Nikhil P. Rao <nikhil.rao@amd.com>
Link: https://patch.msgid.link/20260901044219.1361466-2-nikhil.rao@amd.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
6262acad9d
commit
7980325b2f
|
|
@ -171,8 +171,10 @@ pdsc_legacy_firmware_update(struct pdsc *pdsc,
|
|||
|
||||
dev_info(pdsc->dev, "Installing firmware\n");
|
||||
|
||||
if (!pdsc->cmd_regs)
|
||||
if (!pdsc->cmd_regs) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "BARs not mapped");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
dl = priv_to_devlink(pdsc);
|
||||
devlink_flash_update_status_notify(dl, "Preparing to flash",
|
||||
|
|
@ -198,6 +200,12 @@ pdsc_legacy_firmware_update(struct pdsc *pdsc,
|
|||
|
||||
copy_sz = min_t(unsigned int, buf_sz, fw->size - offset);
|
||||
mutex_lock(&pdsc->devcmd_lock);
|
||||
if (!pdsc->cmd_regs) {
|
||||
mutex_unlock(&pdsc->devcmd_lock);
|
||||
err = -ENXIO;
|
||||
NL_SET_ERR_MSG_MOD(extack, "Device reset during flash");
|
||||
goto err_out;
|
||||
}
|
||||
memcpy_toio(&pdsc->cmd_regs->data, fw->data + offset, copy_sz);
|
||||
err = pdsc_devcmd_fw_download_locked(pdsc, data_addr,
|
||||
offset, copy_sz);
|
||||
|
|
|
|||
|
|
@ -513,7 +513,11 @@ static void pdsc_reset_prepare(struct pci_dev *pdev)
|
|||
pdsc_auxbus_dev_del(pdsc, pdsc, &pdsc->padev);
|
||||
}
|
||||
|
||||
pdsc_unmap_bars(pdsc);
|
||||
if (!pdev->is_virtfn) {
|
||||
mutex_lock(&pdsc->devcmd_lock);
|
||||
pdsc_unmap_bars(pdsc);
|
||||
mutex_unlock(&pdsc->devcmd_lock);
|
||||
}
|
||||
pci_release_regions(pdev);
|
||||
if (pci_is_enabled(pdev))
|
||||
pci_disable_device(pdev);
|
||||
|
|
@ -543,7 +547,9 @@ static void pdsc_reset_done(struct pci_dev *pdev)
|
|||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&pdsc->devcmd_lock);
|
||||
err = pdsc_map_bars(pdsc);
|
||||
mutex_unlock(&pdsc->devcmd_lock);
|
||||
if (err)
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user