scsi: qla2xxx: Fix unbound NVME response length
authorArun Easi <aeasi@marvell.com>
Fri, 24 Jan 2020 04:50:14 +0000 (20:50 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 30 Jan 2020 15:31:47 +0000 (10:31 -0500)
On certain cases when response length is less than 32, NVME response data
is supplied inline in IOCB. This is indicated by some combination of state
flags. There was an instance when a high, and incorrect, response length
was indicated causing driver to overrun buffers. Fix this by checking and
limiting the response payload length.

Fixes: 7401bc18d1ee3 ("scsi: qla2xxx: Add FC-NVMe command handling")
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20200124045014.23554-1-hmadhani@marvell.com
Signed-off-by: Arun Easi <aeasi@marvell.com>
Signed-off-by: Himanshu Madhani <hmadhani@marvell.com>
Reviewed-by: Ewan D. Milne <emilne@redhat.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_dbg.h
drivers/scsi/qla2xxx/qla_isr.c

index e5500bba06ca06c45dffcd9d484cbc71c584229e..88a56e8480f7104783674eb77d10f873d368e629 100644 (file)
@@ -2519,12 +2519,6 @@ qla83xx_fw_dump_failed:
 /*                         Driver Debug Functions.                          */
 /****************************************************************************/
 
-static inline int
-ql_mask_match(uint level)
-{
-       return (level & ql2xextended_error_logging) == level;
-}
-
 /*
  * This function is for formatting and logging debug information.
  * It is to be used when vha is available. It formats the message
index bb01b680ce9fd7541d96a73622e300738f487c7a..433e955028086c0e5a3297bdd0b47ea015106967 100644 (file)
@@ -374,3 +374,9 @@ extern int qla24xx_dump_ram(struct qla_hw_data *, uint32_t, uint32_t *,
 extern void qla24xx_pause_risc(struct device_reg_24xx __iomem *,
        struct qla_hw_data *);
 extern int qla24xx_soft_reset(struct qla_hw_data *);
+
+static inline int
+ql_mask_match(uint level)
+{
+       return (level & ql2xextended_error_logging) == level;
+}
index e7bad0bfffda1c09446396bc1eab1d023f4c5c89..e40705d38cea72abec4388e8bc35226b1634eac7 100644 (file)
@@ -1939,6 +1939,18 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
                inbuf = (uint32_t *)&sts->nvme_ersp_data;
                outbuf = (uint32_t *)fd->rspaddr;
                iocb->u.nvme.rsp_pyld_len = le16_to_cpu(sts->nvme_rsp_pyld_len);
+               if (unlikely(iocb->u.nvme.rsp_pyld_len >
+                   sizeof(struct nvme_fc_ersp_iu))) {
+                       if (ql_mask_match(ql_dbg_io)) {
+                               WARN_ONCE(1, "Unexpected response payload length %u.\n",
+                                   iocb->u.nvme.rsp_pyld_len);
+                               ql_log(ql_log_warn, fcport->vha, 0x5100,
+                                   "Unexpected response payload length %u.\n",
+                                   iocb->u.nvme.rsp_pyld_len);
+                       }
+                       iocb->u.nvme.rsp_pyld_len =
+                           sizeof(struct nvme_fc_ersp_iu);
+               }
                iter = iocb->u.nvme.rsp_pyld_len >> 2;
                for (; iter; iter--)
                        *outbuf++ = swab32(*inbuf++);