| From c2d04e7c2ab652c707917a7447bd62f3b0897640 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 6 Nov 2025 10:38:20 -0600 |
| Subject: scsi: smartpqi: Fix device resources accessed after device removal |
| |
| From: Mike McGowen <mike.mcgowen@microchip.com> |
| |
| [ Upstream commit b518e86d1a70a88f6592a7c396cf1b93493d1aab ] |
| |
| Correct possible race conditions during device removal. |
| |
| Previously, a scheduled work item to reset a LUN could still execute |
| after the device was removed, leading to use-after-free and other |
| resource access issues. |
| |
| This race condition occurs because the abort handler may schedule a LUN |
| reset concurrently with device removal via sdev_destroy(), leading to |
| use-after-free and improper access to freed resources. |
| |
| - Check in the device reset handler if the device is still present in |
| the controller's SCSI device list before running; if not, the reset |
| is skipped. |
| |
| - Cancel any pending TMF work that has not started in sdev_destroy(). |
| |
| - Ensure device freeing in sdev_destroy() is done while holding the |
| LUN reset mutex to avoid races with ongoing resets. |
| |
| Fixes: 2d80f4054f7f ("scsi: smartpqi: Update deleting a LUN via sysfs") |
| Reviewed-by: Scott Teel <scott.teel@microchip.com> |
| Reviewed-by: Scott Benesh <scott.benesh@microchip.com> |
| Signed-off-by: Mike McGowen <mike.mcgowen@microchip.com> |
| Signed-off-by: Don Brace <don.brace@microchip.com> |
| Link: https://patch.msgid.link/20251106163823.786828-3-don.brace@microchip.com |
| Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/scsi/smartpqi/smartpqi_init.c | 19 +++++++++++++++++++ |
| 1 file changed, 19 insertions(+) |
| |
| diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c |
| index 5e39df2b6a4c0..a9f504959dd56 100644 |
| --- a/drivers/scsi/smartpqi/smartpqi_init.c |
| +++ b/drivers/scsi/smartpqi/smartpqi_init.c |
| @@ -6401,10 +6401,22 @@ static int pqi_device_reset(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev |
| |
| static int pqi_device_reset_handler(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device, u8 lun, struct scsi_cmnd *scmd, u8 scsi_opcode) |
| { |
| + unsigned long flags; |
| int rc; |
| |
| mutex_lock(&ctrl_info->lun_reset_mutex); |
| |
| + spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); |
| + if (pqi_find_scsi_dev(ctrl_info, device->bus, device->target, device->lun) == NULL) { |
| + dev_warn(&ctrl_info->pci_dev->dev, |
| + "skipping reset of scsi %d:%d:%d:%u, device has been removed\n", |
| + ctrl_info->scsi_host->host_no, device->bus, device->target, device->lun); |
| + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); |
| + mutex_unlock(&ctrl_info->lun_reset_mutex); |
| + return 0; |
| + } |
| + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); |
| + |
| dev_err(&ctrl_info->pci_dev->dev, |
| "resetting scsi %d:%d:%d:%d due to cmd 0x%02x\n", |
| ctrl_info->scsi_host->host_no, |
| @@ -6583,7 +6595,9 @@ static void pqi_slave_destroy(struct scsi_device *sdev) |
| { |
| struct pqi_ctrl_info *ctrl_info; |
| struct pqi_scsi_dev *device; |
| + struct pqi_tmf_work *tmf_work; |
| int mutex_acquired; |
| + unsigned int lun; |
| unsigned long flags; |
| |
| ctrl_info = shost_to_hba(sdev->host); |
| @@ -6610,8 +6624,13 @@ static void pqi_slave_destroy(struct scsi_device *sdev) |
| |
| mutex_unlock(&ctrl_info->scan_mutex); |
| |
| + for (lun = 0, tmf_work = device->tmf_work; lun < PQI_MAX_LUNS_PER_DEVICE; lun++, tmf_work++) |
| + cancel_work_sync(&tmf_work->work_struct); |
| + |
| + mutex_lock(&ctrl_info->lun_reset_mutex); |
| pqi_dev_info(ctrl_info, "removed", device); |
| pqi_free_device(device); |
| + mutex_unlock(&ctrl_info->lun_reset_mutex); |
| } |
| |
| static int pqi_getpciinfo_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg) |
| -- |
| 2.51.0 |
| |