|
|
5d360b |
From 90ded2892509c6c62140b907c7d036964cf312d5 Mon Sep 17 00:00:00 2001
|
|
|
12e206 |
From: Gerd Hoffmann <kraxel@redhat.com>
|
|
|
12e206 |
Date: Fri, 20 Oct 2017 11:06:18 +0200
|
|
|
5d360b |
Subject: [PATCH 3/7] vga: handle cirrus vbe mode wraparounds.
|
|
|
12e206 |
|
|
|
12e206 |
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
|
|
|
12e206 |
Message-id: <20171020110619.2541-11-kraxel@redhat.com>
|
|
|
12e206 |
Patchwork-id: 77404
|
|
|
12e206 |
O-Subject: [RHEL-7.5 qemu-kvm PATCH 10/11] vga: handle cirrus vbe mode wraparounds.
|
|
|
5d360b |
Bugzilla: 1501295
|
|
|
12e206 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
12e206 |
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
|
|
12e206 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
12e206 |
|
|
|
12e206 |
Commit "3d90c62548 vga: stop passing pointers to vga_draw_line*
|
|
|
12e206 |
functions" is incomplete. It doesn't handle the case that the vga
|
|
|
12e206 |
rendering code tries to create a shared surface, i.e. a pixman image
|
|
|
12e206 |
backed by vga video memory. That can not work in case the guest display
|
|
|
12e206 |
wraps from end of video memory to the start. So force shadowing in that
|
|
|
12e206 |
case. Also adjust the snapshot region calculation.
|
|
|
12e206 |
|
|
|
12e206 |
Can trigger with cirrus only, when programming vbe modes using the bochs
|
|
|
12e206 |
api (stdvga, also qxl and virtio-vga in vga compat mode) wrap arounds
|
|
|
12e206 |
can't happen.
|
|
|
12e206 |
|
|
|
12e206 |
Fixes: CVE-2017-13672
|
|
|
12e206 |
Fixes: 3d90c6254863693a6b13d918d2b8682e08bbc681
|
|
|
12e206 |
Cc: P J P <ppandit@redhat.com>
|
|
|
12e206 |
Reported-by: David Buchanan <d@vidbuchanan.co.uk>
|
|
|
12e206 |
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
|
|
12e206 |
Message-id: 20171010141323.14049-3-kraxel@redhat.com
|
|
|
12e206 |
(cherry picked from commit 28f77de26a4f9995458ddeb9d34bb06c0193bdc9)
|
|
|
12e206 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
12e206 |
---
|
|
|
12e206 |
hw/display/vga.c | 31 ++++++++++++++++++++++++-------
|
|
|
12e206 |
1 file changed, 24 insertions(+), 7 deletions(-)
|
|
|
12e206 |
|
|
|
12e206 |
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
|
|
12e206 |
index a343a0a..c40744f 100644
|
|
|
12e206 |
--- a/hw/display/vga.c
|
|
|
12e206 |
+++ b/hw/display/vga.c
|
|
|
12e206 |
@@ -1505,12 +1505,12 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
|
|
12e206 |
DisplaySurface *surface = qemu_console_surface(s->con);
|
|
|
12e206 |
int y1, y, update, linesize, y_start, double_scan, mask, depth;
|
|
|
12e206 |
int width, height, shift_control, bwidth, bits;
|
|
|
12e206 |
- ram_addr_t page0, page1, page_min, page_max;
|
|
|
12e206 |
+ ram_addr_t page0, page1, page_min, page_max, region_start, region_end;
|
|
|
12e206 |
int disp_width, multi_scan, multi_run;
|
|
|
12e206 |
uint8_t *d;
|
|
|
12e206 |
uint32_t v, addr1, addr;
|
|
|
12e206 |
vga_draw_line_func *vga_draw_line;
|
|
|
12e206 |
- bool share_surface;
|
|
|
12e206 |
+ bool share_surface, force_shadow = false;
|
|
|
12e206 |
#if defined(TARGET_WORDS_BIGENDIAN)
|
|
|
12e206 |
static const bool big_endian_fb = true;
|
|
|
12e206 |
#else
|
|
|
12e206 |
@@ -1530,6 +1530,15 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
|
|
12e206 |
s->get_resolution(s, &width, &height);
|
|
|
12e206 |
disp_width = width;
|
|
|
12e206 |
|
|
|
12e206 |
+ region_start = (s->start_addr * 4);
|
|
|
12e206 |
+ region_end = region_start + s->line_offset * height;
|
|
|
12e206 |
+ if (region_end > s->vbe_size) {
|
|
|
12e206 |
+ /* wraps around (can happen with cirrus vbe modes) */
|
|
|
12e206 |
+ region_start = 0;
|
|
|
12e206 |
+ region_end = s->vbe_size;
|
|
|
12e206 |
+ force_shadow = true;
|
|
|
12e206 |
+ }
|
|
|
12e206 |
+
|
|
|
12e206 |
shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
|
|
|
12e206 |
double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
|
|
|
12e206 |
if (shift_control != 1) {
|
|
|
12e206 |
@@ -1560,7 +1569,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
|
|
12e206 |
|
|
|
12e206 |
depth = s->get_bpp(s);
|
|
|
12e206 |
|
|
|
12e206 |
- share_surface = (!s->force_shadow) &&
|
|
|
12e206 |
+ share_surface = (!s->force_shadow) && !force_shadow &&
|
|
|
12e206 |
( depth == 32 || (depth == 16 && !byteswap) );
|
|
|
12e206 |
if (s->line_offset != s->last_line_offset ||
|
|
|
12e206 |
disp_width != s->last_width ||
|
|
|
12e206 |
@@ -1680,10 +1689,18 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
|
|
12e206 |
addr = (addr & ~0x8000) | ((y1 & 2) << 14);
|
|
|
12e206 |
}
|
|
|
12e206 |
update = full_update;
|
|
|
12e206 |
- page0 = addr;
|
|
|
12e206 |
- page1 = addr + bwidth - 1;
|
|
|
12e206 |
- update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
|
|
|
12e206 |
- DIRTY_MEMORY_VGA);
|
|
|
12e206 |
+ page0 = addr & s->vbe_size_mask;
|
|
|
12e206 |
+ page1 = (addr + bwidth - 1) & s->vbe_size_mask;
|
|
|
12e206 |
+ if (page1 < page0) {
|
|
|
12e206 |
+ /* scanline wraps from end of video memory to the start */
|
|
|
12e206 |
+ update |= memory_region_get_dirty(&s->vram, page0, 0,
|
|
|
12e206 |
+ DIRTY_MEMORY_VGA);
|
|
|
12e206 |
+ update |= memory_region_get_dirty(&s->vram, page1, 0,
|
|
|
12e206 |
+ DIRTY_MEMORY_VGA);
|
|
|
12e206 |
+ } else {
|
|
|
12e206 |
+ update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
|
|
|
12e206 |
+ DIRTY_MEMORY_VGA);
|
|
|
12e206 |
+ }
|
|
|
12e206 |
/* explicit invalidation for the hardware cursor */
|
|
|
12e206 |
update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
|
|
|
12e206 |
if (update) {
|
|
|
12e206 |
--
|
|
|
12e206 |
1.8.3.1
|
|
|
12e206 |
|