carlwgeorge / rpms / qemu

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