ati-vga: Fix checks in ati_2d_blt() to avoid crash
In some corner cases (that never happen during normal operation but a malicious guest could program wrong values) pixman functions were called with parameters that result in a crash. Fix this and add more checks to disallow such cases. Reported-by: Ziming Zhang <ezrakiez@gmail.com> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> Message-id: 20200406204029.19559747D5D@zero.eik.bme.hu Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
		
							parent
							
								
									8d1439b692
								
							
						
					
					
						commit
						ac2071c379
					
				@ -53,12 +53,20 @@ void ati_2d_blt(ATIVGAState *s)
 | 
				
			|||||||
            s->vga.vbe_start_addr, surface_data(ds), surface_stride(ds),
 | 
					            s->vga.vbe_start_addr, surface_data(ds), surface_stride(ds),
 | 
				
			||||||
            surface_bits_per_pixel(ds),
 | 
					            surface_bits_per_pixel(ds),
 | 
				
			||||||
            (s->regs.dp_mix & GMC_ROP3_MASK) >> 16);
 | 
					            (s->regs.dp_mix & GMC_ROP3_MASK) >> 16);
 | 
				
			||||||
    int dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
 | 
					    unsigned dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
 | 
				
			||||||
                 s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width);
 | 
					                      s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width);
 | 
				
			||||||
    int dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
 | 
					    unsigned dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
 | 
				
			||||||
                 s->regs.dst_y : s->regs.dst_y + 1 - s->regs.dst_height);
 | 
					                      s->regs.dst_y : s->regs.dst_y + 1 - s->regs.dst_height);
 | 
				
			||||||
    int bpp = ati_bpp_from_datatype(s);
 | 
					    int bpp = ati_bpp_from_datatype(s);
 | 
				
			||||||
 | 
					    if (!bpp) {
 | 
				
			||||||
 | 
					        qemu_log_mask(LOG_GUEST_ERROR, "Invalid bpp\n");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    int dst_stride = DEFAULT_CNTL ? s->regs.dst_pitch : s->regs.default_pitch;
 | 
					    int dst_stride = DEFAULT_CNTL ? s->regs.dst_pitch : s->regs.default_pitch;
 | 
				
			||||||
 | 
					    if (!dst_stride) {
 | 
				
			||||||
 | 
					        qemu_log_mask(LOG_GUEST_ERROR, "Zero dest pitch\n");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    uint8_t *dst_bits = s->vga.vram_ptr + (DEFAULT_CNTL ?
 | 
					    uint8_t *dst_bits = s->vga.vram_ptr + (DEFAULT_CNTL ?
 | 
				
			||||||
                        s->regs.dst_offset : s->regs.default_offset);
 | 
					                        s->regs.dst_offset : s->regs.default_offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -82,12 +90,16 @@ void ati_2d_blt(ATIVGAState *s)
 | 
				
			|||||||
    switch (s->regs.dp_mix & GMC_ROP3_MASK) {
 | 
					    switch (s->regs.dp_mix & GMC_ROP3_MASK) {
 | 
				
			||||||
    case ROP3_SRCCOPY:
 | 
					    case ROP3_SRCCOPY:
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
 | 
					        unsigned src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
 | 
				
			||||||
                     s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width);
 | 
					                       s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width);
 | 
				
			||||||
        int src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
 | 
					        unsigned src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
 | 
				
			||||||
                     s->regs.src_y : s->regs.src_y + 1 - s->regs.dst_height);
 | 
					                       s->regs.src_y : s->regs.src_y + 1 - s->regs.dst_height);
 | 
				
			||||||
        int src_stride = DEFAULT_CNTL ?
 | 
					        int src_stride = DEFAULT_CNTL ?
 | 
				
			||||||
                         s->regs.src_pitch : s->regs.default_pitch;
 | 
					                         s->regs.src_pitch : s->regs.default_pitch;
 | 
				
			||||||
 | 
					        if (!src_stride) {
 | 
				
			||||||
 | 
					            qemu_log_mask(LOG_GUEST_ERROR, "Zero source pitch\n");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        uint8_t *src_bits = s->vga.vram_ptr + (DEFAULT_CNTL ?
 | 
					        uint8_t *src_bits = s->vga.vram_ptr + (DEFAULT_CNTL ?
 | 
				
			||||||
                            s->regs.src_offset : s->regs.default_offset);
 | 
					                            s->regs.src_offset : s->regs.default_offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -137,8 +149,10 @@ void ati_2d_blt(ATIVGAState *s)
 | 
				
			|||||||
                                    dst_y * surface_stride(ds),
 | 
					                                    dst_y * surface_stride(ds),
 | 
				
			||||||
                                    s->regs.dst_height * surface_stride(ds));
 | 
					                                    s->regs.dst_height * surface_stride(ds));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        s->regs.dst_x += s->regs.dst_width;
 | 
					        s->regs.dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
 | 
				
			||||||
        s->regs.dst_y += s->regs.dst_height;
 | 
					                         dst_x + s->regs.dst_width : dst_x);
 | 
				
			||||||
 | 
					        s->regs.dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
 | 
				
			||||||
 | 
					                         dst_y + s->regs.dst_height : dst_y);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case ROP3_PATCOPY:
 | 
					    case ROP3_PATCOPY:
 | 
				
			||||||
@ -179,7 +193,8 @@ void ati_2d_blt(ATIVGAState *s)
 | 
				
			|||||||
                                    dst_y * surface_stride(ds),
 | 
					                                    dst_y * surface_stride(ds),
 | 
				
			||||||
                                    s->regs.dst_height * surface_stride(ds));
 | 
					                                    s->regs.dst_height * surface_stride(ds));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        s->regs.dst_y += s->regs.dst_height;
 | 
					        s->regs.dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
 | 
				
			||||||
 | 
					                         dst_y + s->regs.dst_height : dst_y);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user