619821
From 8ce7227f70248c7f4926124e16baab74c5689841 Mon Sep 17 00:00:00 2001
4f5da8
From: Gerd Hoffmann <kraxel@redhat.com>
4f5da8
Date: Fri, 10 Feb 2017 08:30:13 +0100
4f5da8
Subject: [PATCH 1/3] cirrus: fix patterncopy checks
4f5da8
4f5da8
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
4f5da8
Message-id: <1486715415-3462-2-git-send-email-kraxel@redhat.com>
4f5da8
Patchwork-id: 73775
4f5da8
O-Subject: [virt-devel] [RHEL-7.4 qemu-kvm PATCH 1/3] cirrus: fix patterncopy checks
619821
Bugzilla: 1420492
4f5da8
CVE: CVE-2017-2620/20170221
4f5da8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
4f5da8
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
4f5da8
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
4f5da8
4f5da8
The blit_region_is_unsafe checks don't work correctly for the
4f5da8
patterncopy source.  It's a fixed-sized region, which doesn't
4f5da8
depend on cirrus_blt_{width,height}.  So go do the check in
4f5da8
cirrus_bitblt_common_patterncopy instead, then tell blit_is_unsafe that
4f5da8
it doesn't need to verify the source.  Also handle the case where we
4f5da8
blit from cirrus_bitbuf correctly.
4f5da8
4f5da8
This patch replaces 5858dd1801883309bdd208d72ddb81c4e9fee30c.
4f5da8
4f5da8
Security impact:  I think for the most part error on the safe side this
4f5da8
time, refusing blits which should have been allowed.
4f5da8
4f5da8
Only exception is placing the blit source at the end of the video ram,
4f5da8
so cirrus_blt_srcaddr + 256 goes beyond the end of video memory.  But
4f5da8
even in that case I'm not fully sure this actually allows read access to
4f5da8
host memory.  To trick the commit 5858dd18 security checks one has to
4f5da8
pick very small cirrus_blt_{width,height} values, which in turn implies
4f5da8
only a fraction of the blit source will actually be used.
4f5da8
4f5da8
Cc: Wolfgang Bumiller <w.bumiller@proxmox.com>
4f5da8
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
4f5da8
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
4f5da8
4f5da8
Upstream: WIP (https://patchwork.ozlabs.org/patch/726080/)
4f5da8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
4f5da8
---
4f5da8
 hw/display/cirrus_vga.c | 36 ++++++++++++++++++++++++++++++------
4f5da8
 1 file changed, 30 insertions(+), 6 deletions(-)
4f5da8
4f5da8
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
4f5da8
index e0e39ef..fff9bf0 100644
4f5da8
--- a/hw/display/cirrus_vga.c
4f5da8
+++ b/hw/display/cirrus_vga.c
4f5da8
@@ -678,14 +678,39 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
4f5da8
     }
4f5da8
 }
4f5da8
 
4f5da8
-static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
4f5da8
-					    const uint8_t * src)
4f5da8
+static int cirrus_bitblt_common_patterncopy(CirrusVGAState *s, bool videosrc)
4f5da8
 {
4f5da8
+    uint32_t patternsize;
4f5da8
     uint8_t *dst;
4f5da8
+    uint8_t *src;
4f5da8
 
4f5da8
     dst = s->vga.vram_ptr + s->cirrus_blt_dstaddr;
4f5da8
 
4f5da8
-    if (blit_is_unsafe(s, false, true)) {
4f5da8
+    if (videosrc) {
4f5da8
+        switch (s->vga.get_bpp(&s->vga)) {
4f5da8
+        case 8:
4f5da8
+            patternsize = 64;
4f5da8
+            break;
4f5da8
+        case 15:
4f5da8
+        case 16:
4f5da8
+            patternsize = 128;
4f5da8
+            break;
4f5da8
+        case 24:
4f5da8
+        case 32:
4f5da8
+        default:
4f5da8
+            patternsize = 256;
4f5da8
+            break;
4f5da8
+        }
4f5da8
+        s->cirrus_blt_srcaddr &= ~(patternsize - 1);
4f5da8
+        if (s->cirrus_blt_srcaddr + patternsize > s->vga.vram_size) {
4f5da8
+            return 0;
4f5da8
+        }
4f5da8
+        src = s->vga.vram_ptr + s->cirrus_blt_srcaddr;
4f5da8
+    } else {
4f5da8
+        src = s->cirrus_bltbuf;
4f5da8
+    }
4f5da8
+
4f5da8
+    if (blit_is_unsafe(s, true, true)) {
4f5da8
         return 0;
4f5da8
     }
4f5da8
 
4f5da8
@@ -726,8 +751,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
4f5da8
 
4f5da8
 static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
4f5da8
 {
4f5da8
-    return cirrus_bitblt_common_patterncopy(s, s->vga.vram_ptr +
4f5da8
-                                            (s->cirrus_blt_srcaddr & ~7));
4f5da8
+    return cirrus_bitblt_common_patterncopy(s, true);
4f5da8
 }
4f5da8
 
4f5da8
 static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
4f5da8
@@ -826,7 +850,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
4f5da8
 
4f5da8
     if (s->cirrus_srccounter > 0) {
4f5da8
         if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
4f5da8
-            cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
4f5da8
+            cirrus_bitblt_common_patterncopy(s, false);
4f5da8
         the_end:
4f5da8
             s->cirrus_srccounter = 0;
4f5da8
             cirrus_bitblt_reset(s);
4f5da8
-- 
4f5da8
1.8.3.1
4f5da8