diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-05-09 13:42:25 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-05-09 13:42:25 +0100 |
commit | 53db932604dfa7bb9241d132e0173894cf54261c (patch) | |
tree | e1c9e10a7d4db068afb8d39707f66a40340f050c | |
parent | 975eb6a547f809608ccb08c221552f666611af25 (diff) | |
parent | fd3c136b3e1482cd0ec7285d6bc2a3e6a62c38d7 (diff) |
Merge remote-tracking branch 'remotes/kraxel/tags/pull-vga-20160509-1' into staging
vga security fixes (CVE-2016-3710, CVE-2016-3712)
# gpg: Signature made Mon 09 May 2016 13:39:30 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg: aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>"
* remotes/kraxel/tags/pull-vga-20160509-1:
vga: make sure vga register setup for vbe stays intact (CVE-2016-3712).
vga: update vga register setup on vbe changes
vga: factor out vga register setup
vga: add vbe_enabled() helper
vga: fix banked access bounds checking (CVE-2016-3710)
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/display/vga.c | 122 |
1 files changed, 78 insertions, 44 deletions
diff --git a/hw/display/vga.c b/hw/display/vga.c index 657e9f196d..4a55ec6dbb 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -142,6 +142,13 @@ static uint32_t expand4[256]; static uint16_t expand2[256]; static uint8_t expand4to8[16]; +static void vbe_update_vgaregs(VGACommonState *s); + +static inline bool vbe_enabled(VGACommonState *s) +{ + return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED; +} + static void vga_update_memory_access(VGACommonState *s) { hwaddr base, offset, size; @@ -179,6 +186,7 @@ static void vga_update_memory_access(VGACommonState *s) size = 0x8000; break; } + assert(offset + size <= s->vram_size); memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram), "vga.chain4", &s->vram, offset, size); memory_region_add_subregion_overlap(s->legacy_address_space, base, @@ -478,6 +486,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("vga: write SR%x = 0x%02x\n", s->sr_index, val); #endif s->sr[s->sr_index] = val & sr_mask[s->sr_index]; + vbe_update_vgaregs(s); if (s->sr_index == VGA_SEQ_CLOCK_MODE) { s->update_retrace_info(s); } @@ -509,6 +518,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("vga: write GR%x = 0x%02x\n", s->gr_index, val); #endif s->gr[s->gr_index] = val & gr_mask[s->gr_index]; + vbe_update_vgaregs(s); vga_update_memory_access(s); break; case VGA_CRT_IM: @@ -527,10 +537,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) if (s->cr_index == VGA_CRTC_OVERFLOW) { s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) | (val & 0x10); + vbe_update_vgaregs(s); } return; } s->cr[s->cr_index] = val; + vbe_update_vgaregs(s); switch(s->cr_index) { case VGA_CRTC_H_TOTAL: @@ -563,7 +575,7 @@ static void vbe_fixup_regs(VGACommonState *s) uint16_t *r = s->vbe_regs; uint32_t bits, linelength, maxy, offset; - if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { + if (!vbe_enabled(s)) { /* vbe is turned off -- nothing to do */ return; } @@ -638,6 +650,49 @@ static void vbe_fixup_regs(VGACommonState *s) s->vbe_start_addr = offset / 4; } +/* we initialize the VGA graphic mode */ +static void vbe_update_vgaregs(VGACommonState *s) +{ + int h, shift_control; + + if (!vbe_enabled(s)) { + /* vbe is turned off -- nothing to do */ + return; + } + + /* graphic mode + memory map 1 */ + s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 | + VGA_GR06_GRAPHICS_MODE; + s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */ + s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3; + /* width */ + s->cr[VGA_CRTC_H_DISP] = + (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; + /* height (only meaningful if < 1024) */ + h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; + s->cr[VGA_CRTC_V_DISP_END] = h; + s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) | + ((h >> 7) & 0x02) | ((h >> 3) & 0x40); + /* line compare to 1023 */ + s->cr[VGA_CRTC_LINE_COMPARE] = 0xff; + s->cr[VGA_CRTC_OVERFLOW] |= 0x10; + s->cr[VGA_CRTC_MAX_SCAN] |= 0x40; + + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { + shift_control = 0; + s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */ + } else { + shift_control = 2; + /* set chain 4 mode */ + s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M; + /* activate all planes */ + s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES; + } + s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) | + (shift_control << 5); + s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */ +} + static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) { VGACommonState *s = opaque; @@ -714,13 +769,10 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) case VBE_DISPI_INDEX_Y_OFFSET: s->vbe_regs[s->vbe_index] = val; vbe_fixup_regs(s); + vbe_update_vgaregs(s); break; case VBE_DISPI_INDEX_BANK: - if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { - val &= (s->vbe_bank_mask >> 2); - } else { - val &= s->vbe_bank_mask; - } + val &= s->vbe_bank_mask; s->vbe_regs[s->vbe_index] = val; s->bank_offset = (val << 16); vga_update_memory_access(s); @@ -728,52 +780,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) case VBE_DISPI_INDEX_ENABLE: if ((val & VBE_DISPI_ENABLED) && !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { - int h, shift_control; s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0; s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0; s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0; s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED; vbe_fixup_regs(s); + vbe_update_vgaregs(s); /* clear the screen */ if (!(val & VBE_DISPI_NOCLEARMEM)) { memset(s->vram_ptr, 0, s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset); } - - /* we initialize the VGA graphic mode */ - /* graphic mode + memory map 1 */ - s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 | - VGA_GR06_GRAPHICS_MODE; - s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */ - s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3; - /* width */ - s->cr[VGA_CRTC_H_DISP] = - (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; - /* height (only meaningful if < 1024) */ - h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; - s->cr[VGA_CRTC_V_DISP_END] = h; - s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) | - ((h >> 7) & 0x02) | ((h >> 3) & 0x40); - /* line compare to 1023 */ - s->cr[VGA_CRTC_LINE_COMPARE] = 0xff; - s->cr[VGA_CRTC_OVERFLOW] |= 0x10; - s->cr[VGA_CRTC_MAX_SCAN] |= 0x40; - - if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { - shift_control = 0; - s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */ - } else { - shift_control = 2; - /* set chain 4 mode */ - s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M; - /* activate all planes */ - s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES; - } - s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) | - (shift_control << 5); - s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */ } else { s->bank_offset = 0; } @@ -819,13 +838,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr) if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) { /* chain 4 mode : simplest access */ + assert(addr < s->vram_size); ret = s->vram_ptr[addr]; } else if (s->gr[VGA_GFX_MODE] & 0x10) { /* odd/even mode (aka text mode mapping) */ plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1); - ret = s->vram_ptr[((addr & ~1) << 1) | plane]; + addr = ((addr & ~1) << 1) | plane; + if (addr >= s->vram_size) { + return 0xff; + } + ret = s->vram_ptr[addr]; } else { /* standard VGA latched access */ + if (addr * sizeof(uint32_t) >= s->vram_size) { + return 0xff; + } s->latch = ((uint32_t *)s->vram_ptr)[addr]; if (!(s->gr[VGA_GFX_MODE] & 0x08)) { @@ -882,6 +909,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) plane = addr & 3; mask = (1 << plane); if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) { + assert(addr < s->vram_size); s->vram_ptr[addr] = val; #ifdef DEBUG_VGA_MEM printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr); @@ -895,6 +923,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) mask = (1 << plane); if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) { addr = ((addr & ~1) << 1) | plane; + if (addr >= s->vram_size) { + return; + } s->vram_ptr[addr] = val; #ifdef DEBUG_VGA_MEM printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr); @@ -968,6 +999,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) mask = s->sr[VGA_SEQ_PLANE_WRITE]; s->plane_updated |= mask; /* only used to detect font change */ write_mask = mask16[mask]; + if (addr * sizeof(uint32_t) >= s->vram_size) { + return; + } ((uint32_t *)s->vram_ptr)[addr] = (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | (val & write_mask); @@ -1046,7 +1080,7 @@ static void vga_get_offsets(VGACommonState *s, { uint32_t start_addr, line_offset, line_compare; - if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + if (vbe_enabled(s)) { line_offset = s->vbe_line_offset; start_addr = s->vbe_start_addr; line_compare = 65535; @@ -1371,7 +1405,7 @@ static int vga_get_bpp(VGACommonState *s) { int ret; - if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + if (vbe_enabled(s)) { ret = s->vbe_regs[VBE_DISPI_INDEX_BPP]; } else { ret = 0; @@ -1383,7 +1417,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight) { int width, height; - if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + if (vbe_enabled(s)) { width = s->vbe_regs[VBE_DISPI_INDEX_XRES]; height = s->vbe_regs[VBE_DISPI_INDEX_YRES]; } else { |