[Xen-devel] [PATCH 08/32] CVE-2014-3615: vbe: rework sanity checks

2015-04-22 Thread Andrew Cooper
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

2015-04-22 Thread Andrew Cooper
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 =