From 68ff33d50e146b0eee41d4b2f51322762fce98fe Mon Sep 17 00:00:00 2001
From: Asias He <asias@redhat.com>
Date: Tue, 15 Oct 2013 09:53:15 +0200
Subject: [PATCH 1/2] scsi: Allocate SCSITargetReq r->buf dynamically [CVE-2013-4344]

RH-Author: Asias He <asias@redhat.com>
Message-id: <1381457431-5479-1-git-send-email-asias@redhat.com>
O-Subject: [virt-devel] [RHEL6.5 qemu-kvm EMBARGOED PATCH v2] scsi: Allocate SCSITargetReq r->buf dynamically [CVE-2013-4344]
Bugzilla: 1007330
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>

This is the manual backport of upstream 846424350b292f16b732b573273a5c1f195cd7a3:

    r->buf is hardcoded to 2056 which is (256 + 1) * 8, allowing 256 luns at
    most. If more than 256 luns are specified by user, we have buffer
    overflow in scsi_target_emulate_report_luns.

    To fix, we allocate the buffer dynamically.

    Signed-off-by: Asias He <asias@redhat.com>
    Tested-by: Michael Roth <mdroth@linux.vnet.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Signed-off-by: Asias He <asias@redhat.com>
---
 hw/scsi-bus.c |   43 +++++++++++++++++++++++++++++++++----------
 hw/scsi.h     |    2 ++
 2 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index c466ffa..d6ffc05 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -11,6 +11,8 @@ static char *scsibus_get_dev_path(DeviceState *dev);
 static char *scsibus_get_fw_dev_path(DeviceState *dev);
 static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
 static void scsi_req_dequeue(SCSIRequest *req);
+static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len);
+static void scsi_target_free_buf(SCSIRequest *req);
 
 static struct BusInfo scsi_bus_info = {
     .name  = "SCSI",
@@ -275,7 +277,8 @@ typedef struct SCSITargetReq SCSITargetReq;
 struct SCSITargetReq {
     SCSIRequest req;
     int len;
-    uint8_t buf[2056];
+    uint8_t *buf;
+    int buf_len;
 };
 
 static void store_lun(uint8_t *outbuf, int lun)
@@ -318,12 +321,10 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
     if (!found_lun0) {
         n += 8;
     }
-    len = MIN(n + 8, r->req.cmd.xfer & ~7);
-    if (len > sizeof(r->buf)) {
-        /* TODO: > 256 LUNs? */
-        return false;
-    }
 
+    scsi_target_alloc_buf(&r->req, n + 8);
+
+    len = MIN(n + 8, r->req.cmd.xfer & ~7);
     memset(r->buf, 0, len);
     r->buf[0] = n >> 24;
     r->buf[1] = n >> 16;
@@ -346,6 +347,9 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
 static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
 {
     assert(r->req.dev->lun != r->req.lun);
+
+    scsi_target_alloc_buf(&r->req, SCSI_INQUIRY_LEN);
+
     if (r->req.cmd.buf[1] & 0x2) {
         /* Command support data - optional, not implemented */
         return false;
@@ -370,7 +374,7 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
             return false;
         }
         /* done with EVPD */
-        assert(r->len < sizeof(r->buf));
+        assert(r->len < r->buf_len);
         r->len = MIN(r->req.cmd.xfer, r->len);
         return true;
     }
@@ -381,7 +385,7 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
     }
 
     /* PAGE CODE == 0 */
-    r->len = MIN(r->req.cmd.xfer, 36);
+    r->len = MIN(r->req.cmd.xfer, SCSI_INQUIRY_LEN);
     memset(r->buf, 0, r->len);
     if (r->req.lun != 0) {
         r->buf[0] = TYPE_NO_LUN;
@@ -414,8 +418,9 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
         }
         break;
     case REQUEST_SENSE:
+        scsi_target_alloc_buf(&r->req, SCSI_SENSE_LEN);
         r->len = scsi_device_get_sense(r->req.dev, r->buf,
-                                       MIN(req->cmd.xfer, sizeof r->buf),
+                                       MIN(req->cmd.xfer, r->buf_len),
                                        (req->cmd.buf[1] & 1) == 0);
         if (r->req.dev->sense_is_ua) {
             if (r->req.dev->info->unit_attention_reported) {
@@ -462,11 +467,29 @@ static uint8_t *scsi_target_get_buf(SCSIRequest *req)
     return r->buf;
 }
 
+static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len)
+{
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+
+    r->buf = g_malloc(len);
+    r->buf_len = len;
+
+    return r->buf;
+}
+
+static void scsi_target_free_buf(SCSIRequest *req)
+{
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+
+    g_free(r->buf);
+}
+
 static const struct SCSIReqOps reqops_target_command = {
     .size         = sizeof(SCSITargetReq),
     .send_command = scsi_target_send_command,
     .read_data    = scsi_target_read_data,
     .get_buf      = scsi_target_get_buf,
+    .free_req     = scsi_target_free_buf,
 };
 
 
@@ -1162,7 +1185,7 @@ int scsi_build_sense(uint8_t *in_buf, int in_len,
         buf[7] = 10;
         buf[12] = sense.asc;
         buf[13] = sense.ascq;
-        return MIN(len, 18);
+        return MIN(len, SCSI_SENSE_LEN);
     } else {
         /* Return descriptor format sense buffer */
         buf[0] = 0x72;
diff --git a/hw/scsi.h b/hw/scsi.h
index 371141b..f4b9d85 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -9,6 +9,8 @@
 #define MAX_SCSI_DEVS	255
 
 #define SCSI_CMD_BUF_SIZE     16
+#define SCSI_SENSE_LEN      18
+#define SCSI_INQUIRY_LEN    36
 
 typedef struct SCSIBus SCSIBus;
 typedef struct SCSIBusInfo SCSIBusInfo;
-- 
1.7.1

