提交 87e459a8 编写于 作者: P Paolo Bonzini

megasas: always store SCSIRequest* into MegasasCmd

This ensures that the request is unref'ed properly, and avoids a
segmentation fault in the new qtest testcase that is added.
This is CVE-2017-9503.
Reported-by: NZhangyanyu <zyy4013@stu.ouc.edu.cn>
Signed-off-by: NPaolo Bonzini <pbonzini@redhat.com>
上级 b356807f
...@@ -609,6 +609,9 @@ static void megasas_reset_frames(MegasasState *s) ...@@ -609,6 +609,9 @@ static void megasas_reset_frames(MegasasState *s)
static void megasas_abort_command(MegasasCmd *cmd) static void megasas_abort_command(MegasasCmd *cmd)
{ {
/* Never abort internal commands. */ /* Never abort internal commands. */
if (cmd->dcmd_opcode != -1) {
return;
}
if (cmd->req != NULL) { if (cmd->req != NULL) {
scsi_req_cancel(cmd->req); scsi_req_cancel(cmd->req);
} }
...@@ -1017,7 +1020,6 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun, ...@@ -1017,7 +1020,6 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
uint64_t pd_size; uint64_t pd_size;
uint16_t pd_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF); uint16_t pd_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
uint8_t cmdbuf[6]; uint8_t cmdbuf[6];
SCSIRequest *req;
size_t len, resid; size_t len, resid;
if (!cmd->iov_buf) { if (!cmd->iov_buf) {
...@@ -1026,8 +1028,8 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun, ...@@ -1026,8 +1028,8 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */ info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */
info->vpd_page83[0] = 0x7f; info->vpd_page83[0] = 0x7f;
megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data)); megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data));
req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd); cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
if (!req) { if (!cmd->req) {
trace_megasas_dcmd_req_alloc_failed(cmd->index, trace_megasas_dcmd_req_alloc_failed(cmd->index,
"PD get info std inquiry"); "PD get info std inquiry");
g_free(cmd->iov_buf); g_free(cmd->iov_buf);
...@@ -1036,26 +1038,26 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun, ...@@ -1036,26 +1038,26 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
} }
trace_megasas_dcmd_internal_submit(cmd->index, trace_megasas_dcmd_internal_submit(cmd->index,
"PD get info std inquiry", lun); "PD get info std inquiry", lun);
len = scsi_req_enqueue(req); len = scsi_req_enqueue(cmd->req);
if (len > 0) { if (len > 0) {
cmd->iov_size = len; cmd->iov_size = len;
scsi_req_continue(req); scsi_req_continue(cmd->req);
} }
return MFI_STAT_INVALID_STATUS; return MFI_STAT_INVALID_STATUS;
} else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) { } else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) {
megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83)); megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83));
req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd); cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
if (!req) { if (!cmd->req) {
trace_megasas_dcmd_req_alloc_failed(cmd->index, trace_megasas_dcmd_req_alloc_failed(cmd->index,
"PD get info vpd inquiry"); "PD get info vpd inquiry");
return MFI_STAT_FLASH_ALLOC_FAIL; return MFI_STAT_FLASH_ALLOC_FAIL;
} }
trace_megasas_dcmd_internal_submit(cmd->index, trace_megasas_dcmd_internal_submit(cmd->index,
"PD get info vpd inquiry", lun); "PD get info vpd inquiry", lun);
len = scsi_req_enqueue(req); len = scsi_req_enqueue(cmd->req);
if (len > 0) { if (len > 0) {
cmd->iov_size = len; cmd->iov_size = len;
scsi_req_continue(req); scsi_req_continue(cmd->req);
} }
return MFI_STAT_INVALID_STATUS; return MFI_STAT_INVALID_STATUS;
} }
...@@ -1217,7 +1219,6 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun, ...@@ -1217,7 +1219,6 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
struct mfi_ld_info *info = cmd->iov_buf; struct mfi_ld_info *info = cmd->iov_buf;
size_t dcmd_size = sizeof(struct mfi_ld_info); size_t dcmd_size = sizeof(struct mfi_ld_info);
uint8_t cdb[6]; uint8_t cdb[6];
SCSIRequest *req;
ssize_t len, resid; ssize_t len, resid;
uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF); uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
uint64_t ld_size; uint64_t ld_size;
...@@ -1226,8 +1227,8 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun, ...@@ -1226,8 +1227,8 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
cmd->iov_buf = g_malloc0(dcmd_size); cmd->iov_buf = g_malloc0(dcmd_size);
info = cmd->iov_buf; info = cmd->iov_buf;
megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83)); megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83));
req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd); cmd->req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
if (!req) { if (!cmd->req) {
trace_megasas_dcmd_req_alloc_failed(cmd->index, trace_megasas_dcmd_req_alloc_failed(cmd->index,
"LD get info vpd inquiry"); "LD get info vpd inquiry");
g_free(cmd->iov_buf); g_free(cmd->iov_buf);
...@@ -1236,10 +1237,10 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun, ...@@ -1236,10 +1237,10 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
} }
trace_megasas_dcmd_internal_submit(cmd->index, trace_megasas_dcmd_internal_submit(cmd->index,
"LD get info vpd inquiry", lun); "LD get info vpd inquiry", lun);
len = scsi_req_enqueue(req); len = scsi_req_enqueue(cmd->req);
if (len > 0) { if (len > 0) {
cmd->iov_size = len; cmd->iov_size = len;
scsi_req_continue(req); scsi_req_continue(cmd->req);
} }
return MFI_STAT_INVALID_STATUS; return MFI_STAT_INVALID_STATUS;
} }
...@@ -1851,7 +1852,7 @@ static void megasas_command_complete(SCSIRequest *req, uint32_t status, ...@@ -1851,7 +1852,7 @@ static void megasas_command_complete(SCSIRequest *req, uint32_t status,
return; return;
} }
if (cmd->req == NULL) { if (cmd->dcmd_opcode != -1) {
/* /*
* Internal command complete * Internal command complete
*/ */
......
...@@ -42,10 +42,45 @@ static void pci_nop(void) ...@@ -42,10 +42,45 @@ static void pci_nop(void)
qmegasas_stop(qs); qmegasas_stop(qs);
} }
/* This used to cause a NULL pointer dereference. */
static void megasas_pd_get_info_fuzz(void)
{
QPCIDevice *dev;
QOSState *qs;
QPCIBar bar;
uint32_t context[256];
uint64_t context_pa;
int i;
qs = qmegasas_start(NULL);
dev = qpci_device_find(qs->pcibus, QPCI_DEVFN(4,0));
g_assert(dev != NULL);
qpci_device_enable(dev);
bar = qpci_iomap(dev, 0, NULL);
memset(context, 0, sizeof(context));
context[0] = cpu_to_le32(0x05050505);
context[1] = cpu_to_le32(0x01010101);
for (i = 2; i < ARRAY_SIZE(context); i++) {
context[i] = cpu_to_le32(0x41414141);
}
context[6] = cpu_to_le32(0x02020000);
context[7] = cpu_to_le32(0);
context_pa = qmalloc(qs, sizeof(context));
memwrite(context_pa, context, sizeof(context));
qpci_io_writel(dev, bar, 0x40, context_pa);
g_free(dev);
qmegasas_stop(qs);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
qtest_add_func("/megasas/pci/nop", pci_nop); qtest_add_func("/megasas/pci/nop", pci_nop);
qtest_add_func("/megasas/dcmd/pd-get-info/fuzz", megasas_pd_get_info_fuzz);
return g_test_run(); return g_test_run();
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册