[Xen-devel] [PATCH 08/32] CVE-2014-3615: vbe: rework sanity checks
Backport of qemu-upstream: * c1b886c45dc70f247300f549dce9833f3fa2def5 Signed-off-by: Andrew Cooper andrew.coop...@citrix.com --- hw/vga.c | 154 ++ 1 file changed, 95 insertions(+), 59 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index d0c12aa..e8b1ce0 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -521,6 +521,93 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) } #ifdef CONFIG_BOCHS_VBE +/* + * Sanity check vbe register writes. + * + * As we don't have a way to signal errors to the guest in the bochs + * dispi interface we'll go adjust the registers to the closest valid + * value. + */ +static void vbe_fixup_regs(VGAState *s) +{ +uint16_t *r = s-vbe_regs; +uint32_t bits, linelength, maxy, offset; + +if (!(r[VBE_DISPI_INDEX_ENABLE] VBE_DISPI_ENABLED)) { +/* vbe is turned off -- nothing to do */ +return; +} + +/* check depth */ +switch (r[VBE_DISPI_INDEX_BPP]) { +case 4: +case 8: +case 16: +case 24: +case 32: +bits = r[VBE_DISPI_INDEX_BPP]; +break; +case 15: +bits = 16; +break; +default: +bits = r[VBE_DISPI_INDEX_BPP] = 8; +break; +} + +/* check width */ +r[VBE_DISPI_INDEX_XRES] = ~7u; +if (r[VBE_DISPI_INDEX_XRES] == 0) { +r[VBE_DISPI_INDEX_XRES] = 8; +} +if (r[VBE_DISPI_INDEX_XRES] VBE_DISPI_MAX_XRES) { +r[VBE_DISPI_INDEX_XRES] = VBE_DISPI_MAX_XRES; +} +r[VBE_DISPI_INDEX_VIRT_WIDTH] = ~7u; +if (r[VBE_DISPI_INDEX_VIRT_WIDTH] VBE_DISPI_MAX_XRES) { +r[VBE_DISPI_INDEX_VIRT_WIDTH] = VBE_DISPI_MAX_XRES; +} +if (r[VBE_DISPI_INDEX_VIRT_WIDTH] r[VBE_DISPI_INDEX_XRES]) { +r[VBE_DISPI_INDEX_VIRT_WIDTH] = r[VBE_DISPI_INDEX_XRES]; +} + +/* check height */ +linelength = r[VBE_DISPI_INDEX_VIRT_WIDTH] * bits / 8; +maxy = s-vram_size / linelength; +if (r[VBE_DISPI_INDEX_YRES] == 0) { +r[VBE_DISPI_INDEX_YRES] = 1; +} +if (r[VBE_DISPI_INDEX_YRES] VBE_DISPI_MAX_YRES) { +r[VBE_DISPI_INDEX_YRES] = VBE_DISPI_MAX_YRES; +} +if (r[VBE_DISPI_INDEX_YRES] maxy) { +r[VBE_DISPI_INDEX_YRES] = maxy; +} + +/* check offset */ +if (r[VBE_DISPI_INDEX_X_OFFSET] VBE_DISPI_MAX_XRES) { +r[VBE_DISPI_INDEX_X_OFFSET] = VBE_DISPI_MAX_XRES; +} +if (r[VBE_DISPI_INDEX_Y_OFFSET] VBE_DISPI_MAX_YRES) { +r[VBE_DISPI_INDEX_Y_OFFSET] = VBE_DISPI_MAX_YRES; +} +offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8; +offset += r[VBE_DISPI_INDEX_Y_OFFSET] * linelength; +if (offset + r[VBE_DISPI_INDEX_YRES] * linelength s-vram_size) { +r[VBE_DISPI_INDEX_Y_OFFSET] = 0; +offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8; +if (offset + r[VBE_DISPI_INDEX_YRES] * linelength s-vram_size) { +r[VBE_DISPI_INDEX_X_OFFSET] = 0; +offset = 0; +} +} + +/* update vga state */ +r[VBE_DISPI_INDEX_VIRT_HEIGHT] = maxy; +s-vbe_line_offset = linelength; +s-vbe_start_addr = offset / 4; +} + static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) { VGAState *s = opaque; @@ -588,22 +675,13 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) } break; case VBE_DISPI_INDEX_XRES: -if ((val = VBE_DISPI_MAX_XRES) ((val 7) == 0)) { -s-vbe_regs[s-vbe_index] = val; -} -break; case VBE_DISPI_INDEX_YRES: -if (val = VBE_DISPI_MAX_YRES) { -s-vbe_regs[s-vbe_index] = val; -} -break; case VBE_DISPI_INDEX_BPP: -if (val == 0) -val = 8; -if (val == 4 || val == 8 || val == 15 || -val == 16 || val == 24 || val == 32) { -s-vbe_regs[s-vbe_index] = val; -} +case VBE_DISPI_INDEX_VIRT_WIDTH: +case VBE_DISPI_INDEX_X_OFFSET: +case VBE_DISPI_INDEX_Y_OFFSET: +s-vbe_regs[s-vbe_index] = val; +vbe_fixup_regs(s); break; case VBE_DISPI_INDEX_BANK: if (s-vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { @@ -623,19 +701,11 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) set_vram_mapping(s, s-lfb_addr, s-lfb_end); } -s-vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = -s-vbe_regs[VBE_DISPI_INDEX_XRES]; -s-vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = -s-vbe_regs[VBE_DISPI_INDEX_YRES]; +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; - -if (s-vbe_regs[VBE_DISPI_INDEX_BPP] == 4) -s-vbe_line_offset =
[Xen-devel] [PATCH 08/32] CVE-2014-3615: vbe: rework sanity checks
Backport of qemu-upstream: * c1b886c45dc70f247300f549dce9833f3fa2def5 Signed-off-by: Andrew Cooper andrew.coop...@citrix.com --- hw/vga.c | 154 ++ 1 file changed, 95 insertions(+), 59 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index d0c12aa..e8b1ce0 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -521,6 +521,93 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) } #ifdef CONFIG_BOCHS_VBE +/* + * Sanity check vbe register writes. + * + * As we don't have a way to signal errors to the guest in the bochs + * dispi interface we'll go adjust the registers to the closest valid + * value. + */ +static void vbe_fixup_regs(VGAState *s) +{ +uint16_t *r = s-vbe_regs; +uint32_t bits, linelength, maxy, offset; + +if (!(r[VBE_DISPI_INDEX_ENABLE] VBE_DISPI_ENABLED)) { +/* vbe is turned off -- nothing to do */ +return; +} + +/* check depth */ +switch (r[VBE_DISPI_INDEX_BPP]) { +case 4: +case 8: +case 16: +case 24: +case 32: +bits = r[VBE_DISPI_INDEX_BPP]; +break; +case 15: +bits = 16; +break; +default: +bits = r[VBE_DISPI_INDEX_BPP] = 8; +break; +} + +/* check width */ +r[VBE_DISPI_INDEX_XRES] = ~7u; +if (r[VBE_DISPI_INDEX_XRES] == 0) { +r[VBE_DISPI_INDEX_XRES] = 8; +} +if (r[VBE_DISPI_INDEX_XRES] VBE_DISPI_MAX_XRES) { +r[VBE_DISPI_INDEX_XRES] = VBE_DISPI_MAX_XRES; +} +r[VBE_DISPI_INDEX_VIRT_WIDTH] = ~7u; +if (r[VBE_DISPI_INDEX_VIRT_WIDTH] VBE_DISPI_MAX_XRES) { +r[VBE_DISPI_INDEX_VIRT_WIDTH] = VBE_DISPI_MAX_XRES; +} +if (r[VBE_DISPI_INDEX_VIRT_WIDTH] r[VBE_DISPI_INDEX_XRES]) { +r[VBE_DISPI_INDEX_VIRT_WIDTH] = r[VBE_DISPI_INDEX_XRES]; +} + +/* check height */ +linelength = r[VBE_DISPI_INDEX_VIRT_WIDTH] * bits / 8; +maxy = s-vram_size / linelength; +if (r[VBE_DISPI_INDEX_YRES] == 0) { +r[VBE_DISPI_INDEX_YRES] = 1; +} +if (r[VBE_DISPI_INDEX_YRES] VBE_DISPI_MAX_YRES) { +r[VBE_DISPI_INDEX_YRES] = VBE_DISPI_MAX_YRES; +} +if (r[VBE_DISPI_INDEX_YRES] maxy) { +r[VBE_DISPI_INDEX_YRES] = maxy; +} + +/* check offset */ +if (r[VBE_DISPI_INDEX_X_OFFSET] VBE_DISPI_MAX_XRES) { +r[VBE_DISPI_INDEX_X_OFFSET] = VBE_DISPI_MAX_XRES; +} +if (r[VBE_DISPI_INDEX_Y_OFFSET] VBE_DISPI_MAX_YRES) { +r[VBE_DISPI_INDEX_Y_OFFSET] = VBE_DISPI_MAX_YRES; +} +offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8; +offset += r[VBE_DISPI_INDEX_Y_OFFSET] * linelength; +if (offset + r[VBE_DISPI_INDEX_YRES] * linelength s-vram_size) { +r[VBE_DISPI_INDEX_Y_OFFSET] = 0; +offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8; +if (offset + r[VBE_DISPI_INDEX_YRES] * linelength s-vram_size) { +r[VBE_DISPI_INDEX_X_OFFSET] = 0; +offset = 0; +} +} + +/* update vga state */ +r[VBE_DISPI_INDEX_VIRT_HEIGHT] = maxy; +s-vbe_line_offset = linelength; +s-vbe_start_addr = offset / 4; +} + static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) { VGAState *s = opaque; @@ -588,22 +675,13 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) } break; case VBE_DISPI_INDEX_XRES: -if ((val = VBE_DISPI_MAX_XRES) ((val 7) == 0)) { -s-vbe_regs[s-vbe_index] = val; -} -break; case VBE_DISPI_INDEX_YRES: -if (val = VBE_DISPI_MAX_YRES) { -s-vbe_regs[s-vbe_index] = val; -} -break; case VBE_DISPI_INDEX_BPP: -if (val == 0) -val = 8; -if (val == 4 || val == 8 || val == 15 || -val == 16 || val == 24 || val == 32) { -s-vbe_regs[s-vbe_index] = val; -} +case VBE_DISPI_INDEX_VIRT_WIDTH: +case VBE_DISPI_INDEX_X_OFFSET: +case VBE_DISPI_INDEX_Y_OFFSET: +s-vbe_regs[s-vbe_index] = val; +vbe_fixup_regs(s); break; case VBE_DISPI_INDEX_BANK: if (s-vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { @@ -623,19 +701,11 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) set_vram_mapping(s, s-lfb_addr, s-lfb_end); } -s-vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = -s-vbe_regs[VBE_DISPI_INDEX_XRES]; -s-vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = -s-vbe_regs[VBE_DISPI_INDEX_YRES]; +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; - -if (s-vbe_regs[VBE_DISPI_INDEX_BPP] == 4) -s-vbe_line_offset =