335584f
From: Paolo Bonzini <pbonzini@redhat.com>
335584f
Date: Thu, 1 Jun 2017 17:26:14 +0200
335584f
Subject: [PATCH] megasas: always store SCSIRequest* into MegasasCmd
335584f
335584f
This ensures that the request is unref'ed properly, and avoids a
335584f
segmentation fault in the new qtest testcase that is added.
335584f
This is CVE-2017-9503.
335584f
335584f
Reported-by: Zhangyanyu <zyy4013@stu.ouc.edu.cn>
335584f
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
335584f
(cherry picked from commit 87e459a810d7b1ec1638085b5a80ea3d9b43119a)
335584f
---
335584f
 hw/scsi/megasas.c | 31 ++++++++++++++++---------------
335584f
 1 file changed, 16 insertions(+), 15 deletions(-)
335584f
335584f
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
335584f
index 135662df31..734fdaef90 100644
335584f
--- a/hw/scsi/megasas.c
335584f
+++ b/hw/scsi/megasas.c
335584f
@@ -609,6 +609,9 @@ static void megasas_reset_frames(MegasasState *s)
335584f
 static void megasas_abort_command(MegasasCmd *cmd)
335584f
 {
335584f
     /* Never abort internal commands.  */
335584f
+    if (cmd->dcmd_opcode != -1) {
335584f
+        return;
335584f
+    }
335584f
     if (cmd->req != NULL) {
335584f
         scsi_req_cancel(cmd->req);
335584f
     }
335584f
@@ -1017,7 +1020,6 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
335584f
     uint64_t pd_size;
335584f
     uint16_t pd_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
335584f
     uint8_t cmdbuf[6];
335584f
-    SCSIRequest *req;
335584f
     size_t len, resid;
335584f
 
335584f
     if (!cmd->iov_buf) {
335584f
@@ -1026,8 +1028,8 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
335584f
         info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */
335584f
         info->vpd_page83[0] = 0x7f;
335584f
         megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data));
335584f
-        req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
335584f
-        if (!req) {
335584f
+        cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
335584f
+        if (!cmd->req) {
335584f
             trace_megasas_dcmd_req_alloc_failed(cmd->index,
335584f
                                                 "PD get info std inquiry");
335584f
             g_free(cmd->iov_buf);
335584f
@@ -1036,26 +1038,26 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
335584f
         }
335584f
         trace_megasas_dcmd_internal_submit(cmd->index,
335584f
                                            "PD get info std inquiry", lun);
335584f
-        len = scsi_req_enqueue(req);
335584f
+        len = scsi_req_enqueue(cmd->req);
335584f
         if (len > 0) {
335584f
             cmd->iov_size = len;
335584f
-            scsi_req_continue(req);
335584f
+            scsi_req_continue(cmd->req);
335584f
         }
335584f
         return MFI_STAT_INVALID_STATUS;
335584f
     } else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) {
335584f
         megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83));
335584f
-        req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
335584f
-        if (!req) {
335584f
+        cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
335584f
+        if (!cmd->req) {
335584f
             trace_megasas_dcmd_req_alloc_failed(cmd->index,
335584f
                                                 "PD get info vpd inquiry");
335584f
             return MFI_STAT_FLASH_ALLOC_FAIL;
335584f
         }
335584f
         trace_megasas_dcmd_internal_submit(cmd->index,
335584f
                                            "PD get info vpd inquiry", lun);
335584f
-        len = scsi_req_enqueue(req);
335584f
+        len = scsi_req_enqueue(cmd->req);
335584f
         if (len > 0) {
335584f
             cmd->iov_size = len;
335584f
-            scsi_req_continue(req);
335584f
+            scsi_req_continue(cmd->req);
335584f
         }
335584f
         return MFI_STAT_INVALID_STATUS;
335584f
     }
335584f
@@ -1217,7 +1219,6 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
335584f
     struct mfi_ld_info *info = cmd->iov_buf;
335584f
     size_t dcmd_size = sizeof(struct mfi_ld_info);
335584f
     uint8_t cdb[6];
335584f
-    SCSIRequest *req;
335584f
     ssize_t len, resid;
335584f
     uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
335584f
     uint64_t ld_size;
335584f
@@ -1226,8 +1227,8 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
335584f
         cmd->iov_buf = g_malloc0(dcmd_size);
335584f
         info = cmd->iov_buf;
335584f
         megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83));
335584f
-        req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
335584f
-        if (!req) {
335584f
+        cmd->req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
335584f
+        if (!cmd->req) {
335584f
             trace_megasas_dcmd_req_alloc_failed(cmd->index,
335584f
                                                 "LD get info vpd inquiry");
335584f
             g_free(cmd->iov_buf);
335584f
@@ -1236,10 +1237,10 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
335584f
         }
335584f
         trace_megasas_dcmd_internal_submit(cmd->index,
335584f
                                            "LD get info vpd inquiry", lun);
335584f
-        len = scsi_req_enqueue(req);
335584f
+        len = scsi_req_enqueue(cmd->req);
335584f
         if (len > 0) {
335584f
             cmd->iov_size = len;
335584f
-            scsi_req_continue(req);
335584f
+            scsi_req_continue(cmd->req);
335584f
         }
335584f
         return MFI_STAT_INVALID_STATUS;
335584f
     }
335584f
@@ -1851,7 +1852,7 @@ static void megasas_command_complete(SCSIRequest *req, uint32_t status,
335584f
         return;
335584f
     }
335584f
 
335584f
-    if (cmd->req == NULL) {
335584f
+    if (cmd->dcmd_opcode != -1) {
335584f
         /*
335584f
          * Internal command complete
335584f
          */