Commit b2eb849d4b1fdb6f35d5c46958c7f703cf64cfef
1 parent
cbf5c748
CVE-2007-1320 - Cirrus LGD-54XX "bitblt" heap overflow
I have just noticed that patch for CVE-2007-1320 has never been applied to the QEMU CVS. Please find it below. | Multiple heap-based buffer overflows in the cirrus_invalidate_region | function in the Cirrus VGA extension in QEMU 0.8.2, as used in Xen and | possibly other products, might allow local users to execute arbitrary | code via unspecified vectors related to "attempting to mark | non-existent regions as dirty," aka the "bitblt" heap overflow. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4340 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
48 additions
and
13 deletions
hw/cirrus_vga.c
| @@ -220,6 +220,20 @@ | @@ -220,6 +220,20 @@ | ||
| 220 | #define CIRRUS_HOOK_NOT_HANDLED 0 | 220 | #define CIRRUS_HOOK_NOT_HANDLED 0 |
| 221 | #define CIRRUS_HOOK_HANDLED 1 | 221 | #define CIRRUS_HOOK_HANDLED 1 |
| 222 | 222 | ||
| 223 | +#define BLTUNSAFE(s) \ | ||
| 224 | + ( \ | ||
| 225 | + ( /* check dst is within bounds */ \ | ||
| 226 | + (s)->cirrus_blt_height * (s)->cirrus_blt_dstpitch \ | ||
| 227 | + + ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \ | ||
| 228 | + (s)->vram_size \ | ||
| 229 | + ) || \ | ||
| 230 | + ( /* check src is within bounds */ \ | ||
| 231 | + (s)->cirrus_blt_height * (s)->cirrus_blt_srcpitch \ | ||
| 232 | + + ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \ | ||
| 233 | + (s)->vram_size \ | ||
| 234 | + ) \ | ||
| 235 | + ) | ||
| 236 | + | ||
| 223 | struct CirrusVGAState; | 237 | struct CirrusVGAState; |
| 224 | typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s, | 238 | typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s, |
| 225 | uint8_t * dst, const uint8_t * src, | 239 | uint8_t * dst, const uint8_t * src, |
| @@ -639,7 +653,7 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin, | @@ -639,7 +653,7 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin, | ||
| 639 | 653 | ||
| 640 | for (y = 0; y < lines; y++) { | 654 | for (y = 0; y < lines; y++) { |
| 641 | off_cur = off_begin; | 655 | off_cur = off_begin; |
| 642 | - off_cur_end = off_cur + bytesperline; | 656 | + off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask; |
| 643 | off_cur &= TARGET_PAGE_MASK; | 657 | off_cur &= TARGET_PAGE_MASK; |
| 644 | while (off_cur < off_cur_end) { | 658 | while (off_cur < off_cur_end) { |
| 645 | cpu_physical_memory_set_dirty(s->vram_offset + off_cur); | 659 | cpu_physical_memory_set_dirty(s->vram_offset + off_cur); |
| @@ -654,7 +668,11 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, | @@ -654,7 +668,11 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, | ||
| 654 | { | 668 | { |
| 655 | uint8_t *dst; | 669 | uint8_t *dst; |
| 656 | 670 | ||
| 657 | - dst = s->vram_ptr + s->cirrus_blt_dstaddr; | 671 | + dst = s->vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask); |
| 672 | + | ||
| 673 | + if (BLTUNSAFE(s)) | ||
| 674 | + return 0; | ||
| 675 | + | ||
| 658 | (*s->cirrus_rop) (s, dst, src, | 676 | (*s->cirrus_rop) (s, dst, src, |
| 659 | s->cirrus_blt_dstpitch, 0, | 677 | s->cirrus_blt_dstpitch, 0, |
| 660 | s->cirrus_blt_width, s->cirrus_blt_height); | 678 | s->cirrus_blt_width, s->cirrus_blt_height); |
| @@ -670,8 +688,10 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) | @@ -670,8 +688,10 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) | ||
| 670 | { | 688 | { |
| 671 | cirrus_fill_t rop_func; | 689 | cirrus_fill_t rop_func; |
| 672 | 690 | ||
| 691 | + if (BLTUNSAFE(s)) | ||
| 692 | + return 0; | ||
| 673 | rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; | 693 | rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; |
| 674 | - rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr, | 694 | + rop_func(s, s->vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), |
| 675 | s->cirrus_blt_dstpitch, | 695 | s->cirrus_blt_dstpitch, |
| 676 | s->cirrus_blt_width, s->cirrus_blt_height); | 696 | s->cirrus_blt_width, s->cirrus_blt_height); |
| 677 | cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, | 697 | cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, |
| @@ -690,8 +710,8 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) | @@ -690,8 +710,8 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) | ||
| 690 | static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) | 710 | static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) |
| 691 | { | 711 | { |
| 692 | return cirrus_bitblt_common_patterncopy(s, | 712 | return cirrus_bitblt_common_patterncopy(s, |
| 693 | - s->vram_ptr + | ||
| 694 | - (s->cirrus_blt_srcaddr & ~7)); | 713 | + s->vram_ptr + ((s->cirrus_blt_srcaddr & ~7) & |
| 714 | + s->cirrus_addr_mask)); | ||
| 695 | } | 715 | } |
| 696 | 716 | ||
| 697 | static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) | 717 | static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) |
| @@ -741,8 +761,10 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) | @@ -741,8 +761,10 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) | ||
| 741 | if (notify) | 761 | if (notify) |
| 742 | vga_hw_update(); | 762 | vga_hw_update(); |
| 743 | 763 | ||
| 744 | - (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, | ||
| 745 | - s->vram_ptr + s->cirrus_blt_srcaddr, | 764 | + (*s->cirrus_rop) (s, s->vram_ptr + |
| 765 | + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), | ||
| 766 | + s->vram_ptr + | ||
| 767 | + (s->cirrus_blt_srcaddr & s->cirrus_addr_mask), | ||
| 746 | s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, | 768 | s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, |
| 747 | s->cirrus_blt_width, s->cirrus_blt_height); | 769 | s->cirrus_blt_width, s->cirrus_blt_height); |
| 748 | 770 | ||
| @@ -768,8 +790,14 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) | @@ -768,8 +790,14 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) | ||
| 768 | s->cirrus_blt_srcaddr - s->start_addr, | 790 | s->cirrus_blt_srcaddr - s->start_addr, |
| 769 | s->cirrus_blt_width, s->cirrus_blt_height); | 791 | s->cirrus_blt_width, s->cirrus_blt_height); |
| 770 | } else { | 792 | } else { |
| 771 | - (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, | ||
| 772 | - s->vram_ptr + s->cirrus_blt_srcaddr, | 793 | + |
| 794 | + if (BLTUNSAFE(s)) | ||
| 795 | + return 0; | ||
| 796 | + | ||
| 797 | + (*s->cirrus_rop) (s, s->vram_ptr + | ||
| 798 | + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), | ||
| 799 | + s->vram_ptr + | ||
| 800 | + (s->cirrus_blt_srcaddr & s->cirrus_addr_mask), | ||
| 773 | s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, | 801 | s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, |
| 774 | s->cirrus_blt_width, s->cirrus_blt_height); | 802 | s->cirrus_blt_width, s->cirrus_blt_height); |
| 775 | 803 | ||
| @@ -801,8 +829,9 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) | @@ -801,8 +829,9 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) | ||
| 801 | } else { | 829 | } else { |
| 802 | /* at least one scan line */ | 830 | /* at least one scan line */ |
| 803 | do { | 831 | do { |
| 804 | - (*s->cirrus_rop)(s, s->vram_ptr + s->cirrus_blt_dstaddr, | ||
| 805 | - s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); | 832 | + (*s->cirrus_rop)(s, s->vram_ptr + |
| 833 | + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), | ||
| 834 | + s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); | ||
| 806 | cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, | 835 | cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, |
| 807 | s->cirrus_blt_width, 1); | 836 | s->cirrus_blt_width, 1); |
| 808 | s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch; | 837 | s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch; |
| @@ -1920,7 +1949,7 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, | @@ -1920,7 +1949,7 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, | ||
| 1920 | unsigned val = mem_value; | 1949 | unsigned val = mem_value; |
| 1921 | uint8_t *dst; | 1950 | uint8_t *dst; |
| 1922 | 1951 | ||
| 1923 | - dst = s->vram_ptr + offset; | 1952 | + dst = s->vram_ptr + (offset &= s->cirrus_addr_mask); |
| 1924 | for (x = 0; x < 8; x++) { | 1953 | for (x = 0; x < 8; x++) { |
| 1925 | if (val & 0x80) { | 1954 | if (val & 0x80) { |
| 1926 | *dst = s->cirrus_shadow_gr1; | 1955 | *dst = s->cirrus_shadow_gr1; |
| @@ -1943,7 +1972,7 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, | @@ -1943,7 +1972,7 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, | ||
| 1943 | unsigned val = mem_value; | 1972 | unsigned val = mem_value; |
| 1944 | uint8_t *dst; | 1973 | uint8_t *dst; |
| 1945 | 1974 | ||
| 1946 | - dst = s->vram_ptr + offset; | 1975 | + dst = s->vram_ptr + (offset &= s->cirrus_addr_mask); |
| 1947 | for (x = 0; x < 8; x++) { | 1976 | for (x = 0; x < 8; x++) { |
| 1948 | if (val & 0x80) { | 1977 | if (val & 0x80) { |
| 1949 | *dst = s->cirrus_shadow_gr1; | 1978 | *dst = s->cirrus_shadow_gr1; |
hw/cirrus_vga_rop.h
| @@ -31,6 +31,12 @@ glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s, | @@ -31,6 +31,12 @@ glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s, | ||
| 31 | int x,y; | 31 | int x,y; |
| 32 | dstpitch -= bltwidth; | 32 | dstpitch -= bltwidth; |
| 33 | srcpitch -= bltwidth; | 33 | srcpitch -= bltwidth; |
| 34 | + | ||
| 35 | + if (dstpitch < 0 || srcpitch < 0) { | ||
| 36 | + /* is 0 valid? srcpitch == 0 could be useful */ | ||
| 37 | + return; | ||
| 38 | + } | ||
| 39 | + | ||
| 34 | for (y = 0; y < bltheight; y++) { | 40 | for (y = 0; y < bltheight; y++) { |
| 35 | for (x = 0; x < bltwidth; x++) { | 41 | for (x = 0; x < bltwidth; x++) { |
| 36 | ROP_OP(*dst, *src); | 42 | ROP_OP(*dst, *src); |