Commit b2eb849d4b1fdb6f35d5c46958c7f703cf64cfef

Authored by aurel32
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
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);