Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5ff0eed authored by Joe Carnuccio's avatar Joe Carnuccio Committed by Martin K. Petersen
Browse files

scsi: qla2xxx: Fix crash due to NULL pointer dereference of ctx



Fixes following signature in the stack trace:

BUG: unable to handle kernel NULL pointer dereference at 0000000000000374
IP: [<ffffffffa06ec8eb>] qla2x00_sp_free_dma+0xeb/0x2a0 [qla2xxx]

Cc: <stable@vger.kernel.org> # v4.10+
Signed-off-by: default avatarJoe Carnuccio <joe.carnuccio@cavium.com>
Signed-off-by: default avatarHimanshu Madhani <himanshu.madhani@cavium.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 74939a0b
Loading
Loading
Loading
Loading
+7 −19
Original line number Diff line number Diff line
@@ -129,28 +129,16 @@ qla2x00_clear_loop_id(fc_port_t *fcport) {
}

static inline void
qla2x00_clean_dsd_pool(struct qla_hw_data *ha, srb_t *sp,
	struct qla_tgt_cmd *tc)
qla2x00_clean_dsd_pool(struct qla_hw_data *ha, struct crc_context *ctx)
{
	struct dsd_dma *dsd_ptr, *tdsd_ptr;
	struct crc_context *ctx;

	if (sp)
		ctx = (struct crc_context *)GET_CMD_CTX_SP(sp);
	else if (tc)
		ctx = (struct crc_context *)tc->ctx;
	else {
		BUG();
		return;
	}
	struct dsd_dma *dsd, *tdsd;

	/* clean up allocated prev pool */
	list_for_each_entry_safe(dsd_ptr, tdsd_ptr,
	    &ctx->dsd_list, list) {
		dma_pool_free(ha->dl_dma_pool, dsd_ptr->dsd_addr,
		    dsd_ptr->dsd_list_dma);
		list_del(&dsd_ptr->list);
		kfree(dsd_ptr);
	list_for_each_entry_safe(dsd, tdsd, &ctx->dsd_list, list) {
		dma_pool_free(ha->dl_dma_pool, dsd->dsd_addr,
		    dsd->dsd_list_dma);
		list_del(&dsd->list);
		kfree(dsd);
	}
	INIT_LIST_HEAD(&ctx->dsd_list);
}
+19 −11
Original line number Diff line number Diff line
@@ -630,20 +630,24 @@ qla2x00_sp_free_dma(void *ptr)
		sp->flags &= ~SRB_CRC_PROT_DMA_VALID;
	}

	if (!ctx)
		goto end;

	if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
		/* List assured to be having elements */
		qla2x00_clean_dsd_pool(ha, sp, NULL);
		qla2x00_clean_dsd_pool(ha, ctx);
		sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
	}

	if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
		dma_pool_free(ha->dl_dma_pool, ctx,
		    ((struct crc_context *)ctx)->crc_ctx_dma);
		struct crc_context *ctx0 = ctx;

		dma_pool_free(ha->dl_dma_pool, ctx0, ctx0->crc_ctx_dma);
		sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
	}

	if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
		struct ct6_dsd *ctx1 = (struct ct6_dsd *)ctx;
		struct ct6_dsd *ctx1 = ctx;

		dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
		    ctx1->fcp_cmnd_dma);
@@ -653,6 +657,7 @@ qla2x00_sp_free_dma(void *ptr)
		mempool_free(ctx1, ha->ctx_mempool);
	}

end:
	CMD_SP(cmd) = NULL;
	qla2x00_rel_sp(sp);
}
@@ -699,21 +704,24 @@ qla2xxx_qpair_sp_free_dma(void *ptr)
		sp->flags &= ~SRB_CRC_PROT_DMA_VALID;
	}

	if (!ctx)
		goto end;

	if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
		/* List assured to be having elements */
		qla2x00_clean_dsd_pool(ha, sp, NULL);
		qla2x00_clean_dsd_pool(ha, ctx);
		sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
	}

	if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
		dma_pool_free(ha->dl_dma_pool, ctx,
		    ((struct crc_context *)ctx)->crc_ctx_dma);
		struct crc_context *ctx0 = ctx;

		dma_pool_free(ha->dl_dma_pool, ctx, ctx0->crc_ctx_dma);
		sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
	}

	if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
		struct ct6_dsd *ctx1 = (struct ct6_dsd *)ctx;

		struct ct6_dsd *ctx1 = ctx;
		dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
		    ctx1->fcp_cmnd_dma);
		list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list);
@@ -721,7 +729,7 @@ qla2xxx_qpair_sp_free_dma(void *ptr)
		ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
		mempool_free(ctx1, ha->ctx_mempool);
	}

end:
	CMD_SP(cmd) = NULL;
	qla2xxx_rel_qpair_sp(sp->qpair, sp);
}
+5 −3
Original line number Diff line number Diff line
@@ -2245,10 +2245,12 @@ static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
		pci_unmap_sg(ha->pdev, cmd->prot_sg, cmd->prot_sg_cnt,
			cmd->dma_data_direction);

	if (!cmd->ctx)
		return;

	if (cmd->ctx_dsd_alloced)
		qla2x00_clean_dsd_pool(ha, NULL, cmd);
		qla2x00_clean_dsd_pool(ha, cmd->ctx);

	if (cmd->ctx)
	dma_pool_free(ha->dl_dma_pool, cmd->ctx, cmd->ctx->crc_ctx_dma);
}