diff --git a/qemu.git-3d90c6254863693a6b13d918d2b8682e08bbc681.patch b/qemu.git-3d90c6254863693a6b13d918d2b8682e08bbc681.patch new file mode 100644 index 0000000..02261da --- /dev/null +++ b/qemu.git-3d90c6254863693a6b13d918d2b8682e08bbc681.patch @@ -0,0 +1,497 @@ +From 3d90c6254863693a6b13d918d2b8682e08bbc681 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 28 Aug 2017 14:29:06 +0200 +Subject: [PATCH] vga: stop passing pointers to vga_draw_line* functions + +Instead pass around the address (aka offset into vga memory). +Add vga_read_* helper functions which apply vbe_size_mask to +the address, to make sure the address stays within the valid +range, similar to the cirrus blitter fixes (commits ffaf857778 +and 026aeffcb4). + +Impact: DoS for privileged guest users. qemu crashes with +a segfault, when hitting the guard page after vga memory +allocation, while reading vga memory for display updates. + +Fixes: CVE-2017-13672 +Cc: P J P +Reported-by: David Buchanan +Signed-off-by: Gerd Hoffmann +Message-id: 20170828122906.18993-1-kraxel@redhat.com +--- + hw/display/vga-helpers.h | 202 ++++++++++++++++++++++++++--------------------- + hw/display/vga.c | 5 +- + hw/display/vga_int.h | 1 + + 3 files changed, 114 insertions(+), 94 deletions(-) + +diff --git a/hw/display/vga-helpers.h b/hw/display/vga-helpers.h +index 94f6de2..5a752b3 100644 +--- a/hw/display/vga-helpers.h ++++ b/hw/display/vga-helpers.h +@@ -95,20 +95,46 @@ static void vga_draw_glyph9(uint8_t *d, int linesize, + } while (--h); + } + ++static inline uint8_t vga_read_byte(VGACommonState *vga, uint32_t addr) ++{ ++ return vga->vram_ptr[addr & vga->vbe_size_mask]; ++} ++ ++static inline uint16_t vga_read_word_le(VGACommonState *vga, uint32_t addr) ++{ ++ uint32_t offset = addr & vga->vbe_size_mask & ~1; ++ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset); ++ return lduw_le_p(ptr); ++} ++ ++static inline uint16_t vga_read_word_be(VGACommonState *vga, uint32_t addr) ++{ ++ uint32_t offset = addr & vga->vbe_size_mask & ~1; ++ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset); ++ return lduw_be_p(ptr); ++} ++ ++static inline uint32_t vga_read_dword_le(VGACommonState *vga, uint32_t addr) ++{ ++ uint32_t offset = addr & vga->vbe_size_mask & ~3; ++ uint32_t *ptr = (uint32_t *)(vga->vram_ptr + offset); ++ return ldl_le_p(ptr); ++} ++ + /* + * 4 color mode + */ +-static void vga_draw_line2(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line2(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { + uint32_t plane_mask, *palette, data, v; + int x; + +- palette = s1->last_palette; +- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; ++ palette = vga->last_palette; ++ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; + width >>= 3; + for(x = 0; x < width; x++) { +- data = ((uint32_t *)s)[0]; ++ data = vga_read_dword_le(vga, addr); + data &= plane_mask; + v = expand2[GET_PLANE(data, 0)]; + v |= expand2[GET_PLANE(data, 2)] << 2; +@@ -124,7 +150,7 @@ static void vga_draw_line2(VGACommonState *s1, uint8_t *d, + ((uint32_t *)d)[6] = palette[(v >> 4) & 0xf]; + ((uint32_t *)d)[7] = palette[(v >> 0) & 0xf]; + d += 32; +- s += 4; ++ addr += 4; + } + } + +@@ -134,17 +160,17 @@ static void vga_draw_line2(VGACommonState *s1, uint8_t *d, + /* + * 4 color mode, dup2 horizontal + */ +-static void vga_draw_line2d2(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line2d2(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { + uint32_t plane_mask, *palette, data, v; + int x; + +- palette = s1->last_palette; +- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; ++ palette = vga->last_palette; ++ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; + width >>= 3; + for(x = 0; x < width; x++) { +- data = ((uint32_t *)s)[0]; ++ data = vga_read_dword_le(vga, addr); + data &= plane_mask; + v = expand2[GET_PLANE(data, 0)]; + v |= expand2[GET_PLANE(data, 2)] << 2; +@@ -160,24 +186,24 @@ static void vga_draw_line2d2(VGACommonState *s1, uint8_t *d, + PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); + PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); + d += 64; +- s += 4; ++ addr += 4; + } + } + + /* + * 16 color mode + */ +-static void vga_draw_line4(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line4(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { + uint32_t plane_mask, data, v, *palette; + int x; + +- palette = s1->last_palette; +- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; ++ palette = vga->last_palette; ++ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; + width >>= 3; + for(x = 0; x < width; x++) { +- data = ((uint32_t *)s)[0]; ++ data = vga_read_dword_le(vga, addr); + data &= plane_mask; + v = expand4[GET_PLANE(data, 0)]; + v |= expand4[GET_PLANE(data, 1)] << 1; +@@ -192,24 +218,24 @@ static void vga_draw_line4(VGACommonState *s1, uint8_t *d, + ((uint32_t *)d)[6] = palette[(v >> 4) & 0xf]; + ((uint32_t *)d)[7] = palette[(v >> 0) & 0xf]; + d += 32; +- s += 4; ++ addr += 4; + } + } + + /* + * 16 color mode, dup2 horizontal + */ +-static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line4d2(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { + uint32_t plane_mask, data, v, *palette; + int x; + +- palette = s1->last_palette; +- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; ++ palette = vga->last_palette; ++ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; + width >>= 3; + for(x = 0; x < width; x++) { +- data = ((uint32_t *)s)[0]; ++ data = vga_read_dword_le(vga, addr); + data &= plane_mask; + v = expand4[GET_PLANE(data, 0)]; + v |= expand4[GET_PLANE(data, 1)] << 1; +@@ -224,7 +250,7 @@ static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d, + PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); + PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); + d += 64; +- s += 4; ++ addr += 4; + } + } + +@@ -233,21 +259,21 @@ static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d, + * + * XXX: add plane_mask support (never used in standard VGA modes) + */ +-static void vga_draw_line8d2(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line8d2(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { + uint32_t *palette; + int x; + +- palette = s1->last_palette; ++ palette = vga->last_palette; + width >>= 3; + for(x = 0; x < width; x++) { +- PUT_PIXEL2(d, 0, palette[s[0]]); +- PUT_PIXEL2(d, 1, palette[s[1]]); +- PUT_PIXEL2(d, 2, palette[s[2]]); +- PUT_PIXEL2(d, 3, palette[s[3]]); ++ PUT_PIXEL2(d, 0, palette[vga_read_byte(vga, addr + 0)]); ++ PUT_PIXEL2(d, 1, palette[vga_read_byte(vga, addr + 1)]); ++ PUT_PIXEL2(d, 2, palette[vga_read_byte(vga, addr + 2)]); ++ PUT_PIXEL2(d, 3, palette[vga_read_byte(vga, addr + 3)]); + d += 32; +- s += 4; ++ addr += 4; + } + } + +@@ -256,63 +282,63 @@ static void vga_draw_line8d2(VGACommonState *s1, uint8_t *d, + * + * XXX: add plane_mask support (never used in standard VGA modes) + */ +-static void vga_draw_line8(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line8(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { + uint32_t *palette; + int x; + +- palette = s1->last_palette; ++ palette = vga->last_palette; + width >>= 3; + for(x = 0; x < width; x++) { +- ((uint32_t *)d)[0] = palette[s[0]]; +- ((uint32_t *)d)[1] = palette[s[1]]; +- ((uint32_t *)d)[2] = palette[s[2]]; +- ((uint32_t *)d)[3] = palette[s[3]]; +- ((uint32_t *)d)[4] = palette[s[4]]; +- ((uint32_t *)d)[5] = palette[s[5]]; +- ((uint32_t *)d)[6] = palette[s[6]]; +- ((uint32_t *)d)[7] = palette[s[7]]; ++ ((uint32_t *)d)[0] = palette[vga_read_byte(vga, addr + 0)]; ++ ((uint32_t *)d)[1] = palette[vga_read_byte(vga, addr + 1)]; ++ ((uint32_t *)d)[2] = palette[vga_read_byte(vga, addr + 2)]; ++ ((uint32_t *)d)[3] = palette[vga_read_byte(vga, addr + 3)]; ++ ((uint32_t *)d)[4] = palette[vga_read_byte(vga, addr + 4)]; ++ ((uint32_t *)d)[5] = palette[vga_read_byte(vga, addr + 5)]; ++ ((uint32_t *)d)[6] = palette[vga_read_byte(vga, addr + 6)]; ++ ((uint32_t *)d)[7] = palette[vga_read_byte(vga, addr + 7)]; + d += 32; +- s += 8; ++ addr += 8; + } + } + + /* + * 15 bit color + */ +-static void vga_draw_line15_le(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line15_le(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { + int w; + uint32_t v, r, g, b; + + w = width; + do { +- v = lduw_le_p((void *)s); ++ v = vga_read_word_le(vga, addr); + r = (v >> 7) & 0xf8; + g = (v >> 2) & 0xf8; + b = (v << 3) & 0xf8; + ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); +- s += 2; ++ addr += 2; + d += 4; + } while (--w != 0); + } + +-static void vga_draw_line15_be(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line15_be(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { + int w; + uint32_t v, r, g, b; + + w = width; + do { +- v = lduw_be_p((void *)s); ++ v = vga_read_word_be(vga, addr); + r = (v >> 7) & 0xf8; + g = (v >> 2) & 0xf8; + b = (v << 3) & 0xf8; + ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); +- s += 2; ++ addr += 2; + d += 4; + } while (--w != 0); + } +@@ -320,38 +346,38 @@ static void vga_draw_line15_be(VGACommonState *s1, uint8_t *d, + /* + * 16 bit color + */ +-static void vga_draw_line16_le(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line16_le(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { + int w; + uint32_t v, r, g, b; + + w = width; + do { +- v = lduw_le_p((void *)s); ++ v = vga_read_word_le(vga, addr); + r = (v >> 8) & 0xf8; + g = (v >> 3) & 0xfc; + b = (v << 3) & 0xf8; + ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); +- s += 2; ++ addr += 2; + d += 4; + } while (--w != 0); + } + +-static void vga_draw_line16_be(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line16_be(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { + int w; + uint32_t v, r, g, b; + + w = width; + do { +- v = lduw_be_p((void *)s); ++ v = vga_read_word_be(vga, addr); + r = (v >> 8) & 0xf8; + g = (v >> 3) & 0xfc; + b = (v << 3) & 0xf8; + ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); +- s += 2; ++ addr += 2; + d += 4; + } while (--w != 0); + } +@@ -359,36 +385,36 @@ static void vga_draw_line16_be(VGACommonState *s1, uint8_t *d, + /* + * 24 bit color + */ +-static void vga_draw_line24_le(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line24_le(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { + int w; + uint32_t r, g, b; + + w = width; + do { +- b = s[0]; +- g = s[1]; +- r = s[2]; ++ b = vga_read_byte(vga, addr + 0); ++ g = vga_read_byte(vga, addr + 1); ++ r = vga_read_byte(vga, addr + 2); + ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); +- s += 3; ++ addr += 3; + d += 4; + } while (--w != 0); + } + +-static void vga_draw_line24_be(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line24_be(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { + int w; + uint32_t r, g, b; + + w = width; + do { +- r = s[0]; +- g = s[1]; +- b = s[2]; ++ r = vga_read_byte(vga, addr + 0); ++ g = vga_read_byte(vga, addr + 1); ++ b = vga_read_byte(vga, addr + 2); + ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); +- s += 3; ++ addr += 3; + d += 4; + } while (--w != 0); + } +@@ -396,44 +422,36 @@ static void vga_draw_line24_be(VGACommonState *s1, uint8_t *d, + /* + * 32 bit color + */ +-static void vga_draw_line32_le(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line32_le(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { +-#ifndef HOST_WORDS_BIGENDIAN +- memcpy(d, s, width * 4); +-#else + int w; + uint32_t r, g, b; + + w = width; + do { +- b = s[0]; +- g = s[1]; +- r = s[2]; ++ b = vga_read_byte(vga, addr + 0); ++ g = vga_read_byte(vga, addr + 1); ++ r = vga_read_byte(vga, addr + 2); + ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); +- s += 4; ++ addr += 4; + d += 4; + } while (--w != 0); +-#endif + } + +-static void vga_draw_line32_be(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width) ++static void vga_draw_line32_be(VGACommonState *vga, uint8_t *d, ++ uint32_t addr, int width) + { +-#ifdef HOST_WORDS_BIGENDIAN +- memcpy(d, s, width * 4); +-#else + int w; + uint32_t r, g, b; + + w = width; + do { +- r = s[1]; +- g = s[2]; +- b = s[3]; ++ r = vga_read_byte(vga, addr + 1); ++ g = vga_read_byte(vga, addr + 2); ++ b = vga_read_byte(vga, addr + 3); + ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); +- s += 4; ++ addr += 4; + d += 4; + } while (--w != 0); +-#endif + } +diff --git a/hw/display/vga.c b/hw/display/vga.c +index ad7a465..6fc8c87 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -1005,7 +1005,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) + } + + typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d, +- const uint8_t *s, int width); ++ uint32_t srcaddr, int width); + + #include "vga-helpers.h" + +@@ -1666,7 +1666,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) + if (y_start < 0) + y_start = y; + if (!(is_buffer_shared(surface))) { +- vga_draw_line(s, d, s->vram_ptr + addr, width); ++ vga_draw_line(s, d, addr, width); + if (s->cursor_draw_line) + s->cursor_draw_line(s, d, y); + } +@@ -2170,6 +2170,7 @@ void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate) + if (!s->vbe_size) { + s->vbe_size = s->vram_size; + } ++ s->vbe_size_mask = s->vbe_size - 1; + + s->is_vbe_vmstate = 1; + memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size, +diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h +index dd6c958..ad34a1f 100644 +--- a/hw/display/vga_int.h ++++ b/hw/display/vga_int.h +@@ -94,6 +94,7 @@ typedef struct VGACommonState { + uint32_t vram_size; + uint32_t vram_size_mb; /* property */ + uint32_t vbe_size; ++ uint32_t vbe_size_mask; + uint32_t latch; + bool has_chain4_alias; + MemoryRegion chain4_alias; +-- +1.8.3.1 + diff --git a/qemu.git-e65294157d4b69393b3f819c99f4f647452b48e3.patch b/qemu.git-e65294157d4b69393b3f819c99f4f647452b48e3.patch new file mode 100644 index 0000000..53fbc88 --- /dev/null +++ b/qemu.git-e65294157d4b69393b3f819c99f4f647452b48e3.patch @@ -0,0 +1,46 @@ +From e65294157d4b69393b3f819c99f4f647452b48e3 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 28 Aug 2017 14:33:07 +0200 +Subject: [PATCH] vga: fix display update region calculation (split screen) + +vga display update mis-calculated the region for the dirty bitmap +snapshot in case split screen mode is used. This can trigger an +assert in cpu_physical_memory_snapshot_get_dirty(). + +Impact: DoS for privileged guest users. + +Fixes: CVE-2017-13673 +Fixes: fec5e8c92becad223df9d972770522f64aafdb72 +Cc: P J P +Reported-by: David Buchanan +Signed-off-by: Gerd Hoffmann +Message-id: 20170828123307.15392-1-kraxel@redhat.com +--- + hw/display/vga.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/hw/display/vga.c b/hw/display/vga.c +index 3433102..ad7a465 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -1628,9 +1628,15 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) + y1 = 0; + + if (!full_update) { ++ ram_addr_t region_start = addr1; ++ ram_addr_t region_end = addr1 + line_offset * height; + vga_sync_dirty_bitmap(s); +- snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1, +- line_offset * height, ++ if (s->line_compare < height) { ++ /* split screen mode */ ++ region_start = 0; ++ } ++ snap = memory_region_snapshot_and_clear_dirty(&s->vram, region_start, ++ region_end - region_start, + DIRTY_MEMORY_VGA); + } + +-- +1.8.3.1 + diff --git a/qemu.git-fec5e8c92becad223df9d972770522f64aafdb72.patch b/qemu.git-fec5e8c92becad223df9d972770522f64aafdb72.patch new file mode 100644 index 0000000..cabcf26 --- /dev/null +++ b/qemu.git-fec5e8c92becad223df9d972770522f64aafdb72.patch @@ -0,0 +1,114 @@ +From fec5e8c92becad223df9d972770522f64aafdb72 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 21 Apr 2017 11:16:27 +0200 +Subject: [PATCH] vga: make display updates thread safe. + +The vga code clears the dirty bits *after* reading the framebuffer +memory. So if the guest framebuffer updates hits the race window +between vga reading the framebuffer and vga clearing the dirty bits +vga will miss that update + +Fix it by using the new memory_region_copy_and_clear_dirty() +memory_region_copy_get_dirty() functions. That way we clear the +dirty bitmap before reading the framebuffer. Any guest display +updates happening in parallel will be properly tracked in the +dirty bitmap then and the next display refresh will pick them up. + +Problem triggers with mttcg only. Before mttcg was merged tcg +never ran in parallel to vga emulation. Using kvm will hide the +problem too, due to qemu operating on a userspace copy of the +kernel's dirty bitmap. + +Signed-off-by: Gerd Hoffmann +Message-id: 20170421091632.30900-5-kraxel@redhat.com +Signed-off-by: Gerd Hoffmann +--- + hw/display/vga.c | 36 +++++++++++++++++------------------- + 1 file changed, 17 insertions(+), 19 deletions(-) + +diff --git a/hw/display/vga.c b/hw/display/vga.c +index 3991b88..b2516c8 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -1465,7 +1465,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) + DisplaySurface *surface = qemu_console_surface(s->con); + int y1, y, update, linesize, y_start, double_scan, mask, depth; + int width, height, shift_control, line_offset, bwidth, bits; +- ram_addr_t page0, page1, page_min, page_max; ++ ram_addr_t page0, page1; ++ DirtyBitmapSnapshot *snap = NULL; + int disp_width, multi_scan, multi_run; + uint8_t *d; + uint32_t v, addr1, addr; +@@ -1480,9 +1481,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) + + full_update |= update_basic_params(s); + +- if (!full_update) +- vga_sync_dirty_bitmap(s); +- + s->get_resolution(s, &width, &height); + disp_width = width; + +@@ -1625,11 +1623,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) + addr1 = (s->start_addr * 4); + bwidth = (width * bits + 7) / 8; + y_start = -1; +- page_min = -1; +- page_max = 0; + d = surface_data(surface); + linesize = surface_stride(surface); + y1 = 0; ++ ++ if (!full_update) { ++ vga_sync_dirty_bitmap(s); ++ snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1, ++ line_offset * height, ++ DIRTY_MEMORY_VGA); ++ } ++ + for(y = 0; y < height; y++) { + addr = addr1; + if (!(s->cr[VGA_CRTC_MODE] & 1)) { +@@ -1644,17 +1648,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) + update = full_update; + page0 = addr; + page1 = addr + bwidth - 1; +- update |= memory_region_get_dirty(&s->vram, page0, page1 - page0, +- DIRTY_MEMORY_VGA); ++ if (full_update) { ++ update = 1; ++ } else { ++ update = memory_region_snapshot_get_dirty(&s->vram, snap, ++ page0, page1 - page0); ++ } + /* explicit invalidation for the hardware cursor */ + update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1; + if (update) { + if (y_start < 0) + y_start = y; +- if (page0 < page_min) +- page_min = page0; +- if (page1 > page_max) +- page_max = page1; + if (!(is_buffer_shared(surface))) { + vga_draw_line(s, d, s->vram_ptr + addr, width); + if (s->cursor_draw_line) +@@ -1687,13 +1691,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) + dpy_gfx_update(s->con, 0, y_start, + disp_width, y - y_start); + } +- /* reset modified pages */ +- if (page_max >= page_min) { +- memory_region_reset_dirty(&s->vram, +- page_min, +- page_max - page_min, +- DIRTY_MEMORY_VGA); +- } ++ g_free(snap); + memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4); + } + +-- +1.8.3.1 + diff --git a/xen.spec b/xen.spec index 6182480..fcd147f 100644 --- a/xen.spec +++ b/xen.spec @@ -50,7 +50,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.9.0 -Release: 10%{?dist} +Release: 11%{?dist} Group: Development/Libraries License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ @@ -128,6 +128,11 @@ Patch78: xsa231-4.9.patch Patch79: xsa232.patch Patch80: xsa233.patch Patch81: xsa234-4.9.patch +Patch82: xsa245-0001-xen-page_alloc-Cover-memory-unreserved-after-boot-in.patch +Patch83: xsa245-0002-xen-arm-Correctly-report-the-memory-region-in-the-du.patch +Patch84: qemu.git-fec5e8c92becad223df9d972770522f64aafdb72.patch +Patch85: qemu.git-e65294157d4b69393b3f819c99f4f647452b48e3.patch +Patch86: qemu.git-3d90c6254863693a6b13d918d2b8682e08bbc681.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root @@ -339,6 +344,8 @@ manage Xen virtual machines. %patch79 -p1 %patch80 -p1 %patch81 -p1 +%patch82 -p1 +%patch83 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -368,6 +375,9 @@ pushd tools/qemu-xen %patch75 -p1 %patch76 -p1 %patch77 -p1 +%patch84 -p1 +%patch85 -p1 +%patch86 -p1 popd # stubdom sources @@ -876,6 +886,12 @@ rm -rf %{buildroot} %endif %changelog +* Sun Oct 01 2017 Michael Young - 4.9.0-11 +- ARM: Some memory not scrubbed at boot [XSA-245] +- Qemu: vga: reachable assert failure during during display update + [CVE-2017-13673] (#1486591) +- Qemu: vga: OOB read access during display update [CVE-2017-13672] (#1486562) + * Tue Sep 12 2017 Michael Young - 4.9.0-10 - xen: various flaws (#1490884) Missing NUMA node parameter verification [XSA-231, CVE-2017-14316] diff --git a/xsa245-0001-xen-page_alloc-Cover-memory-unreserved-after-boot-in.patch b/xsa245-0001-xen-page_alloc-Cover-memory-unreserved-after-boot-in.patch new file mode 100644 index 0000000..2047686 --- /dev/null +++ b/xsa245-0001-xen-page_alloc-Cover-memory-unreserved-after-boot-in.patch @@ -0,0 +1,48 @@ +From a48d47febc1340f27d6c716545692641a09b414c Mon Sep 17 00:00:00 2001 +From: Julien Grall +Date: Thu, 21 Sep 2017 14:13:08 +0100 +Subject: [PATCH 1/2] xen/page_alloc: Cover memory unreserved after boot in + first_valid_mfn + +On Arm, some regions (e.g Initramfs, Dom0 Kernel...) are marked as +reserved until the hardware domain is built and they are copied into its +memory. Therefore, they will not be added in the boot allocator via +init_boot_pages. + +Instead, init_xenheap_pages will be called once the region are not used +anymore. + +Update first_valid_mfn in both init_heap_pages and init_boot_pages +(already exist) to cover all the cases. + +Signed-off-by: Julien Grall +[Adjust comment, added locking around first_valid_mfn update] +Signed-off-by: Boris Ostrovsky +--- + xen/common/page_alloc.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c +index 0b9f6cc6df..fbe5a8af39 100644 +--- a/xen/common/page_alloc.c ++++ b/xen/common/page_alloc.c +@@ -1700,6 +1700,16 @@ static void init_heap_pages( + { + unsigned long i; + ++ /* ++ * Some pages may not go through the boot allocator (e.g reserved ++ * memory at boot but released just after --- kernel, initramfs, ++ * etc.). ++ * Update first_valid_mfn to ensure those regions are covered. ++ */ ++ spin_lock(&heap_lock); ++ first_valid_mfn = min_t(unsigned long, page_to_mfn(pg), first_valid_mfn); ++ spin_unlock(&heap_lock); ++ + for ( i = 0; i < nr_pages; i++ ) + { + unsigned int nid = phys_to_nid(page_to_maddr(pg+i)); +-- +2.11.0 + diff --git a/xsa245-0002-xen-arm-Correctly-report-the-memory-region-in-the-du.patch b/xsa245-0002-xen-arm-Correctly-report-the-memory-region-in-the-du.patch new file mode 100644 index 0000000..cd4d270 --- /dev/null +++ b/xsa245-0002-xen-arm-Correctly-report-the-memory-region-in-the-du.patch @@ -0,0 +1,73 @@ +From cbfcf039d0e0b6f4c4cb3de612f7bf788a0c47cd Mon Sep 17 00:00:00 2001 +From: Julien Grall +Date: Mon, 18 Sep 2017 14:24:08 +0100 +Subject: [PATCH 2/2] xen/arm: Correctly report the memory region in the dummy + NUMA helpers + +NUMA is currently not supported on Arm. Because common code is +NUMA-aware, dummy helpers are instead provided to expose a single node. + +Those helpers are for instance used to know the region to scrub. + +However the memory region is not reported correctly. Indeed, the +frametable may not be at the beginning of the memory and there might be +multiple memory banks. This will lead to not scrub some part of the +memory. + +The memory information can be found using: + * first_valid_mfn as the start of the memory + * max_page - first_valid_mfn as the spanned pages + +Note that first_valid_mfn is now been exported. The prototype has been +added in asm-arm/numa.h and not in a common header because I would +expect the variable to become static once NUMA is fully supported on +Arm. + +Signed-off-by: Julien Grall +--- + xen/common/page_alloc.c | 6 +++++- + xen/include/asm-arm/numa.h | 10 ++++++++-- + 2 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c +index fbe5a8af39..472c6fe329 100644 +--- a/xen/common/page_alloc.c ++++ b/xen/common/page_alloc.c +@@ -192,7 +192,11 @@ PAGE_LIST_HEAD(page_broken_list); + * BOOT-TIME ALLOCATOR + */ + +-static unsigned long __initdata first_valid_mfn = ~0UL; ++/* ++ * first_valid_mfn is exported because it is use in ARM specific NUMA ++ * helpers. See comment in asm-arm/numa.h. ++ */ ++unsigned long first_valid_mfn = ~0UL; + + static struct bootmem_region { + unsigned long s, e; /* MFNs @s through @e-1 inclusive are free */ +diff --git a/xen/include/asm-arm/numa.h b/xen/include/asm-arm/numa.h +index a2c1a3476d..3e7384da9e 100644 +--- a/xen/include/asm-arm/numa.h ++++ b/xen/include/asm-arm/numa.h +@@ -12,9 +12,15 @@ static inline __attribute__((pure)) nodeid_t phys_to_nid(paddr_t addr) + return 0; + } + ++/* ++ * TODO: make first_valid_mfn static when NUMA is supported on Arm, this ++ * is required because the dummy helpers is using it. ++ */ ++extern unsigned long first_valid_mfn; ++ + /* XXX: implement NUMA support */ +-#define node_spanned_pages(nid) (total_pages) +-#define node_start_pfn(nid) (pdx_to_pfn(frametable_base_pdx)) ++#define node_spanned_pages(nid) (max_page - first_valid_mfn) ++#define node_start_pfn(nid) (first_valid_mfn) + #define __node_distance(a, b) (20) + + static inline unsigned int arch_get_dma_bitsize(void) +-- +2.11.0 +