9ae3a8
From 6febc393af5d81e2c3f6f0d2f0e5b7dd58d4974a Mon Sep 17 00:00:00 2001
9ae3a8
From: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
Date: Wed, 3 Dec 2014 09:17:55 +0100
9ae3a8
Subject: [PATCH 2/3] cirrus: fix blit region check
9ae3a8
9ae3a8
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
Message-id: <1417594676-5663-2-git-send-email-kraxel@redhat.com>
9ae3a8
O-Subject: [RHEL-7.1 qemu-kvm PATCH 1/2] cirrus: fix blit region check
9ae3a8
Bugzilla: 1169456
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
9ae3a8
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
9ae3a8
9ae3a8
Issues:
9ae3a8
 * Doesn't check pitches correctly in case it is negative.
9ae3a8
 * Doesn't check width at all.
9ae3a8
9ae3a8
Turn macro into functions while being at it, also factor out the check
9ae3a8
for one region which we then can simply call twice for src + dst.
9ae3a8
9ae3a8
This is CVE-2014-8106.
9ae3a8
9ae3a8
Reported-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
(cherry picked from commit d3532a0db02296e687711b8cdc7791924efccea0)
9ae3a8
---
9ae3a8
 hw/display/cirrus_vga.c | 61 +++++++++++++++++++++++++++++++++++--------------
9ae3a8
 1 file changed, 44 insertions(+), 17 deletions(-)
9ae3a8
9ae3a8
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
9ae3a8
index bfaa0b0..9ae8313 100644
9ae3a8
--- a/hw/display/cirrus_vga.c
9ae3a8
+++ b/hw/display/cirrus_vga.c
9ae3a8
@@ -172,20 +172,6 @@
9ae3a8
 
9ae3a8
 #define CIRRUS_PNPMMIO_SIZE         0x1000
9ae3a8
 
9ae3a8
-#define BLTUNSAFE(s) \
9ae3a8
-    ( \
9ae3a8
-        ( /* check dst is within bounds */ \
9ae3a8
-            (s)->cirrus_blt_height * ABS((s)->cirrus_blt_dstpitch) \
9ae3a8
-                + ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \
9ae3a8
-                    (s)->vga.vram_size \
9ae3a8
-        ) || \
9ae3a8
-        ( /* check src is within bounds */ \
9ae3a8
-            (s)->cirrus_blt_height * ABS((s)->cirrus_blt_srcpitch) \
9ae3a8
-                + ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \
9ae3a8
-                    (s)->vga.vram_size \
9ae3a8
-        ) \
9ae3a8
-    )
9ae3a8
-
9ae3a8
 struct CirrusVGAState;
9ae3a8
 typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
9ae3a8
                                      uint8_t * dst, const uint8_t * src,
9ae3a8
@@ -278,6 +264,46 @@ static void cirrus_update_memory_access(CirrusVGAState *s);
9ae3a8
  *
9ae3a8
  ***************************************/
9ae3a8
 
9ae3a8
+static bool blit_region_is_unsafe(struct CirrusVGAState *s,
9ae3a8
+                                  int32_t pitch, int32_t addr)
9ae3a8
+{
9ae3a8
+    if (pitch < 0) {
9ae3a8
+        int64_t min = addr
9ae3a8
+            + ((int64_t)s->cirrus_blt_height-1) * pitch;
9ae3a8
+        int32_t max = addr
9ae3a8
+            + s->cirrus_blt_width;
9ae3a8
+        if (min < 0 || max >= s->vga.vram_size) {
9ae3a8
+            return true;
9ae3a8
+        }
9ae3a8
+    } else {
9ae3a8
+        int64_t max = addr
9ae3a8
+            + ((int64_t)s->cirrus_blt_height-1) * pitch
9ae3a8
+            + s->cirrus_blt_width;
9ae3a8
+        if (max >= s->vga.vram_size) {
9ae3a8
+            return true;
9ae3a8
+        }
9ae3a8
+    }
9ae3a8
+    return false;
9ae3a8
+}
9ae3a8
+
9ae3a8
+static bool blit_is_unsafe(struct CirrusVGAState *s)
9ae3a8
+{
9ae3a8
+    /* should be the case, see cirrus_bitblt_start */
9ae3a8
+    assert(s->cirrus_blt_width > 0);
9ae3a8
+    assert(s->cirrus_blt_height > 0);
9ae3a8
+
9ae3a8
+    if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
9ae3a8
+                              s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
9ae3a8
+        return true;
9ae3a8
+    }
9ae3a8
+    if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
9ae3a8
+                              s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
9ae3a8
+        return true;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    return false;
9ae3a8
+}
9ae3a8
+
9ae3a8
 static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
9ae3a8
                                   uint8_t *dst,const uint8_t *src,
9ae3a8
                                   int dstpitch,int srcpitch,
9ae3a8
@@ -635,7 +661,7 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
9ae3a8
 
9ae3a8
     dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
9ae3a8
 
9ae3a8
-    if (BLTUNSAFE(s))
9ae3a8
+    if (blit_is_unsafe(s))
9ae3a8
         return 0;
9ae3a8
 
9ae3a8
     (*s->cirrus_rop) (s, dst, src,
9ae3a8
@@ -653,8 +679,9 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
9ae3a8
 {
9ae3a8
     cirrus_fill_t rop_func;
9ae3a8
 
9ae3a8
-    if (BLTUNSAFE(s))
9ae3a8
+    if (blit_is_unsafe(s)) {
9ae3a8
         return 0;
9ae3a8
+    }
9ae3a8
     rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
9ae3a8
     rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
9ae3a8
              s->cirrus_blt_dstpitch,
9ae3a8
@@ -751,7 +778,7 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
9ae3a8
 
9ae3a8
 static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
9ae3a8
 {
9ae3a8
-    if (BLTUNSAFE(s))
9ae3a8
+    if (blit_is_unsafe(s))
9ae3a8
         return 0;
9ae3a8
 
9ae3a8
     cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8