* Xen Security Advisory 179 (CVE-2016-3710, CVE-2016-3712) - QEMU: Banked access to VGA memory (VBE) uses inconsistent bounds checks
@ 2016-05-09 12:00 Xen.org security team
0 siblings, 0 replies; 2+ messages in thread
From: Xen.org security team @ 2016-05-09 12:00 UTC (permalink / raw)
To: xen-announce, xen-devel, xen-users, oss-security; +Cc: Xen.org security team
[-- Attachment #1: Type: text/plain, Size: 10986 bytes --]
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Xen Security Advisory CVE-2016-3710,CVE-2016-3712 / XSA-179
version 4
QEMU: Banked access to VGA memory (VBE) uses inconsistent bounds checks
UPDATES IN VERSION 4
====================
Public release. Also include CVE and description of both issues.
(All advisories sent have included patches for both issues, but only
the description and CVE for the first issue.)
ISSUE DESCRIPTION
=================
Qemu VGA module allows banked access to video memory using the window
at 0xa00000 and it supports different access modes with different
address calculations. But an attacker can easily change access modes
after setting the bank register. This is CVE-2016-3710.
Qemu VGA module allows guest to edit certain registers in 'vbe' and
'vga' modes. ie. guest could set certain 'VGA' registers while in
'VBE' mode. This is CVE-2016-3712.
IMPACT
======
A privileged guest user could use CVE-2016-3710 to exceed the bank
address window and write beyond the said memory area, potentially
leading to arbitrary code execution with privileges of the Qemu
process. If the system is not using stubdomains, this will be in
domain 0.
A privileged guest user could use CVE-2016-3712 to cause potential
integer overflow or OOB read access issues in Qemu, resulting in a DoS
of the guest itself. More dangerous effect, such as data leakage or
code execution, are not known but cannot be ruled out.
VULNERABLE SYSTEMS
==================
Versions of qemu shipped with all Xen versions are vulnerable.
Xen systems running on x86 with HVM guests, with the qemu process
running in dom0 are vulnerable.
Only guests provided with the "stdvga" emulated video card can exploit
the vulnerability. The default "cirrus" emulated video card is not
vulnerable. (With xl the emulated video card is controlled by the
"stdvga=" and "vga=" domain configuration options.)
ARM systems are not vulnerable. Systems using only PV guests are not
vulnerable.
For VMs whose qemu process is running in a stub domain, a successful
attacker will only gain the privileges of that stubdom, which should
be only over the guest itself.
Both upstream-based versions of qemu (device_model_version="qemu-xen")
and `traditional' qemu (device_model_version="qemu-xen-traditional")
are vulnerable.
MITIGATION
==========
Running only PV guests will avoid the issue.
Running HVM guests with the device model in a stubdomain will mitigate
the issue.
Changing the video card emulation to cirrus (stdvga=0, vga="cirrus",
in the xl domain configuraton) will avoid the vulnerability.
CREDITS
=======
CVE-2016-3710 was discovered and reported by "Wei Xiao and Qinghao
Tang of 360 Marvel Team" of 360.cn Inc.
CVE-2016-3710 was discovered and reported by Zuozhi Fzz of Alibaba
Inc.
RESOLUTION
==========
Applying the appropriate attached patch resolves this issue for
systems using upstream-based versions of qemu. Patch 0001 addresses
CVE-2016-3710, and patches 0002-0005 address CVE-2016-3712.
qemu-upstream, xen-unstable:
xsa179-qemuu-unstable-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
xsa179-qemuu-unstable-0002-vga-add-vbe_enabled-helper.patch
xsa179-qemuu-unstable-0003-vga-factor-out-vga-register-setup.patch
xsa179-qemuu-unstable-0004-vga-update-vga-register-setup-on-vbe-changes.patch
xsa179-qemuu-unstable-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
qemu-upstream, xen 4.6:
xsa179-qemuu-4.6-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
xsa179-qemuu-4.6-0002-vga-add-vbe_enabled-helper.patch
xsa179-qemuu-4.6-0003-vga-factor-out-vga-register-setup.patch
xsa179-qemuu-4.6-0004-vga-update-vga-register-setup-on-vbe-changes.patch
xsa179-qemuu-4.6-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
qemu-upstream, xen 4.5:
xsa179-qemuu-4.5-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
xsa179-qemuu-4.5-0002-vga-add-vbe_enabled-helper.patch
xsa179-qemuu-4.5-0003-vga-factor-out-vga-register-setup.patch
xsa179-qemuu-4.5-0004-vga-update-vga-register-setup-on-vbe-changes.patch
xsa179-qemuu-4.5-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
qemu-upstream, xen 4.4:
xsa179-qemuu-4.4-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
xsa179-qemuu-4.4-0002-vga-add-vbe_enabled-helper.patch
xsa179-qemuu-4.4-0003-vga-factor-out-vga-register-setup.patch
xsa179-qemuu-4.4-0004-vga-update-vga-register-setup-on-vbe-changes.patch
xsa179-qemuu-4.4-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
qemu-upstream, xen 4.3:
xsa179-qemuu-4.3-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
xsa179-qemuu-4.3-0002-vga-add-vbe_enabled-helper.patch
xsa179-qemuu-4.3-0003-vga-factor-out-vga-register-setup.patch
xsa179-qemuu-4.3-0004-vga-update-vga-register-setup-on-vbe-changes.patch
xsa179-qemuu-4.3-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
qemu-xen-traditional, unstable:
xsa179-qemut-unstable-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
xsa179-qemut-unstable-0002-vga-add-vbe_enabled-helper.patch
xsa179-qemut-unstable-0003-vga-factor-out-vga-register-setup.patch
xsa179-qemut-unstable-0004-vga-update-vga-register-setup-on-vbe-changes.patch
xsa179-qemut-unstable-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
$ sha256sum xsa179*
e216959d099ed807b282026e1e4d558ce0c0e8ead284ddd9d0581cef5fcef0ad xsa179-qemuu-unstable-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
708e40d85866540567d2d915731c6e9876cd0d6754bc6696650ed71d8e48d710 xsa179-qemuu-unstable-0002-vga-add-vbe_enabled-helper.patch
767007028189bce54df9769ff6cb9db7cd37b5c2afaac86787b30c8f2a03f342 xsa179-qemuu-unstable-0003-vga-factor-out-vga-register-setup.patch
1fb507c307b093e5e4471d4a5e567db419adecbfe772a68bf91722836bcba4cd xsa179-qemuu-unstable-0004-vga-update-vga-register-setup-on-vbe-changes.patch
ff4327d598d2e0912dc3a22ab9ba14d6c79bfa5a154714b6c5da761d5ded403f xsa179-qemuu-unstable-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
059bfa59f39222ad6991e6c0c8338385f2a317e379d02d0c2cb0e5a8138cb329 xsa179-qemuu-4.3-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
c6dfe50d694b75670bbdec78a3ce6293a8da46d5ff8b47f1e0d7e4fac22260bf xsa179-qemuu-4.3-0002-vga-add-vbe_enabled-helper.patch
f57e31e8b81f1161537277a0934013c1fb3bbf57319543dfd10a5dc5fdfb927b xsa179-qemuu-4.3-0003-vga-factor-out-vga-register-setup.patch
14900af2b13d362ffb98c061e76b13965965284399dd9b9f1a4e41b41f34a3a3 xsa179-qemuu-4.3-0004-vga-update-vga-register-setup-on-vbe-changes.patch
2b2e7d306fd95fa74490ee1694af1af9438d7ff738d8c6aecc7d99d4eb96dcb2 xsa179-qemuu-4.3-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
e6108266bf0abada5fc6e0a3ca65c2702fcae610826ead6a215d622ec3ed973a xsa179-qemuu-4.4-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
05bdfae312078b22542e9f18db98fae11dbfd9785184b0b3c8de8c94797e1427 xsa179-qemuu-4.4-0002-vga-add-vbe_enabled-helper.patch
56dee9d0f54357391d5249a01ab28a1879dd7d1a36b4d147d68c62688d8af22b xsa179-qemuu-4.4-0003-vga-factor-out-vga-register-setup.patch
10603f5ffe317de328dc46139a6b5ff6081040ca6368ee1642b5343db9bcfda1 xsa179-qemuu-4.4-0004-vga-update-vga-register-setup-on-vbe-changes.patch
e0dbc47086f0346a9554b98468256bc325d67440f5d786c5825390d293896509 xsa179-qemuu-4.4-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
9b0cfdba369437a3e3da86690cd0c6d9d05e39d1168065e4d11ff2de4e546feb xsa179-qemuu-4.5-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
3c56f255d2ff3e5ae24f15de69cbd4abf3ff0d2dbb63a686937d5e2ab1989d59 xsa179-qemuu-4.5-0002-vga-add-vbe_enabled-helper.patch
b1ddabf50720635efa17a7c57778acd2e1d9fd6a6424038455163991afecb044 xsa179-qemuu-4.5-0003-vga-factor-out-vga-register-setup.patch
0f34eeda817f39d3b5e484d535aa29bae16e7e36b4dc042bc41ef0e1844bf3cb xsa179-qemuu-4.5-0004-vga-update-vga-register-setup-on-vbe-changes.patch
c24b3401a7ed45f853de7c96b998d50461254e9082a706753b814ddcbc285b17 xsa179-qemuu-4.5-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
de59a098a39c1adbc86f3857dbb2b655479f97756d46e017e83b41c1390a98b9 xsa179-qemuu-4.6-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
3686d0b5c3603819fe0eca65ed62161c676e6abd8e676e513f6d4b3d46e7a997 xsa179-qemuu-4.6-0002-vga-add-vbe_enabled-helper.patch
18d01083e2f4000816ecf26d85da5cb337f540da447e6252f348a5b538cc7fa4 xsa179-qemuu-4.6-0003-vga-factor-out-vga-register-setup.patch
811ce206293b54ad601eb0a0e59bee502277c642f73f1ea0bad712efc528f82d xsa179-qemuu-4.6-0004-vga-update-vga-register-setup-on-vbe-changes.patch
2097c9e4eac66a65e07607664d1aaec288c4c8b0f147c73636c1b2532cdd20dd xsa179-qemuu-4.6-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
132fd7f7d1f7bee4d934daefc24ec65080ae09b7d0e07a86edc3b683cad8156a xsa179-qemut-unstable-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
b83c29c3737415bf05da14c0b856abeb3bdbb77fba7d538956535ed67160abe8 xsa179-qemut-unstable-0002-vga-add-vbe_enabled-helper.patch
834266af0499167e6d8e2e87bb770b79c0e8480ab5ea72064298656ccdd36741 xsa179-qemut-unstable-0003-vga-factor-out-vga-register-setup.patch
a5c3c38340261c7ff44047289aad6276e501930e214c40350056a364469965cd xsa179-qemut-unstable-0004-vga-update-vga-register-setup-on-vbe-changes.patch
4869ad504cba52f537dae102e226b020422e3b6494ffba3b865eb2893bee0e9e xsa179-qemut-unstable-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
$
DEPLOYMENT DURING EMBARGO
=========================
Deployment of the patches and/or mitigations described above (or
others which are substantially similar) is permitted during the
embargo, even on public-facing systems with untrusted guest users and
administrators.
But: Distribution of updated software is prohibited (except to other
members of the predisclosure list).
Predisclosure list members who wish to deploy significantly different
patches and/or mitigations, please contact the Xen Project Security
Team.
(Note: this during-embargo deployment notice is retained in
post-embargo publicly released Xen Project advisories, even though it
is then no longer applicable. This is to enable the community to have
oversight of the Xen Project Security Team's decisionmaking.)
For more information about permissible uses of embargoed information,
consult the Xen Project community's agreed Security Policy:
http://www.xenproject.org/security-policy.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)
iQEcBAEBAgAGBQJXMHkhAAoJEIP+FMlX6CvZ4J4IAKgEIz12GbtunUY4H3EY+bye
qtpFfPIvE8933HCNG4c2e8VR/PehOlDhUWMDlkyFJ3jBja7VPeqOm9jnHWlsxaCz
x7nix3PbbcconeUMn5JMf9i2ocY0wNvrD+wYBVCnSvLjvnBpKXEKgCIrAZ2bLLa8
TfcqCC3R5z15r2GoJ801lP9ts3/tQLketBefBUznGYaZreVgGF73g7tyK6bsFQAz
PFVzBb2lSx2XwfWNC1Ya/a456WUmuDFpcfRVfdKi4yEh/xPOlKj1kKvx8GpSDm0m
3+5h04pp5Znu+ORVztfqcRPx4v4LXT33bM5mjBytJRc05//DIsHuC3GKOoBu9rQ=
=faLY
-----END PGP SIGNATURE-----
[-- Attachment #2: xsa179-qemuu-unstable-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch --]
[-- Type: application/octet-stream, Size: 4343 bytes --]
From 3bf1817079bb0d80c0d8a86a7c7dd0bfe90eb82e Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 08:49:10 +0200
Subject: [PATCH 1/5] vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000
and it supports a different access modes with different address
calculations.
The VBE bochs extentions support banked access too, using the
VBE_DISPI_INDEX_BANK register. The code tries to take the different
address calculations into account and applies different limits to
VBE_DISPI_INDEX_BANK depending on the current access mode.
Which is probably effective in stopping misprogramming by accident.
But from a security point of view completely useless as an attacker
can easily change access modes after setting the bank register.
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
instead.
Fixes: CVE-2016-3710
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 657e9f1..b9191ca 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -179,6 +179,7 @@ static void vga_update_memory_access(VGACommonState *s)
size = 0x8000;
break;
}
+ assert(offset + size <= s->vram_size);
memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
"vga.chain4", &s->vram, offset, size);
memory_region_add_subregion_overlap(s->legacy_address_space, base,
@@ -716,11 +717,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
vbe_fixup_regs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
vga_update_memory_access(s);
@@ -819,13 +816,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
@@ -882,6 +887,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
@@ -895,6 +901,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
@@ -968,6 +977,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
--
1.8.3.1
[-- Attachment #3: xsa179-qemuu-unstable-0002-vga-add-vbe_enabled-helper.patch --]
[-- Type: application/octet-stream, Size: 2096 bytes --]
From bfa0f151a564a83b5a26f3e917da98674bf3cf62 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:11:34 +0200
Subject: [PATCH 2/5] vga: add vbe_enabled() helper
Makes code a bit easier to read.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index b9191ca..0c1c5b5 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -142,6 +142,11 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static inline bool vbe_enabled(VGACommonState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
static void vga_update_memory_access(VGACommonState *s)
{
hwaddr base, offset, size;
@@ -564,7 +569,7 @@ static void vbe_fixup_regs(VGACommonState *s)
uint16_t *r = s->vbe_regs;
uint32_t bits, linelength, maxy, offset;
- if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -1058,7 +1063,7 @@ static void vga_get_offsets(VGACommonState *s,
{
uint32_t start_addr, line_offset, line_compare;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1383,7 +1388,7 @@ static int vga_get_bpp(VGACommonState *s)
{
int ret;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else {
ret = 0;
@@ -1395,7 +1400,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
{
int width, height;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else {
--
1.8.3.1
[-- Attachment #4: xsa179-qemuu-unstable-0003-vga-factor-out-vga-register-setup.patch --]
[-- Type: application/octet-stream, Size: 5115 bytes --]
From 7fa5c2c5dc9f9bf878c1e8669eb9644d70a71e71 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:24:18 +0200
Subject: [PATCH 3/5] vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer. Move that code to a separate function so we can call it
from other places too.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 78 ++++++++++++++++++++++++++++++++------------------------
1 file changed, 44 insertions(+), 34 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 0c1c5b5..e12f5ac 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -644,6 +644,49 @@ static void vbe_fixup_regs(VGACommonState *s)
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGACommonState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+ }
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGACommonState *s = opaque;
@@ -730,52 +773,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
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;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode */
- /* graphic mode + memory map 1 */
- s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
- VGA_GR06_GRAPHICS_MODE;
- s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
- s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[VGA_CRTC_H_DISP] =
- (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[VGA_CRTC_V_DISP_END] = h;
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
- s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
- s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- /* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
- /* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
- }
- s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
- (shift_control << 5);
- s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
s->bank_offset = 0;
}
--
1.8.3.1
[-- Attachment #5: xsa179-qemuu-unstable-0004-vga-update-vga-register-setup-on-vbe-changes.patch --]
[-- Type: application/octet-stream, Size: 920 bytes --]
From 2068192dcccd8a80dddfcc8df6164cf9c26e0fc4 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:39:22 +0200
Subject: [PATCH 4/5] vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index e12f5ac..eeeb9c8 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -763,6 +763,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
val &= s->vbe_bank_mask;
--
1.8.3.1
[-- Attachment #6: xsa179-qemuu-unstable-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch --]
[-- Type: application/octet-stream, Size: 2799 bytes --]
From fd3c136b3e1482cd0ec7285d6bc2a3e6a62c38d7 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:48:06 +0200
Subject: [PATCH 5/5] vga: make sure vga register setup for vbe stays intact
(CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode. This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.
Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.
Which is good for one or another buffer overflow. Not that
critical as they typically read overflows happening somewhere
in the display code. So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.
Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index eeeb9c8..4a55ec6 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -142,6 +142,8 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static void vbe_update_vgaregs(VGACommonState *s);
+
static inline bool vbe_enabled(VGACommonState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
@@ -484,6 +486,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+ vbe_update_vgaregs(s);
if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
s->update_retrace_info(s);
}
@@ -515,6 +518,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
vga_update_memory_access(s);
break;
case VGA_CRT_IM:
@@ -533,10 +537,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->cr_index == VGA_CRTC_OVERFLOW) {
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
(val & 0x10);
+ vbe_update_vgaregs(s);
}
return;
}
s->cr[s->cr_index] = val;
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case VGA_CRTC_H_TOTAL:
--
1.8.3.1
[-- Attachment #7: xsa179-qemuu-4.3-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch --]
[-- Type: application/octet-stream, Size: 4334 bytes --]
From 67305fcf4733fb4fb9eacc33436ec66a7c0352ef Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 4 May 2016 17:40:58 +0100
Subject: [PATCH 1/5] vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000
and it supports a different access modes with different address
calculations.
The VBE bochs extentions support banked access too, using the
VBE_DISPI_INDEX_BANK register. The code tries to take the different
address calculations into account and applies different limits to
VBE_DISPI_INDEX_BANK depending on the current access mode.
Which is probably effective in stopping misprogramming by accident.
But from a security point of view completely useless as an attacker
can easily change access modes after setting the bank register.
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
instead.
Fixes: CVE-2016-3710
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/vga.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/hw/vga.c b/hw/vga.c
index 69399db..cd7e7aa 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -200,6 +200,7 @@ static void vga_update_memory_access(VGACommonState *s)
break;
}
base += isa_mem_base;
+ assert(offset + size <= s->vram_size);
region = g_malloc(sizeof(*region));
memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
memory_region_add_subregion_overlap(s->legacy_address_space, base,
@@ -747,11 +748,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
vbe_fixup_regs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
vga_update_memory_access(s);
@@ -852,13 +849,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
@@ -915,6 +920,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
@@ -928,6 +934,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
@@ -1001,6 +1010,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
--
1.9.1
[-- Attachment #8: xsa179-qemuu-4.3-0002-vga-add-vbe_enabled-helper.patch --]
[-- Type: application/octet-stream, Size: 2199 bytes --]
From e7d7c09689c725be4f0b489b4ba3b741c5d9ab31 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 4 May 2016 17:41:39 +0100
Subject: [PATCH 2/5] vga: add vbe_enabled() helper
Makes code a bit easier to read.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/vga.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/vga.c b/hw/vga.c
index cd7e7aa..cb1c14d 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -169,6 +169,11 @@ static uint8_t expand4to8[16];
static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
Error **errp);
+static inline bool vbe_enabled(VGACommonState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
static void vga_update_memory_access(VGACommonState *s)
{
MemoryRegion *region, *old_region = s->chain4_alias;
@@ -595,7 +600,7 @@ static void vbe_fixup_regs(VGACommonState *s)
uint16_t *r = s->vbe_regs;
uint32_t bits, linelength, maxy, offset;
- if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -1176,7 +1181,7 @@ static void vga_get_offsets(VGACommonState *s,
{
uint32_t start_addr, line_offset, line_compare;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1626,7 +1631,7 @@ static int vga_get_bpp(VGACommonState *s)
{
int ret;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else {
ret = 0;
@@ -1638,7 +1643,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
{
int width, height;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else {
--
1.9.1
[-- Attachment #9: xsa179-qemuu-4.3-0003-vga-factor-out-vga-register-setup.patch --]
[-- Type: application/octet-stream, Size: 5246 bytes --]
From 2700250c6b28248b70b15fd6e0b4c9db8b2ddfb7 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 4 May 2016 17:42:24 +0100
Subject: [PATCH 3/5] vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer. Move that code to a separate function so we can call it
from other places too.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/vga.c | 79 ++++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 44 insertions(+), 35 deletions(-)
diff --git a/hw/vga.c b/hw/vga.c
index cb1c14d..ad7ca49 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -675,6 +675,49 @@ static void vbe_fixup_regs(VGACommonState *s)
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGACommonState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+ }
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGACommonState *s = opaque;
@@ -761,53 +804,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
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;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen (should be done in BIOS) */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode (should be done
- in BIOS) */
- /* graphic mode + memory map 1 */
- s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
- VGA_GR06_GRAPHICS_MODE;
- s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
- s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[VGA_CRTC_H_DISP] =
- (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[VGA_CRTC_V_DISP_END] = h;
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
- s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
- s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- /* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
- /* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
- }
- s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
- (shift_control << 5);
- s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
/* XXX: the bios should do that */
s->bank_offset = 0;
--
1.9.1
[-- Attachment #10: xsa179-qemuu-4.3-0004-vga-update-vga-register-setup-on-vbe-changes.patch --]
[-- Type: application/octet-stream, Size: 936 bytes --]
From 98be1fb6ea31c130264025de8ec87ad2c7532f21 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 4 May 2016 17:42:59 +0100
Subject: [PATCH 4/5] vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/vga.c b/hw/vga.c
index ad7ca49..1ac8083 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -794,6 +794,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
val &= s->vbe_bank_mask;
--
1.9.1
[-- Attachment #11: xsa179-qemuu-4.3-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch --]
[-- Type: application/octet-stream, Size: 2876 bytes --]
From 0f2e9e6b3c75a87e9ec9a80d7bc914810e3f3da2 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 4 May 2016 17:43:36 +0100
Subject: [PATCH 5/5] vga: make sure vga register setup for vbe stays intact
(CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode. This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.
Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.
Which is good for one or another buffer overflow. Not that
critical as they typically read overflows happening somewhere
in the display code. So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.
Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/vga.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hw/vga.c b/hw/vga.c
index 1ac8083..17b389e 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -169,6 +169,8 @@ static uint8_t expand4to8[16];
static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
Error **errp);
+static void vbe_update_vgaregs(VGACommonState *s);
+
static inline bool vbe_enabled(VGACommonState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
@@ -515,6 +517,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+ vbe_update_vgaregs(s);
if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
s->update_retrace_info(s);
}
@@ -546,6 +549,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
vga_update_memory_access(s);
break;
case VGA_CRT_IM:
@@ -564,10 +568,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->cr_index == VGA_CRTC_OVERFLOW) {
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
(val & 0x10);
+ vbe_update_vgaregs(s);
}
return;
}
s->cr[s->cr_index] = val;
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case VGA_CRTC_H_TOTAL:
--
1.9.1
[-- Attachment #12: xsa179-qemuu-4.4-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch --]
[-- Type: application/octet-stream, Size: 4363 bytes --]
From 25935fd1ed3c4337aa4b61902ec580e17b130b63 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 08:49:10 +0200
Subject: [PATCH 1/5] vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000
and it supports a different access modes with different address
calculations.
The VBE bochs extentions support banked access too, using the
VBE_DISPI_INDEX_BANK register. The code tries to take the different
address calculations into account and applies different limits to
VBE_DISPI_INDEX_BANK depending on the current access mode.
Which is probably effective in stopping misprogramming by accident.
But from a security point of view completely useless as an attacker
can easily change access modes after setting the bank register.
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
instead.
Fixes: CVE-2016-3710
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 430e7ed..69e2554 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -197,6 +197,7 @@ static void vga_update_memory_access(VGACommonState *s)
break;
}
base += isa_mem_base;
+ assert(offset + size <= s->vram_size);
region = g_malloc(sizeof(*region));
memory_region_init_alias(region, memory_region_owner(&s->vram),
"vga.chain4", &s->vram, offset, size);
@@ -745,11 +746,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
vbe_fixup_regs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
vga_update_memory_access(s);
@@ -850,13 +847,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
@@ -913,6 +918,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
@@ -926,6 +932,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
@@ -999,6 +1008,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
--
1.9.1
[-- Attachment #13: xsa179-qemuu-4.4-0002-vga-add-vbe_enabled-helper.patch --]
[-- Type: application/octet-stream, Size: 2179 bytes --]
From 294a6c15a38669f80920b885287191514ab7d9ff Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:11:34 +0200
Subject: [PATCH 2/5] vga: add vbe_enabled() helper
Makes code a bit easier to read.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 69e2554..da1eb4a 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -166,6 +166,11 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static inline bool vbe_enabled(VGACommonState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
static void vga_update_memory_access(VGACommonState *s)
{
MemoryRegion *region, *old_region = s->chain4_alias;
@@ -593,7 +598,7 @@ static void vbe_fixup_regs(VGACommonState *s)
uint16_t *r = s->vbe_regs;
uint32_t bits, linelength, maxy, offset;
- if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -1174,7 +1179,7 @@ static void vga_get_offsets(VGACommonState *s,
{
uint32_t start_addr, line_offset, line_compare;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1627,7 +1632,7 @@ static int vga_get_bpp(VGACommonState *s)
{
int ret;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else {
ret = 0;
@@ -1639,7 +1644,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
{
int width, height;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else {
--
1.9.1
[-- Attachment #14: xsa179-qemuu-4.4-0003-vga-factor-out-vga-register-setup.patch --]
[-- Type: application/octet-stream, Size: 5279 bytes --]
From d377918c23d85f64d01914b43bfabc0a46fe974a Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:24:18 +0200
Subject: [PATCH 3/5] vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer. Move that code to a separate function so we can call it
from other places too.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 79 +++++++++++++++++++++++++++++++-------------------------
1 file changed, 44 insertions(+), 35 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index da1eb4a..cf5f97e 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -673,6 +673,49 @@ static void vbe_fixup_regs(VGACommonState *s)
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGACommonState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+ }
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGACommonState *s = opaque;
@@ -759,53 +802,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
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;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen (should be done in BIOS) */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode (should be done
- in BIOS) */
- /* graphic mode + memory map 1 */
- s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
- VGA_GR06_GRAPHICS_MODE;
- s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
- s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[VGA_CRTC_H_DISP] =
- (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[VGA_CRTC_V_DISP_END] = h;
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
- s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
- s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- /* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
- /* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
- }
- s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
- (shift_control << 5);
- s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
/* XXX: the bios should do that */
s->bank_offset = 0;
--
1.9.1
[-- Attachment #15: xsa179-qemuu-4.4-0004-vga-update-vga-register-setup-on-vbe-changes.patch --]
[-- Type: application/octet-stream, Size: 977 bytes --]
From fbcff82cd7998f93556c28dfc63bbbd7b206c8ce Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:39:22 +0200
Subject: [PATCH 4/5] vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index cf5f97e..63d1a70 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -792,6 +792,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
val &= s->vbe_bank_mask;
--
1.9.1
[-- Attachment #16: xsa179-qemuu-4.4-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch --]
[-- Type: application/octet-stream, Size: 2856 bytes --]
From f7926c73685c2bc7124265f567bafb502864c5dd Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:48:06 +0200
Subject: [PATCH 5/5] vga: make sure vga register setup for vbe stays intact
(CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode. This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.
Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.
Which is good for one or another buffer overflow. Not that
critical as they typically read overflows happening somewhere
in the display code. So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.
Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 63d1a70..dd61246 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -166,6 +166,8 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static void vbe_update_vgaregs(VGACommonState *s);
+
static inline bool vbe_enabled(VGACommonState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
@@ -513,6 +515,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+ vbe_update_vgaregs(s);
if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
s->update_retrace_info(s);
}
@@ -544,6 +547,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
vga_update_memory_access(s);
break;
case VGA_CRT_IM:
@@ -562,10 +566,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->cr_index == VGA_CRTC_OVERFLOW) {
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
(val & 0x10);
+ vbe_update_vgaregs(s);
}
return;
}
s->cr[s->cr_index] = val;
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case VGA_CRTC_H_TOTAL:
--
1.9.1
[-- Attachment #17: xsa179-qemuu-4.5-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch --]
[-- Type: application/octet-stream, Size: 4363 bytes --]
From c9a1a2d7bf3db54b7961df4b8a30946a767b4853 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 08:49:10 +0200
Subject: [PATCH 1/5] vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000
and it supports a different access modes with different address
calculations.
The VBE bochs extentions support banked access too, using the
VBE_DISPI_INDEX_BANK register. The code tries to take the different
address calculations into account and applies different limits to
VBE_DISPI_INDEX_BANK depending on the current access mode.
Which is probably effective in stopping misprogramming by accident.
But from a security point of view completely useless as an attacker
can easily change access modes after setting the bank register.
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
instead.
Fixes: CVE-2016-3710
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 2bb85ae..f7142ba 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -197,6 +197,7 @@ static void vga_update_memory_access(VGACommonState *s)
break;
}
base += isa_mem_base;
+ assert(offset + size <= s->vram_size);
region = g_malloc(sizeof(*region));
memory_region_init_alias(region, memory_region_owner(&s->vram),
"vga.chain4", &s->vram, offset, size);
@@ -741,11 +742,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
vbe_fixup_regs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
vga_update_memory_access(s);
@@ -846,13 +843,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
@@ -909,6 +914,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
@@ -922,6 +928,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
@@ -995,6 +1004,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
--
1.9.1
[-- Attachment #18: xsa179-qemuu-4.5-0002-vga-add-vbe_enabled-helper.patch --]
[-- Type: application/octet-stream, Size: 2179 bytes --]
From fcd262a966c72dac4127d5fc4a9da3cf242395dd Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:11:34 +0200
Subject: [PATCH 2/5] vga: add vbe_enabled() helper
Makes code a bit easier to read.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index f7142ba..d493b0a 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -166,6 +166,11 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static inline bool vbe_enabled(VGACommonState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
static void vga_update_memory_access(VGACommonState *s)
{
MemoryRegion *region, *old_region = s->chain4_alias;
@@ -589,7 +594,7 @@ static void vbe_fixup_regs(VGACommonState *s)
uint16_t *r = s->vbe_regs;
uint32_t bits, linelength, maxy, offset;
- if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -1170,7 +1175,7 @@ static void vga_get_offsets(VGACommonState *s,
{
uint32_t start_addr, line_offset, line_compare;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1623,7 +1628,7 @@ static int vga_get_bpp(VGACommonState *s)
{
int ret;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else {
ret = 0;
@@ -1635,7 +1640,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
{
int width, height;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else {
--
1.9.1
[-- Attachment #19: xsa179-qemuu-4.5-0003-vga-factor-out-vga-register-setup.patch --]
[-- Type: application/octet-stream, Size: 5279 bytes --]
From 60c87d425c41f43ac81cb33b27af6846f022b45c Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:24:18 +0200
Subject: [PATCH 3/5] vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer. Move that code to a separate function so we can call it
from other places too.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 79 +++++++++++++++++++++++++++++++-------------------------
1 file changed, 44 insertions(+), 35 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index d493b0a..3e4c52e 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -669,6 +669,49 @@ static void vbe_fixup_regs(VGACommonState *s)
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGACommonState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+ }
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGACommonState *s = opaque;
@@ -755,53 +798,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
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;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen (should be done in BIOS) */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode (should be done
- in BIOS) */
- /* graphic mode + memory map 1 */
- s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
- VGA_GR06_GRAPHICS_MODE;
- s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
- s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[VGA_CRTC_H_DISP] =
- (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[VGA_CRTC_V_DISP_END] = h;
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
- s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
- s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- /* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
- /* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
- }
- s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
- (shift_control << 5);
- s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
/* XXX: the bios should do that */
s->bank_offset = 0;
--
1.9.1
[-- Attachment #20: xsa179-qemuu-4.5-0004-vga-update-vga-register-setup-on-vbe-changes.patch --]
[-- Type: application/octet-stream, Size: 977 bytes --]
From 49484ebb79e4e4edac2609fdaa6ef3ac1a4ee6d0 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:39:22 +0200
Subject: [PATCH 4/5] vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 3e4c52e..f265b97 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -788,6 +788,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
val &= s->vbe_bank_mask;
--
1.9.1
[-- Attachment #21: xsa179-qemuu-4.5-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch --]
[-- Type: application/octet-stream, Size: 2856 bytes --]
From 1109b8bd05947ac09b6f24f46a9f784c39cac46e Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:48:06 +0200
Subject: [PATCH 5/5] vga: make sure vga register setup for vbe stays intact
(CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode. This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.
Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.
Which is good for one or another buffer overflow. Not that
critical as they typically read overflows happening somewhere
in the display code. So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.
Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index f265b97..a3feb2d 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -166,6 +166,8 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static void vbe_update_vgaregs(VGACommonState *s);
+
static inline bool vbe_enabled(VGACommonState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
@@ -509,6 +511,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+ vbe_update_vgaregs(s);
if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
s->update_retrace_info(s);
}
@@ -540,6 +543,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
vga_update_memory_access(s);
break;
case VGA_CRT_IM:
@@ -558,10 +562,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->cr_index == VGA_CRTC_OVERFLOW) {
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
(val & 0x10);
+ vbe_update_vgaregs(s);
}
return;
}
s->cr[s->cr_index] = val;
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case VGA_CRTC_H_TOTAL:
--
1.9.1
[-- Attachment #22: xsa179-qemuu-4.6-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch --]
[-- Type: application/octet-stream, Size: 4403 bytes --]
From b16db5ab2d0c5ff755e08942f4c8e8f9f8618eae Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 08:49:10 +0200
Subject: [PATCH 1/5] vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000
and it supports a different access modes with different address
calculations.
The VBE bochs extentions support banked access too, using the
VBE_DISPI_INDEX_BANK register. The code tries to take the different
address calculations into account and applies different limits to
VBE_DISPI_INDEX_BANK depending on the current access mode.
Which is probably effective in stopping misprogramming by accident.
But from a security point of view completely useless as an attacker
can easily change access modes after setting the bank register.
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
instead.
Fixes: CVE-2016-3710
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 52eaf05..b577712 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -178,6 +178,7 @@ static void vga_update_memory_access(VGACommonState *s)
break;
}
base += isa_mem_base;
+ assert(offset + size <= s->vram_size);
memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
"vga.chain4", &s->vram, offset, size);
memory_region_add_subregion_overlap(s->legacy_address_space, base,
@@ -715,11 +716,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
vbe_fixup_regs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
vga_update_memory_access(s);
@@ -818,13 +815,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
@@ -881,6 +886,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
@@ -894,6 +900,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
@@ -967,6 +976,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
--
1.9.1
[-- Attachment #23: xsa179-qemuu-4.6-0002-vga-add-vbe_enabled-helper.patch --]
[-- Type: application/octet-stream, Size: 2153 bytes --]
From e026859e9aecf8635daf06e9fc2325239f458959 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:11:34 +0200
Subject: [PATCH 2/5] vga: add vbe_enabled() helper
Makes code a bit easier to read.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index b577712..ebf63ff 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -140,6 +140,11 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static inline bool vbe_enabled(VGACommonState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
static void vga_update_memory_access(VGACommonState *s)
{
hwaddr base, offset, size;
@@ -563,7 +568,7 @@ static void vbe_fixup_regs(VGACommonState *s)
uint16_t *r = s->vbe_regs;
uint32_t bits, linelength, maxy, offset;
- if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -1057,7 +1062,7 @@ static void vga_get_offsets(VGACommonState *s,
{
uint32_t start_addr, line_offset, line_compare;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1382,7 +1387,7 @@ static int vga_get_bpp(VGACommonState *s)
{
int ret;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else {
ret = 0;
@@ -1394,7 +1399,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
{
int width, height;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else {
--
1.9.1
[-- Attachment #24: xsa179-qemuu-4.6-0003-vga-factor-out-vga-register-setup.patch --]
[-- Type: application/octet-stream, Size: 5172 bytes --]
From b36a4e26caf7a050a6e8593527c26bfa4f47a758 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:24:18 +0200
Subject: [PATCH 3/5] vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer. Move that code to a separate function so we can call it
from other places too.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 78 ++++++++++++++++++++++++++++++++------------------------
1 file changed, 44 insertions(+), 34 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index ebf63ff..fb822f4 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -643,6 +643,49 @@ static void vbe_fixup_regs(VGACommonState *s)
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGACommonState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+ }
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGACommonState *s = opaque;
@@ -729,52 +772,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
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;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode */
- /* graphic mode + memory map 1 */
- s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
- VGA_GR06_GRAPHICS_MODE;
- s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
- s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[VGA_CRTC_H_DISP] =
- (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[VGA_CRTC_V_DISP_END] = h;
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
- s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
- s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- /* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
- /* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
- }
- s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
- (shift_control << 5);
- s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
s->bank_offset = 0;
}
--
1.9.1
[-- Attachment #25: xsa179-qemuu-4.6-0004-vga-update-vga-register-setup-on-vbe-changes.patch --]
[-- Type: application/octet-stream, Size: 977 bytes --]
From ef8bd1b26a597ae7c306227655626640093cb7a2 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:39:22 +0200
Subject: [PATCH 4/5] vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index fb822f4..3739758 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -762,6 +762,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
val &= s->vbe_bank_mask;
--
1.9.1
[-- Attachment #26: xsa179-qemuu-4.6-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch --]
[-- Type: application/octet-stream, Size: 2856 bytes --]
From 92456c0c361d5da858d544647c6246ec78ed922b Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:48:06 +0200
Subject: [PATCH 5/5] vga: make sure vga register setup for vbe stays intact
(CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode. This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.
Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.
Which is good for one or another buffer overflow. Not that
critical as they typically read overflows happening somewhere
in the display code. So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.
Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 3739758..e7be97e 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -140,6 +140,8 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static void vbe_update_vgaregs(VGACommonState *s);
+
static inline bool vbe_enabled(VGACommonState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
@@ -483,6 +485,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+ vbe_update_vgaregs(s);
if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
s->update_retrace_info(s);
}
@@ -514,6 +517,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
vga_update_memory_access(s);
break;
case VGA_CRT_IM:
@@ -532,10 +536,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->cr_index == VGA_CRTC_OVERFLOW) {
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
(val & 0x10);
+ vbe_update_vgaregs(s);
}
return;
}
s->cr[s->cr_index] = val;
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case VGA_CRTC_H_TOTAL:
--
1.9.1
[-- Attachment #27: xsa179-qemut-unstable-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch --]
[-- Type: application/octet-stream, Size: 3977 bytes --]
From bebb4f580901fb638016d9851a28dbb83d44b3a6 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 08:49:10 +0200
Subject: [PATCH 1/5] vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000
and it supports a different access modes with different address
calculations.
The VBE bochs extentions support banked access too, using the
VBE_DISPI_INDEX_BANK register. The code tries to take the different
address calculations into account and applies different limits to
VBE_DISPI_INDEX_BANK depending on the current access mode.
Which is probably effective in stopping misprogramming by accident.
But from a security point of view completely useless as an attacker
can easily change access modes after setting the bank register.
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
instead.
Fixes: CVE-2016-3710
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
[Backport to qemu-xen-tradition]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
hw/vga.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/hw/vga.c b/hw/vga.c
index e8b1ce0..72256f1 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -34,6 +34,8 @@
#include "qemu-timer.h"
+#include <assert.h>
+
//#define DEBUG_VGA
//#define DEBUG_VGA_MEM
//#define DEBUG_VGA_REG
@@ -684,11 +686,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
vbe_fixup_regs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
break;
@@ -787,13 +785,21 @@ uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
if (s->sr[4] & 0x08) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[5] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[4] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[5] & 0x08)) {
@@ -880,6 +886,7 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[2] & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x%x]\n", addr);
@@ -893,6 +900,9 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
mask = (1 << plane);
if (s->sr[2] & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x%x]\n", addr);
@@ -965,6 +975,9 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
mask = s->sr[2];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
--
2.1.4
[-- Attachment #28: xsa179-qemut-unstable-0002-vga-add-vbe_enabled-helper.patch --]
[-- Type: application/octet-stream, Size: 2185 bytes --]
From 34db09fb9967441408a1ff0579d553222cf17441 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:11:34 +0200
Subject: [PATCH 2/5] vga: add vbe_enabled() helper
Makes code a bit easier to read.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
[Backport to qemu-xen-tradition]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
hw/vga.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/vga.c b/hw/vga.c
index 72256f1..f39a2ed 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -160,6 +160,11 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static inline bool vbe_enabled(VGAState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
static void vga_bios_init(VGAState *s);
static void vga_screen_dump(void *opaque, const char *filename);
@@ -535,7 +540,7 @@ 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)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -1165,7 +1170,7 @@ static void vga_get_offsets(VGAState *s,
{
uint32_t start_addr, line_offset, line_compare;
#ifdef CONFIG_BOCHS_VBE
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1551,7 +1556,7 @@ static int vga_get_bpp(VGAState *s)
{
int ret;
#ifdef CONFIG_BOCHS_VBE
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else
#endif
@@ -1566,7 +1571,7 @@ static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
int width, height;
#ifdef CONFIG_BOCHS_VBE
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else
--
2.1.4
[-- Attachment #29: xsa179-qemut-unstable-0003-vga-factor-out-vga-register-setup.patch --]
[-- Type: application/octet-stream, Size: 4707 bytes --]
From df228023ce39e8b72bd5a198b8703319b8b9ca23 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:24:18 +0200
Subject: [PATCH 3/5] vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer. Move that code to a separate function so we can call it
from other places too.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
[Backport to qemu-xen-tradition]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
hw/vga.c | 70 +++++++++++++++++++++++++++++++++++++---------------------------
1 file changed, 41 insertions(+), 29 deletions(-)
diff --git a/hw/vga.c b/hw/vga.c
index f39a2ed..dba93d7 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -615,6 +615,46 @@ static void vbe_fixup_regs(VGAState *s)
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGAState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05;
+ s->cr[0x17] |= 3; /* no CGA modes */
+ s->cr[0x13] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[0x12] = h;
+ s->cr[0x07] = (s->cr[0x07] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[0x18] = 0xff;
+ s->cr[0x07] |= 0x10;
+ s->cr[0x09] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr[0x01] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr[4] |= 0x08;
+ /* activate all planes */
+ s->sr[2] |= 0x0f;
+ }
+ s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
+ s->cr[0x09] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGAState *s = opaque;
@@ -698,7 +738,6 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
if (s->vram_gmfn != s->lfb_addr) {
set_vram_mapping(s, s->lfb_addr, s->lfb_end);
@@ -709,40 +748,13 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen (should be done in BIOS) */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode (should be done
- in BIOS) */
- s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
- s->cr[0x17] |= 3; /* no CGA modes */
- s->cr[0x13] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[0x12] = h;
- s->cr[0x07] = (s->cr[0x07] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[0x18] = 0xff;
- s->cr[0x07] |= 0x10;
- s->cr[0x09] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[0x01] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- s->sr[4] |= 0x08; /* set chain 4 mode */
- s->sr[2] |= 0x0f; /* activate all planes */
- }
- s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
- s->cr[0x09] &= ~0x9f; /* no double scan */
} else {
/* XXX: the bios should do that */
s->bank_offset = 0;
--
2.1.4
[-- Attachment #30: xsa179-qemut-unstable-0004-vga-update-vga-register-setup-on-vbe-changes.patch --]
[-- Type: application/octet-stream, Size: 975 bytes --]
From 5e840e6292825fcae90f6750a8f57bc989e28c5f Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:39:22 +0200
Subject: [PATCH 4/5] vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
[Backport to qemu-xen-tradition]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
hw/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/vga.c b/hw/vga.c
index dba93d7..b1b501b 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -729,6 +729,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
val &= s->vbe_bank_mask;
--
2.1.4
[-- Attachment #31: xsa179-qemut-unstable-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch --]
[-- Type: application/octet-stream, Size: 3094 bytes --]
From 0b0cf8110e97b0cbd0da73d11163e26978822757 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:48:06 +0200
Subject: [PATCH 5/5] vga: make sure vga register setup for vbe stays intact
(CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode. This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.
Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.
Which is good for one or another buffer overflow. Not that
critical as they typically read overflows happening somewhere
in the display code. So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.
Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
[Backport to qemu-xen-tradition]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
hw/vga.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/hw/vga.c b/hw/vga.c
index b1b501b..5778c7d 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -160,6 +160,8 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static void vbe_update_vgaregs(VGAState *s);
+
static inline bool vbe_enabled(VGAState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
@@ -449,6 +451,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+ vbe_update_vgaregs(s);
if (s->sr_index == 1) s->update_retrace_info(s);
break;
case 0x3c7:
@@ -477,6 +480,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
break;
case 0x3b4:
case 0x3d4:
@@ -490,8 +494,10 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
/* handle CR0-7 protection */
if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
/* can always write bit 4 of CR7 */
- if (s->cr_index == 7)
+ if (s->cr_index == 7) {
s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
+ vbe_update_vgaregs(s);
+ }
return;
}
switch(s->cr_index) {
@@ -507,6 +513,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->cr[s->cr_index] = val;
break;
}
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case 0x00:
--
2.1.4
[-- Attachment #32: Type: text/plain, Size: 126 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Xen Security Advisory 179 (CVE-2016-3710, CVE-2016-3712) - QEMU: Banked access to VGA memory (VBE) uses inconsistent bounds checks
@ 2016-05-10 11:25 Xen.org security team
0 siblings, 0 replies; 2+ messages in thread
From: Xen.org security team @ 2016-05-10 11:25 UTC (permalink / raw)
To: xen-announce, xen-devel, xen-users, oss-security; +Cc: Xen.org security team
[-- Attachment #1: Type: text/plain, Size: 10934 bytes --]
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Xen Security Advisory CVE-2016-3710,CVE-2016-3712 / XSA-179
version 5
QEMU: Banked access to VGA memory (VBE) uses inconsistent bounds checks
UPDATES IN VERSION 5
====================
Fixed credits section. Zuozhi Fzz was mistakenly credited with
CVE-2016-3710, but should have been credited with CVE-2016-3712.
ISSUE DESCRIPTION
=================
Qemu VGA module allows banked access to video memory using the window
at 0xa00000 and it supports different access modes with different
address calculations. But an attacker can easily change access modes
after setting the bank register. This is CVE-2016-3710.
Qemu VGA module allows guest to edit certain registers in 'vbe' and
'vga' modes. ie. guest could set certain 'VGA' registers while in
'VBE' mode. This is CVE-2016-3712.
IMPACT
======
A privileged guest user could use CVE-2016-3710 to exceed the bank
address window and write beyond the said memory area, potentially
leading to arbitrary code execution with privileges of the Qemu
process. If the system is not using stubdomains, this will be in
domain 0.
A privileged guest user could use CVE-2016-3712 to cause potential
integer overflow or OOB read access issues in Qemu, resulting in a DoS
of the guest itself. More dangerous effect, such as data leakage or
code execution, are not known but cannot be ruled out.
VULNERABLE SYSTEMS
==================
Versions of qemu shipped with all Xen versions are vulnerable.
Xen systems running on x86 with HVM guests, with the qemu process
running in dom0 are vulnerable.
Only guests provided with the "stdvga" emulated video card can exploit
the vulnerability. The default "cirrus" emulated video card is not
vulnerable. (With xl the emulated video card is controlled by the
"stdvga=" and "vga=" domain configuration options.)
ARM systems are not vulnerable. Systems using only PV guests are not
vulnerable.
For VMs whose qemu process is running in a stub domain, a successful
attacker will only gain the privileges of that stubdom, which should
be only over the guest itself.
Both upstream-based versions of qemu (device_model_version="qemu-xen")
and `traditional' qemu (device_model_version="qemu-xen-traditional")
are vulnerable.
MITIGATION
==========
Running only PV guests will avoid the issue.
Running HVM guests with the device model in a stubdomain will mitigate
the issue.
Changing the video card emulation to cirrus (stdvga=0, vga="cirrus",
in the xl domain configuraton) will avoid the vulnerability.
CREDITS
=======
CVE-2016-3710 was discovered and reported by "Wei Xiao and Qinghao
Tang of 360 Marvel Team" of 360.cn Inc.
CVE-2016-3712 was discovered and reported by Zuozhi Fzz of Alibaba
Inc.
RESOLUTION
==========
Applying the appropriate attached patch resolves this issue for
systems using upstream-based versions of qemu. Patch 0001 addresses
CVE-2016-3710, and patches 0002-0005 address CVE-2016-3712.
qemu-upstream, xen-unstable:
xsa179-qemuu-unstable-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
xsa179-qemuu-unstable-0002-vga-add-vbe_enabled-helper.patch
xsa179-qemuu-unstable-0003-vga-factor-out-vga-register-setup.patch
xsa179-qemuu-unstable-0004-vga-update-vga-register-setup-on-vbe-changes.patch
xsa179-qemuu-unstable-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
qemu-upstream, xen 4.6:
xsa179-qemuu-4.6-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
xsa179-qemuu-4.6-0002-vga-add-vbe_enabled-helper.patch
xsa179-qemuu-4.6-0003-vga-factor-out-vga-register-setup.patch
xsa179-qemuu-4.6-0004-vga-update-vga-register-setup-on-vbe-changes.patch
xsa179-qemuu-4.6-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
qemu-upstream, xen 4.5:
xsa179-qemuu-4.5-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
xsa179-qemuu-4.5-0002-vga-add-vbe_enabled-helper.patch
xsa179-qemuu-4.5-0003-vga-factor-out-vga-register-setup.patch
xsa179-qemuu-4.5-0004-vga-update-vga-register-setup-on-vbe-changes.patch
xsa179-qemuu-4.5-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
qemu-upstream, xen 4.4:
xsa179-qemuu-4.4-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
xsa179-qemuu-4.4-0002-vga-add-vbe_enabled-helper.patch
xsa179-qemuu-4.4-0003-vga-factor-out-vga-register-setup.patch
xsa179-qemuu-4.4-0004-vga-update-vga-register-setup-on-vbe-changes.patch
xsa179-qemuu-4.4-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
qemu-upstream, xen 4.3:
xsa179-qemuu-4.3-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
xsa179-qemuu-4.3-0002-vga-add-vbe_enabled-helper.patch
xsa179-qemuu-4.3-0003-vga-factor-out-vga-register-setup.patch
xsa179-qemuu-4.3-0004-vga-update-vga-register-setup-on-vbe-changes.patch
xsa179-qemuu-4.3-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
qemu-xen-traditional, unstable:
xsa179-qemut-unstable-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
xsa179-qemut-unstable-0002-vga-add-vbe_enabled-helper.patch
xsa179-qemut-unstable-0003-vga-factor-out-vga-register-setup.patch
xsa179-qemut-unstable-0004-vga-update-vga-register-setup-on-vbe-changes.patch
xsa179-qemut-unstable-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
$ sha256sum xsa179*
e216959d099ed807b282026e1e4d558ce0c0e8ead284ddd9d0581cef5fcef0ad xsa179-qemuu-unstable-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
708e40d85866540567d2d915731c6e9876cd0d6754bc6696650ed71d8e48d710 xsa179-qemuu-unstable-0002-vga-add-vbe_enabled-helper.patch
767007028189bce54df9769ff6cb9db7cd37b5c2afaac86787b30c8f2a03f342 xsa179-qemuu-unstable-0003-vga-factor-out-vga-register-setup.patch
1fb507c307b093e5e4471d4a5e567db419adecbfe772a68bf91722836bcba4cd xsa179-qemuu-unstable-0004-vga-update-vga-register-setup-on-vbe-changes.patch
ff4327d598d2e0912dc3a22ab9ba14d6c79bfa5a154714b6c5da761d5ded403f xsa179-qemuu-unstable-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
059bfa59f39222ad6991e6c0c8338385f2a317e379d02d0c2cb0e5a8138cb329 xsa179-qemuu-4.3-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
c6dfe50d694b75670bbdec78a3ce6293a8da46d5ff8b47f1e0d7e4fac22260bf xsa179-qemuu-4.3-0002-vga-add-vbe_enabled-helper.patch
f57e31e8b81f1161537277a0934013c1fb3bbf57319543dfd10a5dc5fdfb927b xsa179-qemuu-4.3-0003-vga-factor-out-vga-register-setup.patch
14900af2b13d362ffb98c061e76b13965965284399dd9b9f1a4e41b41f34a3a3 xsa179-qemuu-4.3-0004-vga-update-vga-register-setup-on-vbe-changes.patch
2b2e7d306fd95fa74490ee1694af1af9438d7ff738d8c6aecc7d99d4eb96dcb2 xsa179-qemuu-4.3-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
e6108266bf0abada5fc6e0a3ca65c2702fcae610826ead6a215d622ec3ed973a xsa179-qemuu-4.4-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
05bdfae312078b22542e9f18db98fae11dbfd9785184b0b3c8de8c94797e1427 xsa179-qemuu-4.4-0002-vga-add-vbe_enabled-helper.patch
56dee9d0f54357391d5249a01ab28a1879dd7d1a36b4d147d68c62688d8af22b xsa179-qemuu-4.4-0003-vga-factor-out-vga-register-setup.patch
10603f5ffe317de328dc46139a6b5ff6081040ca6368ee1642b5343db9bcfda1 xsa179-qemuu-4.4-0004-vga-update-vga-register-setup-on-vbe-changes.patch
e0dbc47086f0346a9554b98468256bc325d67440f5d786c5825390d293896509 xsa179-qemuu-4.4-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
9b0cfdba369437a3e3da86690cd0c6d9d05e39d1168065e4d11ff2de4e546feb xsa179-qemuu-4.5-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
3c56f255d2ff3e5ae24f15de69cbd4abf3ff0d2dbb63a686937d5e2ab1989d59 xsa179-qemuu-4.5-0002-vga-add-vbe_enabled-helper.patch
b1ddabf50720635efa17a7c57778acd2e1d9fd6a6424038455163991afecb044 xsa179-qemuu-4.5-0003-vga-factor-out-vga-register-setup.patch
0f34eeda817f39d3b5e484d535aa29bae16e7e36b4dc042bc41ef0e1844bf3cb xsa179-qemuu-4.5-0004-vga-update-vga-register-setup-on-vbe-changes.patch
c24b3401a7ed45f853de7c96b998d50461254e9082a706753b814ddcbc285b17 xsa179-qemuu-4.5-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
de59a098a39c1adbc86f3857dbb2b655479f97756d46e017e83b41c1390a98b9 xsa179-qemuu-4.6-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
3686d0b5c3603819fe0eca65ed62161c676e6abd8e676e513f6d4b3d46e7a997 xsa179-qemuu-4.6-0002-vga-add-vbe_enabled-helper.patch
18d01083e2f4000816ecf26d85da5cb337f540da447e6252f348a5b538cc7fa4 xsa179-qemuu-4.6-0003-vga-factor-out-vga-register-setup.patch
811ce206293b54ad601eb0a0e59bee502277c642f73f1ea0bad712efc528f82d xsa179-qemuu-4.6-0004-vga-update-vga-register-setup-on-vbe-changes.patch
2097c9e4eac66a65e07607664d1aaec288c4c8b0f147c73636c1b2532cdd20dd xsa179-qemuu-4.6-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
132fd7f7d1f7bee4d934daefc24ec65080ae09b7d0e07a86edc3b683cad8156a xsa179-qemut-unstable-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch
b83c29c3737415bf05da14c0b856abeb3bdbb77fba7d538956535ed67160abe8 xsa179-qemut-unstable-0002-vga-add-vbe_enabled-helper.patch
834266af0499167e6d8e2e87bb770b79c0e8480ab5ea72064298656ccdd36741 xsa179-qemut-unstable-0003-vga-factor-out-vga-register-setup.patch
a5c3c38340261c7ff44047289aad6276e501930e214c40350056a364469965cd xsa179-qemut-unstable-0004-vga-update-vga-register-setup-on-vbe-changes.patch
4869ad504cba52f537dae102e226b020422e3b6494ffba3b865eb2893bee0e9e xsa179-qemut-unstable-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch
$
DEPLOYMENT DURING EMBARGO
=========================
Deployment of the patches and/or mitigations described above (or
others which are substantially similar) is permitted during the
embargo, even on public-facing systems with untrusted guest users and
administrators.
But: Distribution of updated software is prohibited (except to other
members of the predisclosure list).
Predisclosure list members who wish to deploy significantly different
patches and/or mitigations, please contact the Xen Project Security
Team.
(Note: this during-embargo deployment notice is retained in
post-embargo publicly released Xen Project advisories, even though it
is then no longer applicable. This is to enable the community to have
oversight of the Xen Project Security Team's decisionmaking.)
For more information about permissible uses of embargoed information,
consult the Xen Project community's agreed Security Policy:
http://www.xenproject.org/security-policy.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)
iQEcBAEBAgAGBQJXMcStAAoJEIP+FMlX6CvZ8g4H/i3UdCtqBWhs5ZAa7arEzDLC
GggGZ0MQDriujr+10MN6OyM7W493AxHC2+8Ck0jft1YrUh0ojlVt3/tqd+f4yI1I
1S5ueWQYS0vEqH4lxiftp4MRc9/wWpKnEGdo3437AyDuuZwqDfTjvt8yDrfMLCuI
2v3ofXfSOeBiNYqSSsz3Hbmlb9ZqohGRIGqc74C4D+RKYJlDBVO6GNDMv9lI5tdW
LE5PqaCxndZVO+uFAgIg6tw+GOObk2IyEBi00R5FmkW5g9QP2i2em+/usKAb8l3v
bFjBEuw0SkL/CZF3fpoBNjTej/5HHSJwhB2rDY2NFV1hwmt36G8NPKKwLrcQKdU=
=O3qx
-----END PGP SIGNATURE-----
[-- Attachment #2: xsa179-qemuu-unstable-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch --]
[-- Type: application/octet-stream, Size: 4343 bytes --]
From 3bf1817079bb0d80c0d8a86a7c7dd0bfe90eb82e Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 08:49:10 +0200
Subject: [PATCH 1/5] vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000
and it supports a different access modes with different address
calculations.
The VBE bochs extentions support banked access too, using the
VBE_DISPI_INDEX_BANK register. The code tries to take the different
address calculations into account and applies different limits to
VBE_DISPI_INDEX_BANK depending on the current access mode.
Which is probably effective in stopping misprogramming by accident.
But from a security point of view completely useless as an attacker
can easily change access modes after setting the bank register.
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
instead.
Fixes: CVE-2016-3710
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 657e9f1..b9191ca 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -179,6 +179,7 @@ static void vga_update_memory_access(VGACommonState *s)
size = 0x8000;
break;
}
+ assert(offset + size <= s->vram_size);
memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
"vga.chain4", &s->vram, offset, size);
memory_region_add_subregion_overlap(s->legacy_address_space, base,
@@ -716,11 +717,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
vbe_fixup_regs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
vga_update_memory_access(s);
@@ -819,13 +816,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
@@ -882,6 +887,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
@@ -895,6 +901,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
@@ -968,6 +977,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
--
1.8.3.1
[-- Attachment #3: xsa179-qemuu-unstable-0002-vga-add-vbe_enabled-helper.patch --]
[-- Type: application/octet-stream, Size: 2096 bytes --]
From bfa0f151a564a83b5a26f3e917da98674bf3cf62 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:11:34 +0200
Subject: [PATCH 2/5] vga: add vbe_enabled() helper
Makes code a bit easier to read.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index b9191ca..0c1c5b5 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -142,6 +142,11 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static inline bool vbe_enabled(VGACommonState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
static void vga_update_memory_access(VGACommonState *s)
{
hwaddr base, offset, size;
@@ -564,7 +569,7 @@ static void vbe_fixup_regs(VGACommonState *s)
uint16_t *r = s->vbe_regs;
uint32_t bits, linelength, maxy, offset;
- if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -1058,7 +1063,7 @@ static void vga_get_offsets(VGACommonState *s,
{
uint32_t start_addr, line_offset, line_compare;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1383,7 +1388,7 @@ static int vga_get_bpp(VGACommonState *s)
{
int ret;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else {
ret = 0;
@@ -1395,7 +1400,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
{
int width, height;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else {
--
1.8.3.1
[-- Attachment #4: xsa179-qemuu-unstable-0003-vga-factor-out-vga-register-setup.patch --]
[-- Type: application/octet-stream, Size: 5115 bytes --]
From 7fa5c2c5dc9f9bf878c1e8669eb9644d70a71e71 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:24:18 +0200
Subject: [PATCH 3/5] vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer. Move that code to a separate function so we can call it
from other places too.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 78 ++++++++++++++++++++++++++++++++------------------------
1 file changed, 44 insertions(+), 34 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 0c1c5b5..e12f5ac 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -644,6 +644,49 @@ static void vbe_fixup_regs(VGACommonState *s)
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGACommonState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+ }
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGACommonState *s = opaque;
@@ -730,52 +773,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
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;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode */
- /* graphic mode + memory map 1 */
- s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
- VGA_GR06_GRAPHICS_MODE;
- s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
- s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[VGA_CRTC_H_DISP] =
- (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[VGA_CRTC_V_DISP_END] = h;
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
- s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
- s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- /* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
- /* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
- }
- s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
- (shift_control << 5);
- s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
s->bank_offset = 0;
}
--
1.8.3.1
[-- Attachment #5: xsa179-qemuu-unstable-0004-vga-update-vga-register-setup-on-vbe-changes.patch --]
[-- Type: application/octet-stream, Size: 920 bytes --]
From 2068192dcccd8a80dddfcc8df6164cf9c26e0fc4 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:39:22 +0200
Subject: [PATCH 4/5] vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index e12f5ac..eeeb9c8 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -763,6 +763,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
val &= s->vbe_bank_mask;
--
1.8.3.1
[-- Attachment #6: xsa179-qemuu-unstable-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch --]
[-- Type: application/octet-stream, Size: 2799 bytes --]
From fd3c136b3e1482cd0ec7285d6bc2a3e6a62c38d7 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:48:06 +0200
Subject: [PATCH 5/5] vga: make sure vga register setup for vbe stays intact
(CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode. This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.
Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.
Which is good for one or another buffer overflow. Not that
critical as they typically read overflows happening somewhere
in the display code. So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.
Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index eeeb9c8..4a55ec6 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -142,6 +142,8 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static void vbe_update_vgaregs(VGACommonState *s);
+
static inline bool vbe_enabled(VGACommonState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
@@ -484,6 +486,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+ vbe_update_vgaregs(s);
if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
s->update_retrace_info(s);
}
@@ -515,6 +518,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
vga_update_memory_access(s);
break;
case VGA_CRT_IM:
@@ -533,10 +537,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->cr_index == VGA_CRTC_OVERFLOW) {
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
(val & 0x10);
+ vbe_update_vgaregs(s);
}
return;
}
s->cr[s->cr_index] = val;
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case VGA_CRTC_H_TOTAL:
--
1.8.3.1
[-- Attachment #7: xsa179-qemuu-4.3-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch --]
[-- Type: application/octet-stream, Size: 4334 bytes --]
From 67305fcf4733fb4fb9eacc33436ec66a7c0352ef Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 4 May 2016 17:40:58 +0100
Subject: [PATCH 1/5] vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000
and it supports a different access modes with different address
calculations.
The VBE bochs extentions support banked access too, using the
VBE_DISPI_INDEX_BANK register. The code tries to take the different
address calculations into account and applies different limits to
VBE_DISPI_INDEX_BANK depending on the current access mode.
Which is probably effective in stopping misprogramming by accident.
But from a security point of view completely useless as an attacker
can easily change access modes after setting the bank register.
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
instead.
Fixes: CVE-2016-3710
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/vga.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/hw/vga.c b/hw/vga.c
index 69399db..cd7e7aa 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -200,6 +200,7 @@ static void vga_update_memory_access(VGACommonState *s)
break;
}
base += isa_mem_base;
+ assert(offset + size <= s->vram_size);
region = g_malloc(sizeof(*region));
memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
memory_region_add_subregion_overlap(s->legacy_address_space, base,
@@ -747,11 +748,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
vbe_fixup_regs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
vga_update_memory_access(s);
@@ -852,13 +849,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
@@ -915,6 +920,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
@@ -928,6 +934,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
@@ -1001,6 +1010,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
--
1.9.1
[-- Attachment #8: xsa179-qemuu-4.3-0002-vga-add-vbe_enabled-helper.patch --]
[-- Type: application/octet-stream, Size: 2199 bytes --]
From e7d7c09689c725be4f0b489b4ba3b741c5d9ab31 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 4 May 2016 17:41:39 +0100
Subject: [PATCH 2/5] vga: add vbe_enabled() helper
Makes code a bit easier to read.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/vga.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/vga.c b/hw/vga.c
index cd7e7aa..cb1c14d 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -169,6 +169,11 @@ static uint8_t expand4to8[16];
static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
Error **errp);
+static inline bool vbe_enabled(VGACommonState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
static void vga_update_memory_access(VGACommonState *s)
{
MemoryRegion *region, *old_region = s->chain4_alias;
@@ -595,7 +600,7 @@ static void vbe_fixup_regs(VGACommonState *s)
uint16_t *r = s->vbe_regs;
uint32_t bits, linelength, maxy, offset;
- if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -1176,7 +1181,7 @@ static void vga_get_offsets(VGACommonState *s,
{
uint32_t start_addr, line_offset, line_compare;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1626,7 +1631,7 @@ static int vga_get_bpp(VGACommonState *s)
{
int ret;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else {
ret = 0;
@@ -1638,7 +1643,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
{
int width, height;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else {
--
1.9.1
[-- Attachment #9: xsa179-qemuu-4.3-0003-vga-factor-out-vga-register-setup.patch --]
[-- Type: application/octet-stream, Size: 5246 bytes --]
From 2700250c6b28248b70b15fd6e0b4c9db8b2ddfb7 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 4 May 2016 17:42:24 +0100
Subject: [PATCH 3/5] vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer. Move that code to a separate function so we can call it
from other places too.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/vga.c | 79 ++++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 44 insertions(+), 35 deletions(-)
diff --git a/hw/vga.c b/hw/vga.c
index cb1c14d..ad7ca49 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -675,6 +675,49 @@ static void vbe_fixup_regs(VGACommonState *s)
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGACommonState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+ }
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGACommonState *s = opaque;
@@ -761,53 +804,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
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;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen (should be done in BIOS) */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode (should be done
- in BIOS) */
- /* graphic mode + memory map 1 */
- s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
- VGA_GR06_GRAPHICS_MODE;
- s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
- s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[VGA_CRTC_H_DISP] =
- (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[VGA_CRTC_V_DISP_END] = h;
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
- s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
- s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- /* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
- /* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
- }
- s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
- (shift_control << 5);
- s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
/* XXX: the bios should do that */
s->bank_offset = 0;
--
1.9.1
[-- Attachment #10: xsa179-qemuu-4.3-0004-vga-update-vga-register-setup-on-vbe-changes.patch --]
[-- Type: application/octet-stream, Size: 936 bytes --]
From 98be1fb6ea31c130264025de8ec87ad2c7532f21 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 4 May 2016 17:42:59 +0100
Subject: [PATCH 4/5] vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/vga.c b/hw/vga.c
index ad7ca49..1ac8083 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -794,6 +794,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
val &= s->vbe_bank_mask;
--
1.9.1
[-- Attachment #11: xsa179-qemuu-4.3-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch --]
[-- Type: application/octet-stream, Size: 2876 bytes --]
From 0f2e9e6b3c75a87e9ec9a80d7bc914810e3f3da2 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 4 May 2016 17:43:36 +0100
Subject: [PATCH 5/5] vga: make sure vga register setup for vbe stays intact
(CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode. This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.
Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.
Which is good for one or another buffer overflow. Not that
critical as they typically read overflows happening somewhere
in the display code. So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.
Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/vga.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hw/vga.c b/hw/vga.c
index 1ac8083..17b389e 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -169,6 +169,8 @@ static uint8_t expand4to8[16];
static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
Error **errp);
+static void vbe_update_vgaregs(VGACommonState *s);
+
static inline bool vbe_enabled(VGACommonState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
@@ -515,6 +517,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+ vbe_update_vgaregs(s);
if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
s->update_retrace_info(s);
}
@@ -546,6 +549,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
vga_update_memory_access(s);
break;
case VGA_CRT_IM:
@@ -564,10 +568,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->cr_index == VGA_CRTC_OVERFLOW) {
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
(val & 0x10);
+ vbe_update_vgaregs(s);
}
return;
}
s->cr[s->cr_index] = val;
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case VGA_CRTC_H_TOTAL:
--
1.9.1
[-- Attachment #12: xsa179-qemuu-4.4-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch --]
[-- Type: application/octet-stream, Size: 4363 bytes --]
From 25935fd1ed3c4337aa4b61902ec580e17b130b63 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 08:49:10 +0200
Subject: [PATCH 1/5] vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000
and it supports a different access modes with different address
calculations.
The VBE bochs extentions support banked access too, using the
VBE_DISPI_INDEX_BANK register. The code tries to take the different
address calculations into account and applies different limits to
VBE_DISPI_INDEX_BANK depending on the current access mode.
Which is probably effective in stopping misprogramming by accident.
But from a security point of view completely useless as an attacker
can easily change access modes after setting the bank register.
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
instead.
Fixes: CVE-2016-3710
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 430e7ed..69e2554 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -197,6 +197,7 @@ static void vga_update_memory_access(VGACommonState *s)
break;
}
base += isa_mem_base;
+ assert(offset + size <= s->vram_size);
region = g_malloc(sizeof(*region));
memory_region_init_alias(region, memory_region_owner(&s->vram),
"vga.chain4", &s->vram, offset, size);
@@ -745,11 +746,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
vbe_fixup_regs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
vga_update_memory_access(s);
@@ -850,13 +847,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
@@ -913,6 +918,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
@@ -926,6 +932,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
@@ -999,6 +1008,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
--
1.9.1
[-- Attachment #13: xsa179-qemuu-4.4-0002-vga-add-vbe_enabled-helper.patch --]
[-- Type: application/octet-stream, Size: 2179 bytes --]
From 294a6c15a38669f80920b885287191514ab7d9ff Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:11:34 +0200
Subject: [PATCH 2/5] vga: add vbe_enabled() helper
Makes code a bit easier to read.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 69e2554..da1eb4a 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -166,6 +166,11 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static inline bool vbe_enabled(VGACommonState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
static void vga_update_memory_access(VGACommonState *s)
{
MemoryRegion *region, *old_region = s->chain4_alias;
@@ -593,7 +598,7 @@ static void vbe_fixup_regs(VGACommonState *s)
uint16_t *r = s->vbe_regs;
uint32_t bits, linelength, maxy, offset;
- if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -1174,7 +1179,7 @@ static void vga_get_offsets(VGACommonState *s,
{
uint32_t start_addr, line_offset, line_compare;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1627,7 +1632,7 @@ static int vga_get_bpp(VGACommonState *s)
{
int ret;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else {
ret = 0;
@@ -1639,7 +1644,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
{
int width, height;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else {
--
1.9.1
[-- Attachment #14: xsa179-qemuu-4.4-0003-vga-factor-out-vga-register-setup.patch --]
[-- Type: application/octet-stream, Size: 5279 bytes --]
From d377918c23d85f64d01914b43bfabc0a46fe974a Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:24:18 +0200
Subject: [PATCH 3/5] vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer. Move that code to a separate function so we can call it
from other places too.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 79 +++++++++++++++++++++++++++++++-------------------------
1 file changed, 44 insertions(+), 35 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index da1eb4a..cf5f97e 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -673,6 +673,49 @@ static void vbe_fixup_regs(VGACommonState *s)
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGACommonState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+ }
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGACommonState *s = opaque;
@@ -759,53 +802,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
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;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen (should be done in BIOS) */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode (should be done
- in BIOS) */
- /* graphic mode + memory map 1 */
- s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
- VGA_GR06_GRAPHICS_MODE;
- s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
- s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[VGA_CRTC_H_DISP] =
- (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[VGA_CRTC_V_DISP_END] = h;
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
- s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
- s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- /* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
- /* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
- }
- s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
- (shift_control << 5);
- s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
/* XXX: the bios should do that */
s->bank_offset = 0;
--
1.9.1
[-- Attachment #15: xsa179-qemuu-4.4-0004-vga-update-vga-register-setup-on-vbe-changes.patch --]
[-- Type: application/octet-stream, Size: 977 bytes --]
From fbcff82cd7998f93556c28dfc63bbbd7b206c8ce Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:39:22 +0200
Subject: [PATCH 4/5] vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index cf5f97e..63d1a70 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -792,6 +792,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
val &= s->vbe_bank_mask;
--
1.9.1
[-- Attachment #16: xsa179-qemuu-4.4-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch --]
[-- Type: application/octet-stream, Size: 2856 bytes --]
From f7926c73685c2bc7124265f567bafb502864c5dd Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:48:06 +0200
Subject: [PATCH 5/5] vga: make sure vga register setup for vbe stays intact
(CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode. This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.
Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.
Which is good for one or another buffer overflow. Not that
critical as they typically read overflows happening somewhere
in the display code. So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.
Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 63d1a70..dd61246 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -166,6 +166,8 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static void vbe_update_vgaregs(VGACommonState *s);
+
static inline bool vbe_enabled(VGACommonState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
@@ -513,6 +515,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+ vbe_update_vgaregs(s);
if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
s->update_retrace_info(s);
}
@@ -544,6 +547,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
vga_update_memory_access(s);
break;
case VGA_CRT_IM:
@@ -562,10 +566,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->cr_index == VGA_CRTC_OVERFLOW) {
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
(val & 0x10);
+ vbe_update_vgaregs(s);
}
return;
}
s->cr[s->cr_index] = val;
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case VGA_CRTC_H_TOTAL:
--
1.9.1
[-- Attachment #17: xsa179-qemuu-4.5-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch --]
[-- Type: application/octet-stream, Size: 4363 bytes --]
From c9a1a2d7bf3db54b7961df4b8a30946a767b4853 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 08:49:10 +0200
Subject: [PATCH 1/5] vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000
and it supports a different access modes with different address
calculations.
The VBE bochs extentions support banked access too, using the
VBE_DISPI_INDEX_BANK register. The code tries to take the different
address calculations into account and applies different limits to
VBE_DISPI_INDEX_BANK depending on the current access mode.
Which is probably effective in stopping misprogramming by accident.
But from a security point of view completely useless as an attacker
can easily change access modes after setting the bank register.
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
instead.
Fixes: CVE-2016-3710
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 2bb85ae..f7142ba 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -197,6 +197,7 @@ static void vga_update_memory_access(VGACommonState *s)
break;
}
base += isa_mem_base;
+ assert(offset + size <= s->vram_size);
region = g_malloc(sizeof(*region));
memory_region_init_alias(region, memory_region_owner(&s->vram),
"vga.chain4", &s->vram, offset, size);
@@ -741,11 +742,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
vbe_fixup_regs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
vga_update_memory_access(s);
@@ -846,13 +843,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
@@ -909,6 +914,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
@@ -922,6 +928,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
@@ -995,6 +1004,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
--
1.9.1
[-- Attachment #18: xsa179-qemuu-4.5-0002-vga-add-vbe_enabled-helper.patch --]
[-- Type: application/octet-stream, Size: 2179 bytes --]
From fcd262a966c72dac4127d5fc4a9da3cf242395dd Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:11:34 +0200
Subject: [PATCH 2/5] vga: add vbe_enabled() helper
Makes code a bit easier to read.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index f7142ba..d493b0a 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -166,6 +166,11 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static inline bool vbe_enabled(VGACommonState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
static void vga_update_memory_access(VGACommonState *s)
{
MemoryRegion *region, *old_region = s->chain4_alias;
@@ -589,7 +594,7 @@ static void vbe_fixup_regs(VGACommonState *s)
uint16_t *r = s->vbe_regs;
uint32_t bits, linelength, maxy, offset;
- if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -1170,7 +1175,7 @@ static void vga_get_offsets(VGACommonState *s,
{
uint32_t start_addr, line_offset, line_compare;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1623,7 +1628,7 @@ static int vga_get_bpp(VGACommonState *s)
{
int ret;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else {
ret = 0;
@@ -1635,7 +1640,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
{
int width, height;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else {
--
1.9.1
[-- Attachment #19: xsa179-qemuu-4.5-0003-vga-factor-out-vga-register-setup.patch --]
[-- Type: application/octet-stream, Size: 5279 bytes --]
From 60c87d425c41f43ac81cb33b27af6846f022b45c Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:24:18 +0200
Subject: [PATCH 3/5] vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer. Move that code to a separate function so we can call it
from other places too.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 79 +++++++++++++++++++++++++++++++-------------------------
1 file changed, 44 insertions(+), 35 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index d493b0a..3e4c52e 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -669,6 +669,49 @@ static void vbe_fixup_regs(VGACommonState *s)
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGACommonState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+ }
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGACommonState *s = opaque;
@@ -755,53 +798,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
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;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen (should be done in BIOS) */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode (should be done
- in BIOS) */
- /* graphic mode + memory map 1 */
- s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
- VGA_GR06_GRAPHICS_MODE;
- s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
- s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[VGA_CRTC_H_DISP] =
- (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[VGA_CRTC_V_DISP_END] = h;
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
- s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
- s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- /* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
- /* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
- }
- s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
- (shift_control << 5);
- s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
/* XXX: the bios should do that */
s->bank_offset = 0;
--
1.9.1
[-- Attachment #20: xsa179-qemuu-4.5-0004-vga-update-vga-register-setup-on-vbe-changes.patch --]
[-- Type: application/octet-stream, Size: 977 bytes --]
From 49484ebb79e4e4edac2609fdaa6ef3ac1a4ee6d0 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:39:22 +0200
Subject: [PATCH 4/5] vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 3e4c52e..f265b97 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -788,6 +788,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
val &= s->vbe_bank_mask;
--
1.9.1
[-- Attachment #21: xsa179-qemuu-4.5-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch --]
[-- Type: application/octet-stream, Size: 2856 bytes --]
From 1109b8bd05947ac09b6f24f46a9f784c39cac46e Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:48:06 +0200
Subject: [PATCH 5/5] vga: make sure vga register setup for vbe stays intact
(CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode. This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.
Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.
Which is good for one or another buffer overflow. Not that
critical as they typically read overflows happening somewhere
in the display code. So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.
Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index f265b97..a3feb2d 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -166,6 +166,8 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static void vbe_update_vgaregs(VGACommonState *s);
+
static inline bool vbe_enabled(VGACommonState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
@@ -509,6 +511,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+ vbe_update_vgaregs(s);
if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
s->update_retrace_info(s);
}
@@ -540,6 +543,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
vga_update_memory_access(s);
break;
case VGA_CRT_IM:
@@ -558,10 +562,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->cr_index == VGA_CRTC_OVERFLOW) {
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
(val & 0x10);
+ vbe_update_vgaregs(s);
}
return;
}
s->cr[s->cr_index] = val;
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case VGA_CRTC_H_TOTAL:
--
1.9.1
[-- Attachment #22: xsa179-qemuu-4.6-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch --]
[-- Type: application/octet-stream, Size: 4403 bytes --]
From b16db5ab2d0c5ff755e08942f4c8e8f9f8618eae Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 08:49:10 +0200
Subject: [PATCH 1/5] vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000
and it supports a different access modes with different address
calculations.
The VBE bochs extentions support banked access too, using the
VBE_DISPI_INDEX_BANK register. The code tries to take the different
address calculations into account and applies different limits to
VBE_DISPI_INDEX_BANK depending on the current access mode.
Which is probably effective in stopping misprogramming by accident.
But from a security point of view completely useless as an attacker
can easily change access modes after setting the bank register.
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
instead.
Fixes: CVE-2016-3710
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 52eaf05..b577712 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -178,6 +178,7 @@ static void vga_update_memory_access(VGACommonState *s)
break;
}
base += isa_mem_base;
+ assert(offset + size <= s->vram_size);
memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
"vga.chain4", &s->vram, offset, size);
memory_region_add_subregion_overlap(s->legacy_address_space, base,
@@ -715,11 +716,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
vbe_fixup_regs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
vga_update_memory_access(s);
@@ -818,13 +815,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
@@ -881,6 +886,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
@@ -894,6 +900,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
@@ -967,6 +976,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
--
1.9.1
[-- Attachment #23: xsa179-qemuu-4.6-0002-vga-add-vbe_enabled-helper.patch --]
[-- Type: application/octet-stream, Size: 2153 bytes --]
From e026859e9aecf8635daf06e9fc2325239f458959 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:11:34 +0200
Subject: [PATCH 2/5] vga: add vbe_enabled() helper
Makes code a bit easier to read.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index b577712..ebf63ff 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -140,6 +140,11 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static inline bool vbe_enabled(VGACommonState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
static void vga_update_memory_access(VGACommonState *s)
{
hwaddr base, offset, size;
@@ -563,7 +568,7 @@ static void vbe_fixup_regs(VGACommonState *s)
uint16_t *r = s->vbe_regs;
uint32_t bits, linelength, maxy, offset;
- if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -1057,7 +1062,7 @@ static void vga_get_offsets(VGACommonState *s,
{
uint32_t start_addr, line_offset, line_compare;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1382,7 +1387,7 @@ static int vga_get_bpp(VGACommonState *s)
{
int ret;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else {
ret = 0;
@@ -1394,7 +1399,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
{
int width, height;
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else {
--
1.9.1
[-- Attachment #24: xsa179-qemuu-4.6-0003-vga-factor-out-vga-register-setup.patch --]
[-- Type: application/octet-stream, Size: 5172 bytes --]
From b36a4e26caf7a050a6e8593527c26bfa4f47a758 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:24:18 +0200
Subject: [PATCH 3/5] vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer. Move that code to a separate function so we can call it
from other places too.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 78 ++++++++++++++++++++++++++++++++------------------------
1 file changed, 44 insertions(+), 34 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index ebf63ff..fb822f4 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -643,6 +643,49 @@ static void vbe_fixup_regs(VGACommonState *s)
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGACommonState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+ }
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGACommonState *s = opaque;
@@ -729,52 +772,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
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;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode */
- /* graphic mode + memory map 1 */
- s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
- VGA_GR06_GRAPHICS_MODE;
- s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
- s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[VGA_CRTC_H_DISP] =
- (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[VGA_CRTC_V_DISP_END] = h;
- s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
- s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
- s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- /* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
- /* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
- }
- s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
- (shift_control << 5);
- s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
s->bank_offset = 0;
}
--
1.9.1
[-- Attachment #25: xsa179-qemuu-4.6-0004-vga-update-vga-register-setup-on-vbe-changes.patch --]
[-- Type: application/octet-stream, Size: 977 bytes --]
From ef8bd1b26a597ae7c306227655626640093cb7a2 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:39:22 +0200
Subject: [PATCH 4/5] vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index fb822f4..3739758 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -762,6 +762,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
val &= s->vbe_bank_mask;
--
1.9.1
[-- Attachment #26: xsa179-qemuu-4.6-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch --]
[-- Type: application/octet-stream, Size: 2856 bytes --]
From 92456c0c361d5da858d544647c6246ec78ed922b Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:48:06 +0200
Subject: [PATCH 5/5] vga: make sure vga register setup for vbe stays intact
(CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode. This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.
Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.
Which is good for one or another buffer overflow. Not that
critical as they typically read overflows happening somewhere
in the display code. So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.
Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
hw/display/vga.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 3739758..e7be97e 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -140,6 +140,8 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static void vbe_update_vgaregs(VGACommonState *s);
+
static inline bool vbe_enabled(VGACommonState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
@@ -483,6 +485,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+ vbe_update_vgaregs(s);
if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
s->update_retrace_info(s);
}
@@ -514,6 +517,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
vga_update_memory_access(s);
break;
case VGA_CRT_IM:
@@ -532,10 +536,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->cr_index == VGA_CRTC_OVERFLOW) {
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
(val & 0x10);
+ vbe_update_vgaregs(s);
}
return;
}
s->cr[s->cr_index] = val;
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case VGA_CRTC_H_TOTAL:
--
1.9.1
[-- Attachment #27: xsa179-qemut-unstable-0001-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch --]
[-- Type: application/octet-stream, Size: 3977 bytes --]
From bebb4f580901fb638016d9851a28dbb83d44b3a6 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 08:49:10 +0200
Subject: [PATCH 1/5] vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000
and it supports a different access modes with different address
calculations.
The VBE bochs extentions support banked access too, using the
VBE_DISPI_INDEX_BANK register. The code tries to take the different
address calculations into account and applies different limits to
VBE_DISPI_INDEX_BANK depending on the current access mode.
Which is probably effective in stopping misprogramming by accident.
But from a security point of view completely useless as an attacker
can easily change access modes after setting the bank register.
Drop the bogus check, add range checks to vga_mem_{readb,writeb}
instead.
Fixes: CVE-2016-3710
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
[Backport to qemu-xen-tradition]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
hw/vga.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/hw/vga.c b/hw/vga.c
index e8b1ce0..72256f1 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -34,6 +34,8 @@
#include "qemu-timer.h"
+#include <assert.h>
+
//#define DEBUG_VGA
//#define DEBUG_VGA_MEM
//#define DEBUG_VGA_REG
@@ -684,11 +686,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
vbe_fixup_regs(s);
break;
case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- val &= (s->vbe_bank_mask >> 2);
- } else {
- val &= s->vbe_bank_mask;
- }
+ val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
break;
@@ -787,13 +785,21 @@ uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
if (s->sr[4] & 0x08) {
/* chain 4 mode : simplest access */
+ assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[5] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[4] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+ addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return 0xff;
+ }
+ ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[5] & 0x08)) {
@@ -880,6 +886,7 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[2] & mask) {
+ assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x%x]\n", addr);
@@ -893,6 +900,9 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
mask = (1 << plane);
if (s->sr[2] & mask) {
addr = ((addr & ~1) << 1) | plane;
+ if (addr >= s->vram_size) {
+ return;
+ }
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x%x]\n", addr);
@@ -965,6 +975,9 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
mask = s->sr[2];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
--
2.1.4
[-- Attachment #28: xsa179-qemut-unstable-0002-vga-add-vbe_enabled-helper.patch --]
[-- Type: application/octet-stream, Size: 2185 bytes --]
From 34db09fb9967441408a1ff0579d553222cf17441 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:11:34 +0200
Subject: [PATCH 2/5] vga: add vbe_enabled() helper
Makes code a bit easier to read.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
[Backport to qemu-xen-tradition]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
hw/vga.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/vga.c b/hw/vga.c
index 72256f1..f39a2ed 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -160,6 +160,11 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static inline bool vbe_enabled(VGAState *s)
+{
+ return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
+}
+
static void vga_bios_init(VGAState *s);
static void vga_screen_dump(void *opaque, const char *filename);
@@ -535,7 +540,7 @@ 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)) {
+ if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -1165,7 +1170,7 @@ static void vga_get_offsets(VGAState *s,
{
uint32_t start_addr, line_offset, line_compare;
#ifdef CONFIG_BOCHS_VBE
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1551,7 +1556,7 @@ static int vga_get_bpp(VGAState *s)
{
int ret;
#ifdef CONFIG_BOCHS_VBE
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else
#endif
@@ -1566,7 +1571,7 @@ static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
int width, height;
#ifdef CONFIG_BOCHS_VBE
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else
--
2.1.4
[-- Attachment #29: xsa179-qemut-unstable-0003-vga-factor-out-vga-register-setup.patch --]
[-- Type: application/octet-stream, Size: 4707 bytes --]
From df228023ce39e8b72bd5a198b8703319b8b9ca23 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:24:18 +0200
Subject: [PATCH 3/5] vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer. Move that code to a separate function so we can call it
from other places too.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
[Backport to qemu-xen-tradition]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
hw/vga.c | 70 +++++++++++++++++++++++++++++++++++++---------------------------
1 file changed, 41 insertions(+), 29 deletions(-)
diff --git a/hw/vga.c b/hw/vga.c
index f39a2ed..dba93d7 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -615,6 +615,46 @@ static void vbe_fixup_regs(VGAState *s)
s->vbe_start_addr = offset / 4;
}
+/* we initialize the VGA graphic mode */
+static void vbe_update_vgaregs(VGAState *s)
+{
+ int h, shift_control;
+
+ if (!vbe_enabled(s)) {
+ /* vbe is turned off -- nothing to do */
+ return;
+ }
+
+ /* graphic mode + memory map 1 */
+ s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05;
+ s->cr[0x17] |= 3; /* no CGA modes */
+ s->cr[0x13] = s->vbe_line_offset >> 3;
+ /* width */
+ s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ /* height (only meaningful if < 1024) */
+ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+ s->cr[0x12] = h;
+ s->cr[0x07] = (s->cr[0x07] & ~0x42) |
+ ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+ /* line compare to 1023 */
+ s->cr[0x18] = 0xff;
+ s->cr[0x07] |= 0x10;
+ s->cr[0x09] |= 0x40;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+ shift_control = 0;
+ s->sr[0x01] &= ~8; /* no double line */
+ } else {
+ shift_control = 2;
+ /* set chain 4 mode */
+ s->sr[4] |= 0x08;
+ /* activate all planes */
+ s->sr[2] |= 0x0f;
+ }
+ s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
+ s->cr[0x09] &= ~0x9f; /* no double scan */
+}
+
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGAState *s = opaque;
@@ -698,7 +738,6 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
if (s->vram_gmfn != s->lfb_addr) {
set_vram_mapping(s, s->lfb_addr, s->lfb_end);
@@ -709,40 +748,13 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
/* clear the screen (should be done in BIOS) */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
-
- /* we initialize the VGA graphic mode (should be done
- in BIOS) */
- s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
- s->cr[0x17] |= 3; /* no CGA modes */
- s->cr[0x13] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[0x12] = h;
- s->cr[0x07] = (s->cr[0x07] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[0x18] = 0xff;
- s->cr[0x07] |= 0x10;
- s->cr[0x09] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[0x01] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- s->sr[4] |= 0x08; /* set chain 4 mode */
- s->sr[2] |= 0x0f; /* activate all planes */
- }
- s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
- s->cr[0x09] &= ~0x9f; /* no double scan */
} else {
/* XXX: the bios should do that */
s->bank_offset = 0;
--
2.1.4
[-- Attachment #30: xsa179-qemut-unstable-0004-vga-update-vga-register-setup-on-vbe-changes.patch --]
[-- Type: application/octet-stream, Size: 975 bytes --]
From 5e840e6292825fcae90f6750a8f57bc989e28c5f Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 15:39:22 +0200
Subject: [PATCH 4/5] vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
[Backport to qemu-xen-tradition]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
hw/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/vga.c b/hw/vga.c
index dba93d7..b1b501b 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -729,6 +729,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
+ vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
val &= s->vbe_bank_mask;
--
2.1.4
[-- Attachment #31: xsa179-qemut-unstable-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch --]
[-- Type: application/octet-stream, Size: 3094 bytes --]
From 0b0cf8110e97b0cbd0da73d11163e26978822757 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 26 Apr 2016 14:48:06 +0200
Subject: [PATCH 5/5] vga: make sure vga register setup for vbe stays intact
(CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode. This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.
Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.
Which is good for one or another buffer overflow. Not that
critical as they typically read overflows happening somewhere
in the display code. So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.
Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
[Backport to qemu-xen-tradition]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
hw/vga.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/hw/vga.c b/hw/vga.c
index b1b501b..5778c7d 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -160,6 +160,8 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
+static void vbe_update_vgaregs(VGAState *s);
+
static inline bool vbe_enabled(VGAState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
@@ -449,6 +451,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+ vbe_update_vgaregs(s);
if (s->sr_index == 1) s->update_retrace_info(s);
break;
case 0x3c7:
@@ -477,6 +480,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vbe_update_vgaregs(s);
break;
case 0x3b4:
case 0x3d4:
@@ -490,8 +494,10 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
/* handle CR0-7 protection */
if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
/* can always write bit 4 of CR7 */
- if (s->cr_index == 7)
+ if (s->cr_index == 7) {
s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
+ vbe_update_vgaregs(s);
+ }
return;
}
switch(s->cr_index) {
@@ -507,6 +513,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->cr[s->cr_index] = val;
break;
}
+ vbe_update_vgaregs(s);
switch(s->cr_index) {
case 0x00:
--
2.1.4
[-- Attachment #32: Type: text/plain, Size: 126 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2016-05-10 11:25 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-05-09 12:00 Xen Security Advisory 179 (CVE-2016-3710, CVE-2016-3712) - QEMU: Banked access to VGA memory (VBE) uses inconsistent bounds checks Xen.org security team
-- strict thread matches above, loose matches on Subject: below --
2016-05-10 11:25 Xen.org security team
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).