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