scsi: lpfc: Fix bad memory access during VPD DUMP mailbox command
authorJames Smart <jsmart2021@gmail.com>
Wed, 21 Apr 2021 23:45:11 +0000 (16:45 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 27 Apr 2021 02:58:38 +0000 (22:58 -0400)
The dump command for reading a region passes a requested read length
specified in words (4-byte units). The response overwrites the same field
with the actual number of bytes read.

The mailbox handler for DUMP which reads VPD data (region 23) is treating
the response field as if it were still a word_cnt, thus multiplying it by 4
to set the read's "length". Given the read value was calculated based on
the size of the read buffer, the longer response length runs off the end of
the buffer.

Fix by reworking the code to use the response field as a byte count.

Link: https://lore.kernel.org/r/20210421234511.102206-1-jsmart2021@gmail.com
Co-developed-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: Justin Tee <justin.tee@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 1e4c792..5f018d0 100644 (file)
@@ -254,13 +254,13 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
                if (mb->un.varDmp.word_cnt == 0)
                        break;
 
-               i =  mb->un.varDmp.word_cnt * sizeof(uint32_t);
-               if (offset + i >  DMP_VPD_SIZE)
-                       i =  DMP_VPD_SIZE - offset;
+               if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset)
+                       mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset;
                lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
-                                     lpfc_vpd_data  + offset, i);
-               offset += i;
-       } while (offset < DMP_VPD_SIZE);
+                                     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_parse_vpd(phba, lpfc_vpd_data, offset);
 
index 579ac75..573c859 100644 (file)
@@ -19777,7 +19777,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 i, rc;
+       int rc;
 
        if (!rgn23_data)
                return 0;
@@ -19808,13 +19808,14 @@ lpfc_sli_get_config_region23(struct lpfc_hba *phba, char *rgn23_data)
                if (mb->un.varDmp.word_cnt == 0)
                        break;
 
-               i =  mb->un.varDmp.word_cnt * sizeof(uint32_t);
-               if (offset + i >  DMP_RGN23_SIZE)
-                       i =  DMP_RGN23_SIZE - offset;
+               if (mb->un.varDmp.word_cnt > DMP_RGN23_SIZE - offset)
+                       mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset;
+
                lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
-                                     rgn23_data  + offset, i);
-               offset += i;
-       } while (offset < DMP_RGN23_SIZE);
+                                      rgn23_data + offset,
+                                      mb->un.varDmp.word_cnt);
+               offset += mb->un.varDmp.word_cnt;
+       } while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE);
 
        mempool_free(pmb, phba->mbox_mem_pool);
        return offset;