yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone

Blame SOURCES/kvm-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch

e96cb2
From 73714beab12fec056f3b38a7c2bc35a520405953 Mon Sep 17 00:00:00 2001
e96cb2
From: Gerd Hoffmann <kraxel@redhat.com>
e96cb2
Date: Fri, 29 Apr 2016 07:02:47 +0200
e96cb2
Subject: [PATCH 2/6] vga: fix banked access bounds checking (CVE-2016-3710)
e96cb2
e96cb2
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
e96cb2
Message-id: <1461913371-3145-3-git-send-email-kraxel@redhat.com>
e96cb2
Patchwork-id: 70302
e96cb2
O-Subject: [virt-devel] [RHEL-7.2.z qemu-kvm PATCH 2/6] vga: fix banked access bounds checking (CVE-2016-3710)
e96cb2
Bugzilla: 1331412
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
Fixes: CVE-2016-3710
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