| From a1218b41c67c6352f0c7e08bf291d8caae07f335 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 18 Oct 2021 15:26:50 +0300 |
| Subject: scsi: qla2xxx: Fix unmap of already freed sgl |
| |
| From: Dmitry Bogdanov <d.bogdanov@yadro.com> |
| |
| [ Upstream commit 4a8f71014b4d56c4fb287607e844c0a9f68f46d9 ] |
| |
| The sgl is freed in the target stack in target_release_cmd_kref() before |
| calling qlt_free_cmd() but there is an unmap of sgl in qlt_free_cmd() that |
| causes a panic if sgl is not yet DMA unmapped: |
| |
| NIP dma_direct_unmap_sg+0xdc/0x180 |
| LR dma_direct_unmap_sg+0xc8/0x180 |
| Call Trace: |
| ql_dbg_prefix+0x68/0xc0 [qla2xxx] (unreliable) |
| dma_unmap_sg_attrs+0x54/0xf0 |
| qlt_unmap_sg.part.19+0x54/0x1c0 [qla2xxx] |
| qlt_free_cmd+0x124/0x1d0 [qla2xxx] |
| tcm_qla2xxx_release_cmd+0x4c/0xa0 [tcm_qla2xxx] |
| target_put_sess_cmd+0x198/0x370 [target_core_mod] |
| transport_generic_free_cmd+0x6c/0x1b0 [target_core_mod] |
| tcm_qla2xxx_complete_free+0x6c/0x90 [tcm_qla2xxx] |
| |
| The sgl may be left unmapped in error cases of response sending. For |
| instance, qlt_rdy_to_xfer() maps sgl and exits when session is being |
| deleted keeping the sgl mapped. |
| |
| This patch removes use-after-free of the sgl and ensures that the sgl is |
| unmapped for any command that was not sent to firmware. |
| |
| Link: https://lore.kernel.org/r/20211018122650.11846-1-d.bogdanov@yadro.com |
| Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> |
| Signed-off-by: Dmitry Bogdanov <d.bogdanov@yadro.com> |
| Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/scsi/qla2xxx/qla_target.c | 14 +++++--------- |
| 1 file changed, 5 insertions(+), 9 deletions(-) |
| |
| diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c |
| index 57068e2faef54..0111c543f0e64 100644 |
| --- a/drivers/scsi/qla2xxx/qla_target.c |
| +++ b/drivers/scsi/qla2xxx/qla_target.c |
| @@ -3251,8 +3251,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, |
| "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n", |
| vha->flags.online, qla2x00_reset_active(vha), |
| cmd->reset_count, qpair->chip_reset); |
| - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); |
| - return 0; |
| + goto out_unmap_unlock; |
| } |
| |
| /* Does F/W have an IOCBs for this request */ |
| @@ -3375,10 +3374,6 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) |
| prm.sg = NULL; |
| prm.req_cnt = 1; |
| |
| - /* Calculate number of entries and segments required */ |
| - if (qlt_pci_map_calc_cnt(&prm) != 0) |
| - return -EAGAIN; |
| - |
| if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) || |
| (cmd->sess && cmd->sess->deleted)) { |
| /* |
| @@ -3396,6 +3391,10 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) |
| return 0; |
| } |
| |
| + /* Calculate number of entries and segments required */ |
| + if (qlt_pci_map_calc_cnt(&prm) != 0) |
| + return -EAGAIN; |
| + |
| spin_lock_irqsave(qpair->qp_lock_ptr, flags); |
| /* Does F/W have an IOCBs for this request */ |
| res = qlt_check_reserve_free_req(qpair, prm.req_cnt); |
| @@ -3800,9 +3799,6 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) |
| |
| BUG_ON(cmd->cmd_in_wq); |
| |
| - if (cmd->sg_mapped) |
| - qlt_unmap_sg(cmd->vha, cmd); |
| - |
| if (!cmd->q_full) |
| qlt_decr_num_pend_cmds(cmd->vha); |
| |
| -- |
| 2.33.0 |
| |