Daniel Wagner 192cba
From: James Smart <jsmart2021@gmail.com>
Daniel Wagner 192cba
Date: Wed, 21 Apr 2021 16:45:11 -0700
Daniel Wagner 192cba
Subject: scsi: lpfc: Fix bad memory access during VPD DUMP mailbox command
Daniel Wagner 192cba
Patch-mainline: v5.13-rc1
Daniel Wagner 192cba
Git-commit: e4ec10228fdf09b88ba018009f14a696fb50d3f2
Daniel Wagner 192cba
References: bsc#1186451
Daniel Wagner 192cba
Daniel Wagner 192cba
The dump command for reading a region passes a requested read length
Daniel Wagner 192cba
specified in words (4-byte units). The response overwrites the same field
Daniel Wagner 192cba
with the actual number of bytes read.
Daniel Wagner 192cba
Daniel Wagner 192cba
The mailbox handler for DUMP which reads VPD data (region 23) is treating
Daniel Wagner 192cba
the response field as if it were still a word_cnt, thus multiplying it by 4
Daniel Wagner 192cba
to set the read's "length". Given the read value was calculated based on
Daniel Wagner 192cba
the size of the read buffer, the longer response length runs off the end of
Daniel Wagner 192cba
the buffer.
Daniel Wagner 192cba
Daniel Wagner 192cba
Fix by reworking the code to use the response field as a byte count.
Daniel Wagner 192cba
Daniel Wagner 192cba
Link: https://lore.kernel.org/r/20210421234511.102206-1-jsmart2021@gmail.com
Daniel Wagner 192cba
Co-developed-by: Justin Tee <justin.tee@broadcom.com>
Daniel Wagner 192cba
Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Daniel Wagner 192cba
Signed-off-by: James Smart <jsmart2021@gmail.com>
Daniel Wagner 192cba
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Daniel Wagner 192cba
Acked-by: Daniel Wagner <dwagner@suse.de>
Daniel Wagner 192cba
---
Daniel Wagner 192cba
 drivers/scsi/lpfc/lpfc_init.c |   12 ++++++------
Daniel Wagner 192cba
 drivers/scsi/lpfc/lpfc_sli.c  |   15 ++++++++-------
Daniel Wagner 192cba
 2 files changed, 14 insertions(+), 13 deletions(-)
Daniel Wagner 192cba
Daniel Wagner 192cba
--- a/drivers/scsi/lpfc/lpfc_init.c
Daniel Wagner 192cba
+++ b/drivers/scsi/lpfc/lpfc_init.c
Daniel Wagner 192cba
@@ -254,13 +254,13 @@ lpfc_config_port_prep(struct lpfc_hba *p
Daniel Wagner 192cba
 		if (mb->un.varDmp.word_cnt == 0)
Daniel Wagner 192cba
 			break;
Daniel Wagner 192cba
 
Daniel Wagner 192cba
-		i =  mb->un.varDmp.word_cnt * sizeof(uint32_t);
Daniel Wagner 192cba
-		if (offset + i >  DMP_VPD_SIZE)
Daniel Wagner 192cba
-			i =  DMP_VPD_SIZE - offset;
Daniel Wagner 192cba
+		if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset)
Daniel Wagner 192cba
+			mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset;
Daniel Wagner 192cba
 		lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
Daniel Wagner 192cba
-				      lpfc_vpd_data  + offset, i);
Daniel Wagner 192cba
-		offset += i;
Daniel Wagner 192cba
-	} while (offset < DMP_VPD_SIZE);
Daniel Wagner 192cba
+				      lpfc_vpd_data + offset,
Daniel Wagner 192cba
+				      mb->un.varDmp.word_cnt);
Daniel Wagner 192cba
+		offset += mb->un.varDmp.word_cnt;
Daniel Wagner 192cba
+	} while (mb->un.varDmp.word_cnt && offset < DMP_VPD_SIZE);
Daniel Wagner 192cba
 
Daniel Wagner 192cba
 	lpfc_parse_vpd(phba, lpfc_vpd_data, offset);
Daniel Wagner 192cba
 
Daniel Wagner 192cba
--- a/drivers/scsi/lpfc/lpfc_sli.c
Daniel Wagner 192cba
+++ b/drivers/scsi/lpfc/lpfc_sli.c
Daniel Wagner 192cba
@@ -19777,7 +19777,7 @@ lpfc_sli_get_config_region23(struct lpfc
Daniel Wagner 192cba
 	LPFC_MBOXQ_t *pmb = NULL;
Daniel Wagner 192cba
 	MAILBOX_t *mb;
Daniel Wagner 192cba
 	uint32_t offset = 0;
Daniel Wagner 192cba
-	int i, rc;
Daniel Wagner 192cba
+	int rc;
Daniel Wagner 192cba
 
Daniel Wagner 192cba
 	if (!rgn23_data)
Daniel Wagner 192cba
 		return 0;
Daniel Wagner 192cba
@@ -19808,13 +19808,14 @@ lpfc_sli_get_config_region23(struct lpfc
Daniel Wagner 192cba
 		if (mb->un.varDmp.word_cnt == 0)
Daniel Wagner 192cba
 			break;
Daniel Wagner 192cba
 
Daniel Wagner 192cba
-		i =  mb->un.varDmp.word_cnt * sizeof(uint32_t);
Daniel Wagner 192cba
-		if (offset + i >  DMP_RGN23_SIZE)
Daniel Wagner 192cba
-			i =  DMP_RGN23_SIZE - offset;
Daniel Wagner 192cba
+		if (mb->un.varDmp.word_cnt > DMP_RGN23_SIZE - offset)
Daniel Wagner 192cba
+			mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset;
Daniel Wagner 192cba
+
Daniel Wagner 192cba
 		lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
Daniel Wagner 192cba
-				      rgn23_data  + offset, i);
Daniel Wagner 192cba
-		offset += i;
Daniel Wagner 192cba
-	} while (offset < DMP_RGN23_SIZE);
Daniel Wagner 192cba
+				       rgn23_data + offset,
Daniel Wagner 192cba
+				       mb->un.varDmp.word_cnt);
Daniel Wagner 192cba
+		offset += mb->un.varDmp.word_cnt;
Daniel Wagner 192cba
+	} while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE);
Daniel Wagner 192cba
 
Daniel Wagner 192cba
 	mempool_free(pmb, phba->mbox_mem_pool);
Daniel Wagner 192cba
 	return offset;