|
|
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 |
|