carlwgeorge / rpms / qemu

Forked from rpms/qemu a year ago
Clone
dfb8478
From: Gerd Hoffmann <kraxel@redhat.com>
dfb8478
Date: Thu, 9 Feb 2017 14:02:20 +0100
dfb8478
Subject: [PATCH] cirrus: fix patterncopy checks
dfb8478
dfb8478
The blit_region_is_unsafe checks don't work correctly for the
dfb8478
patterncopy source.  It's a fixed-sized region, which doesn't
dfb8478
depend on cirrus_blt_{width,height}.  So go do the check in
dfb8478
cirrus_bitblt_common_patterncopy instead, then tell blit_is_unsafe that
dfb8478
it doesn't need to verify the source.  Also handle the case where we
dfb8478
blit from cirrus_bitbuf correctly.
dfb8478
dfb8478
This patch replaces 5858dd1801883309bdd208d72ddb81c4e9fee30c.
dfb8478
dfb8478
Security impact:  I think for the most part error on the safe side this
dfb8478
time, refusing blits which should have been allowed.
dfb8478
dfb8478
Only exception is placing the blit source at the end of the video ram,
dfb8478
so cirrus_blt_srcaddr + 256 goes beyond the end of video memory.  But
dfb8478
even in that case I'm not fully sure this actually allows read access to
dfb8478
host memory.  To trick the commit 5858dd18 security checks one has to
dfb8478
pick very small cirrus_blt_{width,height} values, which in turn implies
dfb8478
only a fraction of the blit source will actually be used.
dfb8478
dfb8478
Cc: Wolfgang Bumiller <w.bumiller@proxmox.com>
dfb8478
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
dfb8478
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
dfb8478
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
dfb8478
Reviewed-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
dfb8478
Reviewed-by: Laurent Vivier <lvivier@redhat.com>
dfb8478
Message-id: 1486645341-5010-1-git-send-email-kraxel@redhat.com
dfb8478
(cherry picked from commit 95280c31cda79bb1d0968afc7b19a220b3a9d986)
dfb8478
---
dfb8478
 hw/display/cirrus_vga.c | 36 ++++++++++++++++++++++++++++++------
dfb8478
 1 file changed, 30 insertions(+), 6 deletions(-)
dfb8478
dfb8478
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
dfb8478
index 16f27e8..6bd13fc 100644
dfb8478
--- a/hw/display/cirrus_vga.c
dfb8478
+++ b/hw/display/cirrus_vga.c
dfb8478
@@ -683,14 +683,39 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
dfb8478
     }
dfb8478
 }
dfb8478
 
dfb8478
-static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
dfb8478
-					    const uint8_t * src)
dfb8478
+static int cirrus_bitblt_common_patterncopy(CirrusVGAState *s, bool videosrc)
dfb8478
 {
dfb8478
+    uint32_t patternsize;
dfb8478
     uint8_t *dst;
dfb8478
+    uint8_t *src;
dfb8478
 
dfb8478
     dst = s->vga.vram_ptr + s->cirrus_blt_dstaddr;
dfb8478
 
dfb8478
-    if (blit_is_unsafe(s, false, true)) {
dfb8478
+    if (videosrc) {
dfb8478
+        switch (s->vga.get_bpp(&s->vga)) {
dfb8478
+        case 8:
dfb8478
+            patternsize = 64;
dfb8478
+            break;
dfb8478
+        case 15:
dfb8478
+        case 16:
dfb8478
+            patternsize = 128;
dfb8478
+            break;
dfb8478
+        case 24:
dfb8478
+        case 32:
dfb8478
+        default:
dfb8478
+            patternsize = 256;
dfb8478
+            break;
dfb8478
+        }
dfb8478
+        s->cirrus_blt_srcaddr &= ~(patternsize - 1);
dfb8478
+        if (s->cirrus_blt_srcaddr + patternsize > s->vga.vram_size) {
dfb8478
+            return 0;
dfb8478
+        }
dfb8478
+        src = s->vga.vram_ptr + s->cirrus_blt_srcaddr;
dfb8478
+    } else {
dfb8478
+        src = s->cirrus_bltbuf;
dfb8478
+    }
dfb8478
+
dfb8478
+    if (blit_is_unsafe(s, true, true)) {
dfb8478
         return 0;
dfb8478
     }
dfb8478
 
dfb8478
@@ -731,8 +756,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
dfb8478
 
dfb8478
 static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
dfb8478
 {
dfb8478
-    return cirrus_bitblt_common_patterncopy(s, s->vga.vram_ptr +
dfb8478
-                                            (s->cirrus_blt_srcaddr & ~7));
dfb8478
+    return cirrus_bitblt_common_patterncopy(s, true);
dfb8478
 }
dfb8478
 
dfb8478
 static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
dfb8478
@@ -831,7 +855,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
dfb8478
 
dfb8478
     if (s->cirrus_srccounter > 0) {
dfb8478
         if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
dfb8478
-            cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
dfb8478
+            cirrus_bitblt_common_patterncopy(s, false);
dfb8478
         the_end:
dfb8478
             s->cirrus_srccounter = 0;
dfb8478
             cirrus_bitblt_reset(s);