diff mbox series

[RESEND] scsi: qla2xxx: fix unmap already freed sgl

Message ID 20211018122650.11846-1-d.bogdanov@yadro.com (mailing list archive)
State Accepted
Commit 4a8f71014b4d56c4fb287607e844c0a9f68f46d9
Headers show
Series [RESEND] scsi: qla2xxx: fix unmap already freed sgl | expand

Commit Message

Dmitry Bogdanov Oct. 18, 2021, 12:26 p.m. UTC
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 such 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]

SGL may be left unmapped in error cases of response sending.
For instance, qlt_rdy_to_xfer maps sgl and exits when sesssion is being
deleted keeping sgl mapped.

This patch removes use-after-free of sgl, and ensures that sgl is
unmapped for the cmd that was not send to FW.

Signed-off-by: Dmitry Bogdanov <d.bogdanov@yadro.com>
---
This patchset is intended for scsi-fix.
---
 drivers/scsi/qla2xxx/qla_target.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

Comments

Himanshu Madhani Oct. 18, 2021, 2:26 p.m. UTC | #1
> On Oct 18, 2021, at 7:26 AM, Dmitry Bogdanov <d.bogdanov@yadro.com> wrote:
> 
> 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 such 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]
> 
> SGL may be left unmapped in error cases of response sending.
> For instance, qlt_rdy_to_xfer maps sgl and exits when sesssion is being
> deleted keeping sgl mapped.
> 
> This patch removes use-after-free of sgl, and ensures that sgl is
> unmapped for the cmd that was not send to FW.
> 
> Signed-off-by: Dmitry Bogdanov <d.bogdanov@yadro.com>
> ---
> This patchset is intended for scsi-fix.
> ---
> 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 b3478ed9b12e..7d8242c120fc 100644
> --- a/drivers/scsi/qla2xxx/qla_target.c
> +++ b/drivers/scsi/qla2xxx/qla_target.c
> @@ -3319,8 +3319,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 */
> @@ -3445,10 +3444,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)) {
> 		/*
> @@ -3466,6 +3461,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);
> @@ -3870,9 +3869,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.25.1
> 

Looks Good.

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>

--
Himanshu Madhani	 Oracle Linux Engineering
Martin K. Petersen Oct. 19, 2021, 3:43 a.m. UTC | #2
On Mon, 18 Oct 2021 15:26:50 +0300, Dmitry Bogdanov wrote:

> 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 such 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]
> 
> [...]

Applied to 5.15/scsi-fixes, thanks!

[1/1] scsi: qla2xxx: fix unmap already freed sgl
      https://git.kernel.org/mkp/scsi/c/4a8f71014b4d
diff mbox series

Patch

diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index b3478ed9b12e..7d8242c120fc 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -3319,8 +3319,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 */
@@ -3445,10 +3444,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)) {
 		/*
@@ -3466,6 +3461,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);
@@ -3870,9 +3869,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);