From: Dick Kennedy Date: Tue, 30 Jun 2020 21:49:52 +0000 (-0700) Subject: scsi: lpfc: Fix oops due to overrun when reading SLI3 data X-Git-Tag: v5.9-rc1~116^2~251 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d91e3abb682b07b04ced3f3d363651abedcb0309;p=thirdparty%2Fkernel%2Flinux.git scsi: lpfc: Fix oops due to overrun when reading SLI3 data When using DUMP on SLI3 to read VPD and Port status data (config region 23), the adapter is overruning the kmalloc'd buffer causing havoc on other consumers of the allocation pools. Rework the loops processing the dump data and validate/size memory lengths before performing bcopy. Link: https://lore.kernel.org/r/20200630215001.70793-6-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 69a5249e007a3..287a78185dc77 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -253,13 +253,15 @@ lpfc_config_port_prep(struct lpfc_hba *phba) */ if (mb->un.varDmp.word_cnt == 0) break; - if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset) - mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset; + + i = mb->un.varDmp.word_cnt * sizeof(uint32_t); + if (offset + i > DMP_VPD_SIZE) + i = DMP_VPD_SIZE - offset; lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, - lpfc_vpd_data + offset, - mb->un.varDmp.word_cnt); - offset += mb->un.varDmp.word_cnt; - } while (mb->un.varDmp.word_cnt && offset < DMP_VPD_SIZE); + lpfc_vpd_data + offset, i); + offset += i; + } while (offset < DMP_VPD_SIZE); + lpfc_parse_vpd(phba, lpfc_vpd_data, offset); kfree(lpfc_vpd_data); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 1575fccc8b0ce..cefc3cbb69ae7 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -19326,7 +19326,7 @@ lpfc_sli_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) LPFC_MBOXQ_t *pmb = NULL; MAILBOX_t *mb; uint32_t offset = 0; - int rc; + int i, rc; if (!rgn23_data) return 0; @@ -19356,14 +19356,14 @@ lpfc_sli_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) */ if (mb->un.varDmp.word_cnt == 0) break; - if (mb->un.varDmp.word_cnt > DMP_RGN23_SIZE - offset) - mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset; + i = mb->un.varDmp.word_cnt * sizeof(uint32_t); + if (offset + i > DMP_RGN23_SIZE) + i = DMP_RGN23_SIZE - offset; lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, - rgn23_data + offset, - mb->un.varDmp.word_cnt); - offset += mb->un.varDmp.word_cnt; - } while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE); + rgn23_data + offset, i); + offset += i; + } while (offset < DMP_RGN23_SIZE); mempool_free(pmb, phba->mbox_mem_pool); return offset;