|
|
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 |
|