Commit b2eb849d authored by Aurelien Jarno's avatar Aurelien Jarno
Browse files

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
parent cbf5c748
Loading
Loading
Loading
Loading
+42 −13
Original line number Diff line number Diff line
@@ -220,6 +220,20 @@
#define CIRRUS_HOOK_NOT_HANDLED 0
#define CIRRUS_HOOK_HANDLED 1

#define BLTUNSAFE(s) \
    ( \
        ( /* check dst is within bounds */ \
            (s)->cirrus_blt_height * (s)->cirrus_blt_dstpitch \
                + ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \
                    (s)->vram_size \
        ) || \
        ( /* check src is within bounds */ \
            (s)->cirrus_blt_height * (s)->cirrus_blt_srcpitch \
                + ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \
                    (s)->vram_size \
        ) \
    )

struct CirrusVGAState;
typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
                                     uint8_t * dst, const uint8_t * src,
@@ -639,7 +653,7 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,

    for (y = 0; y < lines; y++) {
	off_cur = off_begin;
	off_cur_end = off_cur + bytesperline;
	off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
	off_cur &= TARGET_PAGE_MASK;
	while (off_cur < off_cur_end) {
	    cpu_physical_memory_set_dirty(s->vram_offset + off_cur);
@@ -654,7 +668,11 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
{
    uint8_t *dst;

    dst = s->vram_ptr + s->cirrus_blt_dstaddr;
    dst = s->vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);

    if (BLTUNSAFE(s))
        return 0;

    (*s->cirrus_rop) (s, dst, src,
                      s->cirrus_blt_dstpitch, 0,
                      s->cirrus_blt_width, s->cirrus_blt_height);
@@ -670,8 +688,10 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
{
    cirrus_fill_t rop_func;

    if (BLTUNSAFE(s))
        return 0;
    rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
    rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr,
    rop_func(s, s->vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
             s->cirrus_blt_dstpitch,
             s->cirrus_blt_width, s->cirrus_blt_height);
    cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
@@ -690,8 +710,8 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
{
    return cirrus_bitblt_common_patterncopy(s,
					    s->vram_ptr +
                                            (s->cirrus_blt_srcaddr & ~7));
					    s->vram_ptr + ((s->cirrus_blt_srcaddr & ~7) &
                                            s->cirrus_addr_mask));
}

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)
    if (notify)
	vga_hw_update();

    (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
		      s->vram_ptr + s->cirrus_blt_srcaddr,
    (*s->cirrus_rop) (s, s->vram_ptr +
		      (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
		      s->vram_ptr +
		      (s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
		      s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
		      s->cirrus_blt_width, s->cirrus_blt_height);

@@ -768,8 +790,14 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
		       s->cirrus_blt_srcaddr - s->start_addr,
		       s->cirrus_blt_width, s->cirrus_blt_height);
    } else {
	(*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
			  s->vram_ptr + s->cirrus_blt_srcaddr,

    if (BLTUNSAFE(s))
        return 0;

	(*s->cirrus_rop) (s, s->vram_ptr +
                (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
			  s->vram_ptr +
                (s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
			  s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
			  s->cirrus_blt_width, s->cirrus_blt_height);

@@ -801,7 +829,8 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
        } else {
            /* at least one scan line */
            do {
                (*s->cirrus_rop)(s, s->vram_ptr + s->cirrus_blt_dstaddr,
                (*s->cirrus_rop)(s, s->vram_ptr +
                                 (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
                                  s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
                cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
                                         s->cirrus_blt_width, 1);
@@ -1920,7 +1949,7 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
    unsigned val = mem_value;
    uint8_t *dst;

    dst = s->vram_ptr + offset;
    dst = s->vram_ptr + (offset &= s->cirrus_addr_mask);
    for (x = 0; x < 8; x++) {
	if (val & 0x80) {
	    *dst = s->cirrus_shadow_gr1;
@@ -1943,7 +1972,7 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
    unsigned val = mem_value;
    uint8_t *dst;

    dst = s->vram_ptr + offset;
    dst = s->vram_ptr + (offset &= s->cirrus_addr_mask);
    for (x = 0; x < 8; x++) {
	if (val & 0x80) {
	    *dst = s->cirrus_shadow_gr1;
+6 −0
Original line number Diff line number Diff line
@@ -31,6 +31,12 @@ glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
    int x,y;
    dstpitch -= bltwidth;
    srcpitch -= bltwidth;

    if (dstpitch < 0 || srcpitch < 0) {
        /* is 0 valid? srcpitch == 0 could be useful */
        return;
    }

    for (y = 0; y < bltheight; y++) {
        for (x = 0; x < bltwidth; x++) {
            ROP_OP(*dst, *src);