scsi: Allocate SCSITargetReq r->buf dynamically

BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1007330
Brew: https://brewweb.devel.redhat.com/taskinfo?taskID=6282465

This is the backport of the following commit. The patch is not
sent public since it is a embargoed bug.

   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>

Signed-off-by: Asias He <asias@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

*s/&r->buf/r->buf/ due to type change

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
This commit is contained in:
Asias He 2013-09-13 14:56:55 +08:00 committed by Michael Roth
parent 1b5f770941
commit fdcbe7d587
2 changed files with 35 additions and 11 deletions

View File

@ -11,6 +11,8 @@ static char *scsibus_get_dev_path(DeviceState *dev);
static char *scsibus_get_fw_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 int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
static void scsi_req_dequeue(SCSIRequest *req); 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 Property scsi_props[] = { static Property scsi_props[] = {
DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0), DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
@ -317,7 +319,8 @@ typedef struct SCSITargetReq SCSITargetReq;
struct SCSITargetReq { struct SCSITargetReq {
SCSIRequest req; SCSIRequest req;
int len; int len;
uint8_t buf[2056]; uint8_t *buf;
int buf_len;
}; };
static void store_lun(uint8_t *outbuf, int lun) static void store_lun(uint8_t *outbuf, int lun)
@ -361,14 +364,12 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
if (!found_lun0) { if (!found_lun0) {
n += 8; 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); memset(r->buf, 0, len);
stl_be_p(&r->buf, n); stl_be_p(r->buf, n);
i = found_lun0 ? 8 : 16; i = found_lun0 ? 8 : 16;
QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) { QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
DeviceState *qdev = kid->child; DeviceState *qdev = kid->child;
@ -387,6 +388,9 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
static bool scsi_target_emulate_inquiry(SCSITargetReq *r) static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
{ {
assert(r->req.dev->lun != r->req.lun); assert(r->req.dev->lun != r->req.lun);
scsi_target_alloc_buf(&r->req, SCSI_INQUIRY_LEN);
if (r->req.cmd.buf[1] & 0x2) { if (r->req.cmd.buf[1] & 0x2) {
/* Command support data - optional, not implemented */ /* Command support data - optional, not implemented */
return false; return false;
@ -411,7 +415,7 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
return false; return false;
} }
/* done with EVPD */ /* done with EVPD */
assert(r->len < sizeof(r->buf)); assert(r->len < r->buf_len);
r->len = MIN(r->req.cmd.xfer, r->len); r->len = MIN(r->req.cmd.xfer, r->len);
return true; return true;
} }
@ -455,8 +459,8 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
} }
break; break;
case REQUEST_SENSE: case REQUEST_SENSE:
r->len = scsi_device_get_sense(r->req.dev, r->buf, scsi_target_alloc_buf(&r->req, SCSI_SENSE_LEN);
MIN(req->cmd.xfer, sizeof r->buf), r->len = scsi_device_get_sense(r->req.dev, r->buf, r->buf_len,
(req->cmd.buf[1] & 1) == 0); (req->cmd.buf[1] & 1) == 0);
if (r->req.dev->sense_is_ua) { if (r->req.dev->sense_is_ua) {
scsi_device_unit_attention_reported(req->dev); scsi_device_unit_attention_reported(req->dev);
@ -501,11 +505,29 @@ static uint8_t *scsi_target_get_buf(SCSIRequest *req)
return r->buf; 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 = { static const struct SCSIReqOps reqops_target_command = {
.size = sizeof(SCSITargetReq), .size = sizeof(SCSITargetReq),
.send_command = scsi_target_send_command, .send_command = scsi_target_send_command,
.read_data = scsi_target_read_data, .read_data = scsi_target_read_data,
.get_buf = scsi_target_get_buf, .get_buf = scsi_target_get_buf,
.free_req = scsi_target_free_buf,
}; };
@ -1365,7 +1387,7 @@ int scsi_build_sense(uint8_t *in_buf, int in_len,
buf[7] = 10; buf[7] = 10;
buf[12] = sense.asc; buf[12] = sense.asc;
buf[13] = sense.ascq; buf[13] = sense.ascq;
return MIN(len, 18); return MIN(len, SCSI_SENSE_LEN);
} else { } else {
/* Return descriptor format sense buffer */ /* Return descriptor format sense buffer */
buf[0] = 0x72; buf[0] = 0x72;

View File

@ -9,6 +9,8 @@
#define MAX_SCSI_DEVS 255 #define MAX_SCSI_DEVS 255
#define SCSI_CMD_BUF_SIZE 16 #define SCSI_CMD_BUF_SIZE 16
#define SCSI_SENSE_LEN 18
#define SCSI_INQUIRY_LEN 36
typedef struct SCSIBus SCSIBus; typedef struct SCSIBus SCSIBus;
typedef struct SCSIBusInfo SCSIBusInfo; typedef struct SCSIBusInfo SCSIBusInfo;