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 | 220 | #define CIRRUS_HOOK_NOT_HANDLED 0 |
221 | 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 | 237 | struct CirrusVGAState; |
224 | 238 | typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s, |
225 | 239 | uint8_t * dst, const uint8_t * src, |
... | ... | @@ -639,7 +653,7 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin, |
639 | 653 | |
640 | 654 | for (y = 0; y < lines; y++) { |
641 | 655 | off_cur = off_begin; |
642 | - off_cur_end = off_cur + bytesperline; | |
656 | + off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask; | |
643 | 657 | off_cur &= TARGET_PAGE_MASK; |
644 | 658 | while (off_cur < off_cur_end) { |
645 | 659 | cpu_physical_memory_set_dirty(s->vram_offset + off_cur); |
... | ... | @@ -654,7 +668,11 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, |
654 | 668 | { |
655 | 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 | 676 | (*s->cirrus_rop) (s, dst, src, |
659 | 677 | s->cirrus_blt_dstpitch, 0, |
660 | 678 | s->cirrus_blt_width, s->cirrus_blt_height); |
... | ... | @@ -670,8 +688,10 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) |
670 | 688 | { |
671 | 689 | cirrus_fill_t rop_func; |
672 | 690 | |
691 | + if (BLTUNSAFE(s)) | |
692 | + return 0; | |
673 | 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 | 695 | s->cirrus_blt_dstpitch, |
676 | 696 | s->cirrus_blt_width, s->cirrus_blt_height); |
677 | 697 | cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, |
... | ... | @@ -690,8 +710,8 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) |
690 | 710 | static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) |
691 | 711 | { |
692 | 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 | 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 | 761 | if (notify) |
742 | 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 | 768 | s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, |
747 | 769 | s->cirrus_blt_width, s->cirrus_blt_height); |
748 | 770 | |
... | ... | @@ -768,8 +790,14 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) |
768 | 790 | s->cirrus_blt_srcaddr - s->start_addr, |
769 | 791 | s->cirrus_blt_width, s->cirrus_blt_height); |
770 | 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 | 801 | s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, |
774 | 802 | s->cirrus_blt_width, s->cirrus_blt_height); |
775 | 803 | |
... | ... | @@ -801,8 +829,9 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) |
801 | 829 | } else { |
802 | 830 | /* at least one scan line */ |
803 | 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 | 835 | cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, |
807 | 836 | s->cirrus_blt_width, 1); |
808 | 837 | s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch; |
... | ... | @@ -1920,7 +1949,7 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, |
1920 | 1949 | unsigned val = mem_value; |
1921 | 1950 | uint8_t *dst; |
1922 | 1951 | |
1923 | - dst = s->vram_ptr + offset; | |
1952 | + dst = s->vram_ptr + (offset &= s->cirrus_addr_mask); | |
1924 | 1953 | for (x = 0; x < 8; x++) { |
1925 | 1954 | if (val & 0x80) { |
1926 | 1955 | *dst = s->cirrus_shadow_gr1; |
... | ... | @@ -1943,7 +1972,7 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, |
1943 | 1972 | unsigned val = mem_value; |
1944 | 1973 | uint8_t *dst; |
1945 | 1974 | |
1946 | - dst = s->vram_ptr + offset; | |
1975 | + dst = s->vram_ptr + (offset &= s->cirrus_addr_mask); | |
1947 | 1976 | for (x = 0; x < 8; x++) { |
1948 | 1977 | if (val & 0x80) { |
1949 | 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 | 31 | int x,y; |
32 | 32 | dstpitch -= bltwidth; |
33 | 33 | srcpitch -= bltwidth; |
34 | + | |
35 | + if (dstpitch < 0 || srcpitch < 0) { | |
36 | + /* is 0 valid? srcpitch == 0 could be useful */ | |
37 | + return; | |
38 | + } | |
39 | + | |
34 | 40 | for (y = 0; y < bltheight; y++) { |
35 | 41 | for (x = 0; x < bltwidth; x++) { |
36 | 42 | ROP_OP(*dst, *src); | ... | ... |