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

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