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