From: Bart Van Assche <bvanassche@acm.org>
Date: Wed, 17 Apr 2019 14:44:25 -0700
Subject: scsi: qla2xxx: Fix use-after-free issues in
qla2xxx_qpair_sp_free_dma()
Patch-mainline: v5.2-rc1
Git-commit: d8f945bf8096375f458683b5718722a2d5dda2f0
References: bsc#1082635 bsc#1123034 bsc#1131304 bsc#1127988 bsc#1141340 bsc#1143706
The current order for freeing memory is as follows:
- struct crc_context itself.
- struct crc_context member pointers.
Change the freeing order into the following:
- struct crc_context member pointers.
- struct crc_context itself.
Detected by Coverity.
Cc: Himanshu Madhani <hmadhani@marvell.com>
Cc: Giridhar Malavali <gmalavali@marvell.com>
Fixes: 50b812755e97 ("scsi: qla2xxx: Fix DMA error when the DIF sg buffer crosses 4GB boundary") # v5.1-rc1.
Fixes: d74595278f4a ("scsi: qla2xxx: Add multiple queue pair functionality.") # v4.10.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Acked-by: Himanshu Madhani <hmadhani@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Acked-by: Daniel Wagner <dwagner@suse.de>
---
drivers/scsi/qla2xxx/qla_os.c | 38 ++++++++++++++++++++------------------
1 file changed, 20 insertions(+), 18 deletions(-)
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -783,25 +783,8 @@ qla2xxx_qpair_sp_free_dma(void *ptr)
sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
}
- if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
- 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 = 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);
- ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt;
- ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
- mempool_free(ctx1, ha->ctx_mempool);
- sp->flags &= ~SRB_FCP_CMND_DMA_VALID;
- }
if (sp->flags & SRB_DIF_BUNDL_DMA_VALID) {
- struct crc_context *difctx = sp->u.scmd.ctx;
+ struct crc_context *difctx = ctx;
struct dsd_dma *dif_dsd, *nxt_dsd;
list_for_each_entry_safe(dif_dsd, nxt_dsd,
@@ -835,6 +818,25 @@ qla2xxx_qpair_sp_free_dma(void *ptr)
}
sp->flags &= ~SRB_DIF_BUNDL_DMA_VALID;
}
+
+ if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
+ 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);
+ ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt;
+ ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
+ mempool_free(ctx1, ha->ctx_mempool);
+ sp->flags &= ~SRB_FCP_CMND_DMA_VALID;
+ }
+
+ if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
+ struct crc_context *ctx0 = ctx;
+
+ dma_pool_free(ha->dl_dma_pool, ctx, ctx0->crc_ctx_dma);
+ sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
+ }
}
void