34b321
From 27bca97bf22a55b1be7611e07c7592fcef5dd7cc Mon Sep 17 00:00:00 2001
e96cb2
From: Gerd Hoffmann <kraxel@redhat.com>
34b321
Date: Thu, 28 Apr 2016 16:07:28 +0200
34b321
Subject: [PATCH 23/27] vga: fix banked access bounds checking (CVE-2016-xxxx).
e96cb2
e96cb2
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
34b321
Message-id: <1461859652-20918-3-git-send-email-kraxel@redhat.com>
34b321
Patchwork-id: 70293
34b321
O-Subject: [virt-devel] [RHEL-7.3 qemu-kvm PATCH 2/6] vga: fix banked access bounds checking (CVE-2016-xxxx).
34b321
Bugzilla: 1331413
e96cb2
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
e96cb2
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
e96cb2
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
e96cb2
e96cb2
vga allows banked access to video memory using the window at 0xa00000
e96cb2
and it supports a different access modes with different address
e96cb2
calculations.
e96cb2
e96cb2
The VBE bochs extentions support banked access too, using the
e96cb2
VBE_DISPI_INDEX_BANK register.  The code tries to take the different
e96cb2
address calculations into account and applies different limits to
e96cb2
VBE_DISPI_INDEX_BANK depending on the current access mode.
e96cb2
e96cb2
Which is probably effective in stopping misprogramming by accident.
e96cb2
But from a security point of view completely useless as an attacker
e96cb2
can easily change access modes after setting the bank register.
e96cb2
e96cb2
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
e96cb2
instead.
e96cb2
e96cb2
Reported-by: Qinghao Tang <luodalongde@gmail.com>
e96cb2
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
e96cb2
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
e96cb2
---
e96cb2
 hw/display/vga.c | 23 +++++++++++++++++------
e96cb2
 1 file changed, 17 insertions(+), 6 deletions(-)
e96cb2
e96cb2
diff --git a/hw/display/vga.c b/hw/display/vga.c
e96cb2
index 48dad03..ba171ba 100644
e96cb2
--- a/hw/display/vga.c
e96cb2
+++ b/hw/display/vga.c
e96cb2
@@ -744,11 +744,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
e96cb2
             vbe_fixup_regs(s);
e96cb2
             break;
e96cb2
         case VBE_DISPI_INDEX_BANK:
e96cb2
-            if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
e96cb2
-              val &= (s->vbe_bank_mask >> 2);
e96cb2
-            } else {
e96cb2
-              val &= s->vbe_bank_mask;
e96cb2
-            }
e96cb2
+            val &= s->vbe_bank_mask;
e96cb2
             s->vbe_regs[s->vbe_index] = val;
e96cb2
             s->bank_offset = (val << 16);
e96cb2
             vga_update_memory_access(s);
e96cb2
@@ -847,13 +843,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
e96cb2
 
e96cb2
     if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
e96cb2
         /* chain 4 mode : simplest access */
e96cb2
+        assert(addr < s->vram_size);
e96cb2
         ret = s->vram_ptr[addr];
e96cb2
     } else if (s->gr[VGA_GFX_MODE] & 0x10) {
e96cb2
         /* odd/even mode (aka text mode mapping) */
e96cb2
         plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
e96cb2
-        ret = s->vram_ptr[((addr & ~1) << 1) | plane];
e96cb2
+        addr = ((addr & ~1) << 1) | plane;
e96cb2
+        if (addr >= s->vram_size) {
e96cb2
+            return 0xff;
e96cb2
+        }
e96cb2
+        ret = s->vram_ptr[addr];
e96cb2
     } else {
e96cb2
         /* standard VGA latched access */
e96cb2
+        if (addr * sizeof(uint32_t) >= s->vram_size) {
e96cb2
+            return 0xff;
e96cb2
+        }
e96cb2
         s->latch = ((uint32_t *)s->vram_ptr)[addr];
e96cb2
 
e96cb2
         if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
e96cb2
@@ -910,6 +914,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
e96cb2
         plane = addr & 3;
e96cb2
         mask = (1 << plane);
e96cb2
         if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
e96cb2
+            assert(addr < s->vram_size);
e96cb2
             s->vram_ptr[addr] = val;
e96cb2
 #ifdef DEBUG_VGA_MEM
e96cb2
             printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
e96cb2
@@ -923,6 +928,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
e96cb2
         mask = (1 << plane);
e96cb2
         if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
e96cb2
             addr = ((addr & ~1) << 1) | plane;
e96cb2
+            if (addr >= s->vram_size) {
e96cb2
+                return;
e96cb2
+            }
e96cb2
             s->vram_ptr[addr] = val;
e96cb2
 #ifdef DEBUG_VGA_MEM
e96cb2
             printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
e96cb2
@@ -996,6 +1004,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
e96cb2
         mask = s->sr[VGA_SEQ_PLANE_WRITE];
e96cb2
         s->plane_updated |= mask; /* only used to detect font change */
e96cb2
         write_mask = mask16[mask];
e96cb2
+        if (addr * sizeof(uint32_t) >= s->vram_size) {
e96cb2
+            return;
e96cb2
+        }
e96cb2
         ((uint32_t *)s->vram_ptr)[addr] =
e96cb2
             (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
e96cb2
             (val & write_mask);
e96cb2
-- 
e96cb2
1.8.3.1
e96cb2