From 9c1757f479fc2d8a0ce0e927af6de102d1aa11d6 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Mon, 12 Feb 2018 21:25:56 +0200 Subject: [PATCH] Properly validate blit bounds, if it is out of VRAM bounds, reduce height to prevent crashes. --- qemuvga/cirrus_vga.cpp | 107 +++++++++++++++++++++++--------------- qemuvga/cirrus_vga_rop.h | 93 ++++++++++++++++++++------------- qemuvga/cirrus_vga_rop2.h | 92 ++++++++++++++++++++------------ qemuvga/qemuuaeglue.h | 10 ++-- 4 files changed, 185 insertions(+), 117 deletions(-) diff --git a/qemuvga/cirrus_vga.cpp b/qemuvga/cirrus_vga.cpp index b3dc817d..ea51fec7 100644 --- a/qemuvga/cirrus_vga.cpp +++ b/qemuvga/cirrus_vga.cpp @@ -173,19 +173,49 @@ #define CIRRUS_PNPMMIO_SIZE 0x1000 -#define BLTUNSAFE(s) \ - ( \ - ( /* check dst is within bounds */ \ - (s)->cirrus_blt_height * ABS((s)->cirrus_blt_dstpitch) \ - + ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \ - (s)->vga.vram_size \ - ) || \ - ( /* check src is within bounds */ \ - (s)->cirrus_blt_height * ABS((s)->cirrus_blt_srcpitch) \ - + ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \ - (s)->vga.vram_size \ - ) \ - ) +// If blit is out of bounds, reduce height. +static void check_blit(int32_t addr, uint32_t mask, int pitch, int width, int *height, int depth, int dir) +{ + int h = *height; + int32_t off; + if (!h || !width) + return; + addr &= mask; + off = addr + pitch * (h - 1); + if (dir > 0) { + off += width * (depth / 8); + } else { + off -= width * (depth / 8); + } + if (off > mask + 1) { + h -= (off - (mask + 1) + pitch - 1) / pitch; + } else if (off < 0) { + h -= ((-off) + pitch - 1) / pitch; + } + if (h < 0) + h = 0; + *height = h; +} + +#define INITBLIT \ + dst += (dstaddr & dstmask); \ + src += (srcaddr & srcmask); + +#define INITBLIT_DST \ + dst += (dstaddr & dstmask); + +#define BLTCHECK_DST(skip) \ + check_blit(dstaddr, dstmask, dstpitch, bltwidth - skip, &bltheight, DEPTH, 1); + +#define BLTCHECK_FWD \ + check_blit(dstaddr, dstmask, dstpitch, bltwidth, &bltheight, 8, 1); \ + check_blit(srcaddr, srcmask, srcpitch, bltwidth, &bltheight, 8, 1); \ + INITBLIT; + +#define BLTCHECK_BKWD \ + check_blit(dstaddr, dstmask, dstpitch, bltwidth, &bltheight, 8, -1); \ + check_blit(srcaddr, srcmask, srcpitch, bltwidth, &bltheight, 8, -1); \ + INITBLIT; #if 0 typedef struct PCICirrusVGAState { @@ -223,15 +253,16 @@ static void cirrus_update_memory_access(CirrusVGAState *s); ***************************************/ static void cirrus_bitblt_rop_nop(CirrusVGAState *s, - uint8_t *dst,const uint8_t *src, - int dstpitch,int srcpitch, - int bltwidth,int bltheight) + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, + int dstpitch,int srcpitch, + int bltwidth,int bltheight) { } static void cirrus_bitblt_fill_nop(CirrusVGAState *s, - uint8_t *dst, - int dstpitch, int bltwidth,int bltheight) + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + int dstpitch, int bltwidth,int bltheight) { } @@ -578,16 +609,11 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin, static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, const uint8_t * src) { - uint8_t *dst; - - dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask); - -// if (BLTUNSAFE(s)) -// return 0; - - (*s->cirrus_rop) (s, dst, src, - s->cirrus_blt_dstpitch, 0, - s->cirrus_blt_width, s->cirrus_blt_height); + (*s->cirrus_rop) (s, + s->vga.vram_ptr, s->cirrus_blt_dstaddr, s->cirrus_addr_mask, + src, 0, s->cirrus_addr_mask, + s->cirrus_blt_dstpitch, 0, + s->cirrus_blt_width, s->cirrus_blt_height); cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, s->cirrus_blt_dstpitch, s->cirrus_blt_width, s->cirrus_blt_height); @@ -600,10 +626,8 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) { cirrus_fill_t rop_func; -// if (BLTUNSAFE(s)) -// return 0; rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), + rop_func(s, s->vga.vram_ptr, s->cirrus_blt_dstaddr, s->cirrus_addr_mask, s->cirrus_blt_dstpitch, s->cirrus_blt_width, s->cirrus_blt_height); cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, @@ -677,12 +701,11 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) if (notify) graphic_hw_update(s->vga.con); - (*s->cirrus_rop) (s, s->vga.vram_ptr + - (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), - s->vga.vram_ptr + - (s->cirrus_blt_srcaddr & s->cirrus_addr_mask), - s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, - s->cirrus_blt_width, s->cirrus_blt_height); + (*s->cirrus_rop) (s, + s->vga.vram_ptr, s->cirrus_blt_dstaddr, s->cirrus_addr_mask, + s->vga.vram_ptr, s->cirrus_blt_srcaddr, s->cirrus_addr_mask, + s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, + s->cirrus_blt_width, s->cirrus_blt_height); if (notify) { qemu_console_copy(s->vga.con, @@ -701,9 +724,6 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) { -// if (BLTUNSAFE(s)) -// return 0; - cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr, s->cirrus_blt_srcaddr - s->vga.start_addr, s->cirrus_blt_width, s->cirrus_blt_height); @@ -731,9 +751,10 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) } else { /* at least one scan line */ do { - (*s->cirrus_rop)(s, s->vga.vram_ptr + - (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), - s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); + (*s->cirrus_rop)(s, + s->vga.vram_ptr, s->cirrus_blt_dstaddr, s->cirrus_addr_mask, + s->cirrus_bltbuf, 0, 0, + 0, 0, s->cirrus_blt_width, 1); cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, s->cirrus_blt_width, 1); s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch; diff --git a/qemuvga/cirrus_vga_rop.h b/qemuvga/cirrus_vga_rop.h index 45a77a01..e5eb74c0 100644 --- a/qemuvga/cirrus_vga_rop.h +++ b/qemuvga/cirrus_vga_rop.h @@ -44,22 +44,18 @@ STATIC_INLINE void glue(rop_32_,ROP_NAME)(uint32_t *dst, uint32_t src) static void glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s, - uint8_t *dst,const uint8_t *src, - int dstpitch,int srcpitch, - int bltwidth,int bltheight) + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, + int dstpitch,int srcpitch, + int bltwidth,int bltheight) { int x,y; + + BLTCHECK_FWD + dstpitch -= bltwidth; srcpitch -= bltwidth; -#if 0 - /* Invalid test! TW */ - if (dstpitch < 0 || srcpitch < 0) { - /* is 0 valid? srcpitch == 0 could be useful */ - return; - } -#endif - for (y = 0; y < bltheight; y++) { for (x = 0; x < (bltwidth & ~3); x += 4) { ROP_OP_32((uint32_t*)dst, *((uint32_t*)src)); @@ -78,14 +74,19 @@ glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s, static void glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s, - uint8_t *dst,const uint8_t *src, - int dstpitch,int srcpitch, + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, + int dstpitch,int srcpitch, int bltwidth,int bltheight) { - int x,y; - dstpitch += bltwidth; + BLTCHECK_BKWD + + int x,y; + + dstpitch += bltwidth; srcpitch += bltwidth; - for (y = 0; y < bltheight; y++) { + + for (y = 0; y < bltheight; y++) { for (x = 0; x < (bltwidth & ~3); x += 4) { dst -= 3; src -= 3; @@ -105,15 +106,20 @@ glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s, static void glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s, - uint8_t *dst,const uint8_t *src, - int dstpitch,int srcpitch, - int bltwidth,int bltheight) + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, + int dstpitch,int srcpitch, + int bltwidth,int bltheight) { - int x,y; + BLTCHECK_FWD + + int x,y; uint8_t p; - dstpitch -= bltwidth; + + dstpitch -= bltwidth; srcpitch -= bltwidth; - for (y = 0; y < bltheight; y++) { + + for (y = 0; y < bltheight; y++) { for (x = 0; x < bltwidth; x++) { p = *dst; ROP_OP(&p, *src); @@ -128,15 +134,20 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s, static void glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s, - uint8_t *dst,const uint8_t *src, + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, int dstpitch,int srcpitch, int bltwidth,int bltheight) { - int x,y; + BLTCHECK_BKWD + + int x,y; uint8_t p; - dstpitch += bltwidth; + + dstpitch += bltwidth; srcpitch += bltwidth; - for (y = 0; y < bltheight; y++) { + + for (y = 0; y < bltheight; y++) { for (x = 0; x < bltwidth; x++) { p = *dst; ROP_OP(&p, *src); @@ -151,15 +162,20 @@ glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s, static void glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s, - uint8_t *dst,const uint8_t *src, + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, int dstpitch,int srcpitch, int bltwidth,int bltheight) { - int x,y; + BLTCHECK_FWD + + int x,y; uint8_t p1, p2; - dstpitch -= bltwidth; + + dstpitch -= bltwidth; srcpitch -= bltwidth; - for (y = 0; y < bltheight; y++) { + + for (y = 0; y < bltheight; y++) { for (x = 0; x < bltwidth; x+=2) { p1 = *dst; p2 = *(dst+1); @@ -179,15 +195,20 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s, static void glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s, - uint8_t *dst,const uint8_t *src, - int dstpitch,int srcpitch, - int bltwidth,int bltheight) + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, + int dstpitch,int srcpitch, + int bltwidth,int bltheight) { - int x,y; + BLTCHECK_BKWD + + int x,y; uint8_t p1, p2; - dstpitch += bltwidth; + + dstpitch += bltwidth; srcpitch += bltwidth; - for (y = 0; y < bltheight; y++) { + + for (y = 0; y < bltheight; y++) { for (x = 0; x < bltwidth; x+=2) { p1 = *(dst-1); p2 = *dst; diff --git a/qemuvga/cirrus_vga_rop2.h b/qemuvga/cirrus_vga_rop2.h index c665095a..e62418fb 100644 --- a/qemuvga/cirrus_vga_rop2.h +++ b/qemuvga/cirrus_vga_rop2.h @@ -38,12 +38,13 @@ static void glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) - (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, - int bltwidth, int bltheight) + (CirrusVGAState * s, + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, + int dstpitch, int srcpitch, + int bltwidth, int bltheight) { - uint8_t *d; + uint8_t *d; int x, y, pattern_y, pattern_pitch, pattern_x; unsigned int col; const uint8_t *src1; @@ -53,6 +54,9 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) int skipleft = (s->vga.gr[0x2f] & 0x07) * (DEPTH / 8); #endif + BLTCHECK_DST(skipleft) + INITBLIT + #if DEPTH == 8 pattern_pitch = 8; #elif DEPTH == 16 @@ -93,12 +97,13 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) /* NOTE: srcpitch is ignored */ static void glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) - (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, - int bltwidth, int bltheight) + (CirrusVGAState * s, + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, + int dstpitch, int srcpitch, + int bltwidth, int bltheight) { - uint8_t *d; + uint8_t *d; int x, y; unsigned bits, bits_xor; unsigned int col; @@ -112,7 +117,10 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) int dstskipleft = srcskipleft * (DEPTH / 8); #endif - if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { + BLTCHECK_DST(dstskipleft) + INITBLIT + + if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { bits_xor = 0xff; // Color expansion + transparency: fgcol, not bgcol. TW. col = s->cirrus_blt_fgcol; @@ -143,12 +151,13 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) static void glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) - (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, - int bltwidth, int bltheight) + (CirrusVGAState * s, + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, + int dstpitch, int srcpitch, + int bltwidth, int bltheight) { - uint32_t colors[2]; + uint32_t colors[2]; uint8_t *d; int x, y; unsigned bits; @@ -157,7 +166,10 @@ glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) int srcskipleft = s->vga.gr[0x2f] & 0x07; int dstskipleft = srcskipleft * (DEPTH / 8); - colors[0] = s->cirrus_blt_bgcol; + BLTCHECK_DST(dstskipleft) + INITBLIT + + colors[0] = s->cirrus_blt_bgcol; colors[1] = s->cirrus_blt_fgcol; for(y = 0; y < bltheight; y++) { bitmask = 0x80 >> srcskipleft; @@ -179,12 +191,13 @@ glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) static void glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH) - (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, - int bltwidth, int bltheight) + (CirrusVGAState * s, + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, + int dstpitch, int srcpitch, + int bltwidth, int bltheight) { - uint8_t *d; + uint8_t *d; int x, y, bitpos, pattern_y; unsigned int bits, bits_xor; unsigned int col; @@ -196,7 +209,10 @@ glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH) int dstskipleft = srcskipleft * (DEPTH / 8); #endif - if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { + BLTCHECK_DST(dstskipleft) + INITBLIT + + if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { bits_xor = 0xff; // Color expansion + transparency: fgcol, not bgcol. TW. col = s->cirrus_blt_fgcol; @@ -224,10 +240,11 @@ glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH) static void glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH) - (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, - int bltwidth, int bltheight) + (CirrusVGAState * s, + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, + int dstpitch, int srcpitch, + int bltwidth, int bltheight) { uint32_t colors[2]; uint8_t *d; @@ -237,6 +254,9 @@ glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH) int srcskipleft = s->vga.gr[0x2f] & 0x07; int dstskipleft = srcskipleft * (DEPTH / 8); + BLTCHECK_DST(dstskipleft) + INITBLIT + colors[0] = s->cirrus_blt_bgcol; colors[1] = s->cirrus_blt_fgcol; pattern_y = s->cirrus_blt_srcaddr & 7; @@ -258,24 +278,28 @@ glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH) static void glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH) - (CirrusVGAState *s, - uint8_t *dst, int dst_pitch, - int width, int height) + (CirrusVGAState *s, + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + int dstpitch, + int bltwidth, int bltheight) { uint8_t *d, *d1; uint32_t col; int x, y; - col = s->cirrus_blt_fgcol; + BLTCHECK_DST(0) + INITBLIT_DST + + col = s->cirrus_blt_fgcol; d1 = dst; - for(y = 0; y < height; y++) { + for(y = 0; y < bltheight; y++) { d = d1; - for(x = 0; x < width; x += (DEPTH / 8)) { + for(x = 0; x < bltwidth; x += (DEPTH / 8)) { PUTPIXEL(); d += (DEPTH / 8); } - d1 += dst_pitch; + d1 += dstpitch; } } diff --git a/qemuvga/qemuuaeglue.h b/qemuvga/qemuuaeglue.h index 004a0423..ba3448fe 100644 --- a/qemuvga/qemuuaeglue.h +++ b/qemuvga/qemuuaeglue.h @@ -242,11 +242,13 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque); typedef struct CirrusVGAState CirrusVGAState; typedef void (*cirrus_bitblt_rop_t) (CirrusVGAState *s, - uint8_t * dst, const uint8_t * src, - int dstpitch, int srcpitch, - int bltwidth, int bltheight); + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + const uint8_t *src, uint32_t srcaddr, uint32_t srcmask, + int dstpitch, int srcpitch, + int bltwidth, int bltheight); typedef void (*cirrus_fill_t)(CirrusVGAState *s, - uint8_t *dst, int dst_pitch, int width, int height); + uint8_t *dst, uint32_t dstaddr, uint32_t dstmask, + int dst_pitch, int width, int height); struct CirrusVGAState { VGACommonState vga; -- 2.47.3