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: Zhangyanyu <zyy4013@stu.ouc.edu.cn> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									b356807fcd
								
							
						
					
					
						commit
						87e459a810
					
				| @ -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, | |||||||
|     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, | |||||||
|         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, | |||||||
|         } |         } | ||||||
|         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, | |||||||
|     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, | |||||||
|         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, | |||||||
|         } |         } | ||||||
|         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, | |||||||
|         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) | |||||||
|     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(); | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Paolo Bonzini
						Paolo Bonzini