]>
Commit | Line | Data |
---|---|---|
3dcc8d3b | 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
c53dfb57 WB |
2 | From: Gerd Hoffmann <kraxel@redhat.com> |
3 | Date: Tue, 10 Oct 2017 16:13:22 +0200 | |
3dcc8d3b | 4 | Subject: [PATCH] vga: handle cirrus vbe mode wraparounds. |
c53dfb57 WB |
5 | |
6 | Commit "3d90c62548 vga: stop passing pointers to vga_draw_line* | |
7 | functions" is incomplete. It doesn't handle the case that the vga | |
8 | rendering code tries to create a shared surface, i.e. a pixman image | |
9 | backed by vga video memory. That can not work in case the guest display | |
10 | wraps from end of video memory to the start. So force shadowing in that | |
11 | case. Also adjust the snapshot region calculation. | |
12 | ||
13 | Can trigger with cirrus only, when programming vbe modes using the bochs | |
14 | api (stdvga, also qxl and virtio-vga in vga compat mode) wrap arounds | |
15 | can't happen. | |
16 | ||
17 | Fixes: CVE-2017-13672 | |
18 | Fixes: 3d90c6254863693a6b13d918d2b8682e08bbc681 | |
19 | Cc: P J P <ppandit@redhat.com> | |
20 | Reported-by: David Buchanan <d@vidbuchanan.co.uk> | |
21 | Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> | |
22 | Message-id: 20171010141323.14049-3-kraxel@redhat.com | |
23 | --- | |
24 | hw/display/vga.c | 28 +++++++++++++++++++++------- | |
25 | 1 file changed, 21 insertions(+), 7 deletions(-) | |
26 | ||
27 | diff --git a/hw/display/vga.c b/hw/display/vga.c | |
28 | index 77af807a51..7bdbf7441e 100644 | |
29 | --- a/hw/display/vga.c | |
30 | +++ b/hw/display/vga.c | |
31 | @@ -1465,13 +1465,13 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) | |
32 | DisplaySurface *surface = qemu_console_surface(s->con); | |
33 | int y1, y, update, linesize, y_start, double_scan, mask, depth; | |
34 | int width, height, shift_control, bwidth, bits; | |
35 | - ram_addr_t page0, page1; | |
36 | + ram_addr_t page0, page1, region_start, region_end; | |
37 | DirtyBitmapSnapshot *snap = NULL; | |
38 | int disp_width, multi_scan, multi_run; | |
39 | uint8_t *d; | |
40 | uint32_t v, addr1, addr; | |
41 | vga_draw_line_func *vga_draw_line = NULL; | |
42 | - bool share_surface; | |
43 | + bool share_surface, force_shadow = false; | |
44 | pixman_format_code_t format; | |
45 | #ifdef HOST_WORDS_BIGENDIAN | |
46 | bool byteswap = !s->big_endian_fb; | |
47 | @@ -1484,6 +1484,15 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) | |
48 | s->get_resolution(s, &width, &height); | |
49 | disp_width = width; | |
50 | ||
51 | + region_start = (s->start_addr * 4); | |
52 | + region_end = region_start + s->line_offset * height; | |
53 | + if (region_end > s->vbe_size) { | |
54 | + /* wraps around (can happen with cirrus vbe modes) */ | |
55 | + region_start = 0; | |
56 | + region_end = s->vbe_size; | |
57 | + force_shadow = true; | |
58 | + } | |
59 | + | |
60 | shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3; | |
61 | double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7); | |
62 | if (shift_control != 1) { | |
63 | @@ -1523,7 +1532,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) | |
64 | format = qemu_default_pixman_format(depth, !byteswap); | |
65 | if (format) { | |
66 | share_surface = dpy_gfx_check_format(s->con, format) | |
67 | - && !s->force_shadow; | |
68 | + && !s->force_shadow && !force_shadow; | |
69 | } else { | |
70 | share_surface = false; | |
71 | } | |
72 | @@ -1627,8 +1636,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) | |
73 | y1 = 0; | |
74 | ||
75 | if (!full_update) { | |
76 | - ram_addr_t region_start = addr1; | |
77 | - ram_addr_t region_end = addr1 + s->line_offset * height; | |
78 | vga_sync_dirty_bitmap(s); | |
79 | if (s->line_compare < height) { | |
80 | /* split screen mode */ | |
81 | @@ -1651,10 +1658,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) | |
82 | addr = (addr & ~0x8000) | ((y1 & 2) << 14); | |
83 | } | |
84 | update = full_update; | |
85 | - page0 = addr; | |
86 | - page1 = addr + bwidth - 1; | |
87 | + page0 = addr & s->vbe_size_mask; | |
88 | + page1 = (addr + bwidth - 1) & s->vbe_size_mask; | |
89 | if (full_update) { | |
90 | update = 1; | |
91 | + } else if (page1 < page0) { | |
92 | + /* scanline wraps from end of video memory to the start */ | |
93 | + assert(force_shadow); | |
94 | + update = memory_region_snapshot_get_dirty(&s->vram, snap, | |
95 | + page0, 0); | |
96 | + update |= memory_region_snapshot_get_dirty(&s->vram, snap, | |
97 | + page1, 0); | |
98 | } else { | |
99 | update = memory_region_snapshot_get_dirty(&s->vram, snap, | |
100 | page0, page1 - page0); | |
101 | -- | |
102 | 2.11.0 | |
103 |