scsi: lpfc: Fix oops due to overrun when reading SLI3 data
authorDick Kennedy <dick.kennedy@broadcom.com>
Tue, 30 Jun 2020 21:49:52 +0000 (14:49 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 3 Jul 2020 03:06:36 +0000 (23:06 -0400)
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 <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_sli.c

index 69a5249..287a781 100644 (file)
@@ -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);
index 1575fcc..cefc3cb 100644 (file)
@@ -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;