yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone

Blame SOURCES/kvm-scsi-Allocate-SCSITargetReq-r-buf-dynamically-CVE-20.patch

9ae3a8
From 3f4a2e18f357a82186ce02018e42a24b5db4154d Mon Sep 17 00:00:00 2001
9ae3a8
From: Asias He <asias@redhat.com>
9ae3a8
Date: Fri, 11 Oct 2013 10:36:39 +0800
9ae3a8
Subject: [PATCH] scsi: Allocate SCSITargetReq r->buf dynamically [CVE-2013-4344]
9ae3a8
9ae3a8
BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1007334
9ae3a8
Brew: https://brewweb.devel.redhat.com/taskinfo?taskID=6402920
9ae3a8
RH-Author: Asias He <asias@redhat.com>
9ae3a8
Message-id: <1381458999-8048-1-git-send-email-asias@redhat.com>
9ae3a8
O-Subject: [RHEL7.0 qemu-kvm EMBARGOED PATCH v2] scsi: Allocate	SCSITargetReq r->buf dynamically [CVE-2013-4344]
9ae3a8
Bugzilla: 1007334
9ae3a8
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
9ae3a8
r->buf is hardcoded to 2056 which is (256 + 1) * 8, allowing 256 luns at
9ae3a8
most. If more than 256 luns are specified by user, we have buffer
9ae3a8
overflow in scsi_target_emulate_report_luns.
9ae3a8
9ae3a8
To fix, we allocate the buffer dynamically.
9ae3a8
9ae3a8
Signed-off-by: Asias He <asias@redhat.com>
9ae3a8
Tested-by: Michael Roth <mdroth@linux.vnet.ibm.com>
9ae3a8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
(cherry picked from commit 846424350b292f16b732b573273a5c1f195cd7a3)
9ae3a8
---
9ae3a8
 hw/scsi/scsi-bus.c     |   45 ++++++++++++++++++++++++++++++++++-----------
9ae3a8
 include/hw/scsi/scsi.h |    2 ++
9ae3a8
 2 files changed, 36 insertions(+), 11 deletions(-)
9ae3a8
9ae3a8
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
9ae3a8
index 18a0399..9082ea7 100644
9ae3a8
--- a/hw/scsi/scsi-bus.c
9ae3a8
+++ b/hw/scsi/scsi-bus.c
9ae3a8
@@ -11,6 +11,8 @@ static char *scsibus_get_dev_path(DeviceState *dev);
9ae3a8
 static char *scsibus_get_fw_dev_path(DeviceState *dev);
9ae3a8
 static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
9ae3a8
 static void scsi_req_dequeue(SCSIRequest *req);
9ae3a8
+static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len);
9ae3a8
+static void scsi_target_free_buf(SCSIRequest *req);
9ae3a8
 
9ae3a8
 static Property scsi_props[] = {
9ae3a8
     DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
9ae3a8
@@ -309,7 +311,8 @@ typedef struct SCSITargetReq SCSITargetReq;
9ae3a8
 struct SCSITargetReq {
9ae3a8
     SCSIRequest req;
9ae3a8
     int len;
9ae3a8
-    uint8_t buf[2056];
9ae3a8
+    uint8_t *buf;
9ae3a8
+    int buf_len;
9ae3a8
 };
9ae3a8
 
9ae3a8
 static void store_lun(uint8_t *outbuf, int lun)
9ae3a8
@@ -353,14 +356,12 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
9ae3a8
     if (!found_lun0) {
9ae3a8
         n += 8;
9ae3a8
     }
9ae3a8
-    len = MIN(n + 8, r->req.cmd.xfer & ~7);
9ae3a8
-    if (len > sizeof(r->buf)) {
9ae3a8
-        /* TODO: > 256 LUNs? */
9ae3a8
-        return false;
9ae3a8
-    }
9ae3a8
 
9ae3a8
+    scsi_target_alloc_buf(&r->req, n + 8);
9ae3a8
+
9ae3a8
+    len = MIN(n + 8, r->req.cmd.xfer & ~7);
9ae3a8
     memset(r->buf, 0, len);
9ae3a8
-    stl_be_p(&r->buf, n);
9ae3a8
+    stl_be_p(&r->buf[0], n);
9ae3a8
     i = found_lun0 ? 8 : 16;
9ae3a8
     QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
9ae3a8
         DeviceState *qdev = kid->child;
9ae3a8
@@ -379,6 +380,9 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
9ae3a8
 static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
9ae3a8
 {
9ae3a8
     assert(r->req.dev->lun != r->req.lun);
9ae3a8
+
9ae3a8
+    scsi_target_alloc_buf(&r->req, SCSI_INQUIRY_LEN);
9ae3a8
+
9ae3a8
     if (r->req.cmd.buf[1] & 0x2) {
9ae3a8
         /* Command support data - optional, not implemented */
9ae3a8
         return false;
9ae3a8
@@ -403,7 +407,7 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
9ae3a8
             return false;
9ae3a8
         }
9ae3a8
         /* done with EVPD */
9ae3a8
-        assert(r->len < sizeof(r->buf));
9ae3a8
+        assert(r->len < r->buf_len);
9ae3a8
         r->len = MIN(r->req.cmd.xfer, r->len);
9ae3a8
         return true;
9ae3a8
     }
9ae3a8
@@ -414,7 +418,7 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
9ae3a8
     }
9ae3a8
 
9ae3a8
     /* PAGE CODE == 0 */
9ae3a8
-    r->len = MIN(r->req.cmd.xfer, 36);
9ae3a8
+    r->len = MIN(r->req.cmd.xfer, SCSI_INQUIRY_LEN);
9ae3a8
     memset(r->buf, 0, r->len);
9ae3a8
     if (r->req.lun != 0) {
9ae3a8
         r->buf[0] = TYPE_NO_LUN;
9ae3a8
@@ -447,8 +451,9 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
9ae3a8
         }
9ae3a8
         break;
9ae3a8
     case REQUEST_SENSE:
9ae3a8
+        scsi_target_alloc_buf(&r->req, SCSI_SENSE_LEN);
9ae3a8
         r->len = scsi_device_get_sense(r->req.dev, r->buf,
9ae3a8
-                                       MIN(req->cmd.xfer, sizeof r->buf),
9ae3a8
+                                       MIN(req->cmd.xfer, r->buf_len),
9ae3a8
                                        (req->cmd.buf[1] & 1) == 0);
9ae3a8
         if (r->req.dev->sense_is_ua) {
9ae3a8
             scsi_device_unit_attention_reported(req->dev);
9ae3a8
@@ -493,11 +498,29 @@ static uint8_t *scsi_target_get_buf(SCSIRequest *req)
9ae3a8
     return r->buf;
9ae3a8
 }
9ae3a8
 
9ae3a8
+static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len)
9ae3a8
+{
9ae3a8
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
9ae3a8
+
9ae3a8
+    r->buf = g_malloc(len);
9ae3a8
+    r->buf_len = len;
9ae3a8
+
9ae3a8
+    return r->buf;
9ae3a8
+}
9ae3a8
+
9ae3a8
+static void scsi_target_free_buf(SCSIRequest *req)
9ae3a8
+{
9ae3a8
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
9ae3a8
+
9ae3a8
+    g_free(r->buf);
9ae3a8
+}
9ae3a8
+
9ae3a8
 static const struct SCSIReqOps reqops_target_command = {
9ae3a8
     .size         = sizeof(SCSITargetReq),
9ae3a8
     .send_command = scsi_target_send_command,
9ae3a8
     .read_data    = scsi_target_read_data,
9ae3a8
     .get_buf      = scsi_target_get_buf,
9ae3a8
+    .free_req     = scsi_target_free_buf,
9ae3a8
 };
9ae3a8
 
9ae3a8
 
9ae3a8
@@ -1353,7 +1376,7 @@ int scsi_build_sense(uint8_t *in_buf, int in_len,
9ae3a8
         buf[7] = 10;
9ae3a8
         buf[12] = sense.asc;
9ae3a8
         buf[13] = sense.ascq;
9ae3a8
-        return MIN(len, 18);
9ae3a8
+        return MIN(len, SCSI_SENSE_LEN);
9ae3a8
     } else {
9ae3a8
         /* Return descriptor format sense buffer */
9ae3a8
         buf[0] = 0x72;
9ae3a8
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
9ae3a8
index 9786e00..2eccb72 100644
9ae3a8
--- a/include/hw/scsi/scsi.h
9ae3a8
+++ b/include/hw/scsi/scsi.h
9ae3a8
@@ -9,6 +9,8 @@
9ae3a8
 #define MAX_SCSI_DEVS	255
9ae3a8
 
9ae3a8
 #define SCSI_CMD_BUF_SIZE     16
9ae3a8
+#define SCSI_SENSE_LEN      18
9ae3a8
+#define SCSI_INQUIRY_LEN    36
9ae3a8
 
9ae3a8
 typedef struct SCSIBus SCSIBus;
9ae3a8
 typedef struct SCSIBusInfo SCSIBusInfo;
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8