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); |