scsi: pvscsi: limit loop to fetch SG list
In PVSCSI paravirtual SCSI bus, pvscsi_convert_sglist can take a very long time or go into an infinite loop due to two different bugs: 1) the request descriptor data length is defined to be 64 bit. While building SG list from a request descriptor, it gets truncated to 32bit in routine 'pvscsi_convert_sglist'. This could lead to an infinite loop situation large 'dataLen' values when data_length is cast to uint32_t and chunk_size becomes always zero. Fix this by removing the incorrect cast. 2) pvscsi_get_next_sg_elem can be called arbitrarily many times if the element has a zero length. Get out of the loop early when this happens, by introducing an upper limit on the number of SG list elements. Reported-by: Li Qiang <liqiang6-s@360.cn> Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> Message-Id: <1473108643-12983-1-git-send-email-ppandit@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									a2feb3483e
								
							
						
					
					
						commit
						49adc5d3f8
					
				@ -40,6 +40,8 @@
 | 
				
			|||||||
#define PVSCSI_MAX_DEVS                   (64)
 | 
					#define PVSCSI_MAX_DEVS                   (64)
 | 
				
			||||||
#define PVSCSI_MSIX_NUM_VECTORS           (1)
 | 
					#define PVSCSI_MSIX_NUM_VECTORS           (1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PVSCSI_MAX_SG_ELEM                2048
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PVSCSI_MAX_CMD_DATA_WORDS \
 | 
					#define PVSCSI_MAX_CMD_DATA_WORDS \
 | 
				
			||||||
    (sizeof(PVSCSICmdDescSetupRings)/sizeof(uint32_t))
 | 
					    (sizeof(PVSCSICmdDescSetupRings)/sizeof(uint32_t))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -628,17 +630,16 @@ pvscsi_queue_pending_descriptor(PVSCSIState *s, SCSIDevice **d,
 | 
				
			|||||||
static void
 | 
					static void
 | 
				
			||||||
pvscsi_convert_sglist(PVSCSIRequest *r)
 | 
					pvscsi_convert_sglist(PVSCSIRequest *r)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int chunk_size;
 | 
					    uint32_t chunk_size, elmcnt = 0;
 | 
				
			||||||
    uint64_t data_length = r->req.dataLen;
 | 
					    uint64_t data_length = r->req.dataLen;
 | 
				
			||||||
    PVSCSISGState sg = r->sg;
 | 
					    PVSCSISGState sg = r->sg;
 | 
				
			||||||
    while (data_length) {
 | 
					    while (data_length && elmcnt < PVSCSI_MAX_SG_ELEM) {
 | 
				
			||||||
        while (!sg.resid) {
 | 
					        while (!sg.resid && elmcnt++ < PVSCSI_MAX_SG_ELEM) {
 | 
				
			||||||
            pvscsi_get_next_sg_elem(&sg);
 | 
					            pvscsi_get_next_sg_elem(&sg);
 | 
				
			||||||
            trace_pvscsi_convert_sglist(r->req.context, r->sg.dataAddr,
 | 
					            trace_pvscsi_convert_sglist(r->req.context, r->sg.dataAddr,
 | 
				
			||||||
                                        r->sg.resid);
 | 
					                                        r->sg.resid);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        assert(data_length > 0);
 | 
					        chunk_size = MIN(data_length, sg.resid);
 | 
				
			||||||
        chunk_size = MIN((unsigned) data_length, sg.resid);
 | 
					 | 
				
			||||||
        if (chunk_size) {
 | 
					        if (chunk_size) {
 | 
				
			||||||
            qemu_sglist_add(&r->sgl, sg.dataAddr, chunk_size);
 | 
					            qemu_sglist_add(&r->sgl, sg.dataAddr, chunk_size);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user