Blame SOURCES/kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch

9bac43
From cb36a048eaf475d3184e5fbecfa669d5d645f943 Mon Sep 17 00:00:00 2001
9bac43
From: Gerd Hoffmann <kraxel@redhat.com>
9bac43
Date: Fri, 20 Oct 2017 07:19:24 +0200
9bac43
Subject: [PATCH 02/19] vga: handle cirrus vbe mode wraparounds.
9bac43
9bac43
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
9bac43
Message-id: <20171020071925.9483-4-kraxel@redhat.com>
9bac43
Patchwork-id: 77391
9bac43
O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 3/4] vga: handle cirrus vbe mode wraparounds.
9bac43
Bugzilla: 1501301
9bac43
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
9bac43
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
9bac43
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
9bac43
9bac43
Commit "3d90c62548 vga: stop passing pointers to vga_draw_line*
9bac43
functions" is incomplete.  It doesn't handle the case that the vga
9bac43
rendering code tries to create a shared surface, i.e. a pixman image
9bac43
backed by vga video memory.  That can not work in case the guest display
9bac43
wraps from end of video memory to the start.  So force shadowing in that
9bac43
case.  Also adjust the snapshot region calculation.
9bac43
9bac43
Can trigger with cirrus only, when programming vbe modes using the bochs
9bac43
api (stdvga, also qxl and virtio-vga in vga compat mode) wrap arounds
9bac43
can't happen.
9bac43
9bac43
Fixes: CVE-2017-13672
9bac43
Fixes: 3d90c6254863693a6b13d918d2b8682e08bbc681
9bac43
Cc: P J P <ppandit@redhat.com>
9bac43
Reported-by: David Buchanan <d@vidbuchanan.co.uk>
9bac43
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
9bac43
Message-id: 20171010141323.14049-3-kraxel@redhat.com
9bac43
(cherry picked from commit 28f77de26a4f9995458ddeb9d34bb06c0193bdc9)
9bac43
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9bac43
---
9bac43
 hw/display/vga.c | 28 +++++++++++++++++++++-------
9bac43
 1 file changed, 21 insertions(+), 7 deletions(-)
9bac43
9bac43
diff --git a/hw/display/vga.c b/hw/display/vga.c
9bac43
index 895e95c..06ca3da 100644
9bac43
--- a/hw/display/vga.c
9bac43
+++ b/hw/display/vga.c
9bac43
@@ -1465,13 +1465,13 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
9bac43
     DisplaySurface *surface = qemu_console_surface(s->con);
9bac43
     int y1, y, update, linesize, y_start, double_scan, mask, depth;
9bac43
     int width, height, shift_control, bwidth, bits;
9bac43
-    ram_addr_t page0, page1;
9bac43
+    ram_addr_t page0, page1, region_start, region_end;
9bac43
     DirtyBitmapSnapshot *snap = NULL;
9bac43
     int disp_width, multi_scan, multi_run;
9bac43
     uint8_t *d;
9bac43
     uint32_t v, addr1, addr;
9bac43
     vga_draw_line_func *vga_draw_line = NULL;
9bac43
-    bool share_surface;
9bac43
+    bool share_surface, force_shadow = false;
9bac43
     pixman_format_code_t format;
9bac43
 #ifdef HOST_WORDS_BIGENDIAN
9bac43
     bool byteswap = !s->big_endian_fb;
9bac43
@@ -1484,6 +1484,15 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
9bac43
     s->get_resolution(s, &width, &height);
9bac43
     disp_width = width;
9bac43
 
9bac43
+    region_start = (s->start_addr * 4);
9bac43
+    region_end = region_start + s->line_offset * height;
9bac43
+    if (region_end > s->vbe_size) {
9bac43
+        /* wraps around (can happen with cirrus vbe modes) */
9bac43
+        region_start = 0;
9bac43
+        region_end = s->vbe_size;
9bac43
+        force_shadow = true;
9bac43
+    }
9bac43
+
9bac43
     shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
9bac43
     double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
9bac43
     if (shift_control != 1) {
9bac43
@@ -1523,7 +1532,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
9bac43
     format = qemu_default_pixman_format(depth, !byteswap);
9bac43
     if (format) {
9bac43
         share_surface = dpy_gfx_check_format(s->con, format)
9bac43
-            && !s->force_shadow;
9bac43
+            && !s->force_shadow && !force_shadow;
9bac43
     } else {
9bac43
         share_surface = false;
9bac43
     }
9bac43
@@ -1627,8 +1636,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
9bac43
     y1 = 0;
9bac43
 
9bac43
     if (!full_update) {
9bac43
-        ram_addr_t region_start = addr1;
9bac43
-        ram_addr_t region_end = addr1 + s->line_offset * height;
9bac43
         vga_sync_dirty_bitmap(s);
9bac43
         if (s->line_compare < height) {
9bac43
             /* split screen mode */
9bac43
@@ -1651,10 +1658,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
9bac43
             addr = (addr & ~0x8000) | ((y1 & 2) << 14);
9bac43
         }
9bac43
         update = full_update;
9bac43
-        page0 = addr;
9bac43
-        page1 = addr + bwidth - 1;
9bac43
+        page0 = addr & s->vbe_size_mask;
9bac43
+        page1 = (addr + bwidth - 1) & s->vbe_size_mask;
9bac43
         if (full_update) {
9bac43
             update = 1;
9bac43
+        } else if (page1 < page0) {
9bac43
+            /* scanline wraps from end of video memory to the start */
9bac43
+            assert(force_shadow);
9bac43
+            update = memory_region_snapshot_get_dirty(&s->vram, snap,
9bac43
+                                                      page0, 0);
9bac43
+            update |= memory_region_snapshot_get_dirty(&s->vram, snap,
9bac43
+                                                       page1, 0);
9bac43
         } else {
9bac43
             update = memory_region_snapshot_get_dirty(&s->vram, snap,
9bac43
                                                       page0, page1 - page0);
9bac43
-- 
9bac43
1.8.3.1
9bac43