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