CVE-2015-8619: Fix sendkey out of bounds (bz #1292757)

CVE-2016-1981: infinite loop in e1000 (bz #1299995)
Fix Out-of-bounds read in usb-ehci (bz #1300234, bz #1299455)
CVE-2016-2197: ahci: null pointer dereference (bz #1302952)
Fix gdbstub for VSX registers for ppc64 (bz #1304377)
Fix qemu-img vmdk images to work with VMware (bz #1299185)
This commit is contained in:
Cole Robinson 2016-02-15 17:07:21 -05:00
parent 6dcc36319f
commit db34050364
14 changed files with 979 additions and 1 deletions

View File

@ -0,0 +1,120 @@
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 13 Jan 2016 09:09:58 +0100
Subject: [PATCH] hmp: fix sendkey out of bounds write (CVE-2015-8619)
When processing 'sendkey' command, hmp_sendkey routine null
terminates the 'keyname_buf' array. This results in an OOB
write issue, if 'keyname_len' was to fall outside of
'keyname_buf' array.
Since the keyname's length is known the keyname_buf can be
removed altogether by adding a length parameter to
index_from_key() and using it for the error output as well.
Reported-by: Ling Liu <liuling-it@360.cn>
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Message-Id: <20160113080958.GA18934@olga>
[Comparison with "<" dumbed down, test for junk after strtoul()
tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
(cherry picked from commit 64ffbe04eaafebf4045a3ace52a360c14959d196)
Signed-off-by: Cole Robinson <crobinso@redhat.com>
---
hmp.c | 18 ++++++++----------
include/ui/console.h | 2 +-
ui/input-legacy.c | 5 +++--
3 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/hmp.c b/hmp.c
index 1b9a317..b058b1f 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1584,21 +1584,18 @@ void hmp_sendkey(Monitor *mon, const QDict *qdict)
int has_hold_time = qdict_haskey(qdict, "hold-time");
int hold_time = qdict_get_try_int(qdict, "hold-time", -1);
Error *err = NULL;
- char keyname_buf[16];
char *separator;
int keyname_len;
while (1) {
separator = strchr(keys, '-');
keyname_len = separator ? separator - keys : strlen(keys);
- pstrcpy(keyname_buf, sizeof(keyname_buf), keys);
/* Be compatible with old interface, convert user inputted "<" */
- if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) {
- pstrcpy(keyname_buf, sizeof(keyname_buf), "less");
+ if (keys[0] == '<' && keyname_len == 1) {
+ keys = "less";
keyname_len = 4;
}
- keyname_buf[keyname_len] = 0;
keylist = g_malloc0(sizeof(*keylist));
keylist->value = g_malloc0(sizeof(*keylist->value));
@@ -1611,16 +1608,17 @@ void hmp_sendkey(Monitor *mon, const QDict *qdict)
}
tmp = keylist;
- if (strstart(keyname_buf, "0x", NULL)) {
+ if (strstart(keys, "0x", NULL)) {
char *endp;
- int value = strtoul(keyname_buf, &endp, 0);
- if (*endp != '\0') {
+ int value = strtoul(keys, &endp, 0);
+ assert(endp <= keys + keyname_len);
+ if (endp != keys + keyname_len) {
goto err_out;
}
keylist->value->kind = KEY_VALUE_KIND_NUMBER;
keylist->value->number = value;
} else {
- int idx = index_from_key(keyname_buf);
+ int idx = index_from_key(keys, keyname_len);
if (idx == Q_KEY_CODE_MAX) {
goto err_out;
}
@@ -1642,7 +1640,7 @@ out:
return;
err_out:
- monitor_printf(mon, "invalid parameter: %s\n", keyname_buf);
+ monitor_printf(mon, "invalid parameter: %.*s\n", keyname_len, keys);
goto out;
}
diff --git a/include/ui/console.h b/include/ui/console.h
index 2f5b9f0..c28ef58 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -352,7 +352,7 @@ static inline int vnc_display_pw_expire(const char *id, time_t expires)
void curses_display_init(DisplayState *ds, int full_screen);
/* input.c */
-int index_from_key(const char *key);
+int index_from_key(const char *key, size_t key_length);
/* gtk.c */
void early_gtk_display_init(void);
diff --git a/ui/input-legacy.c b/ui/input-legacy.c
index 2d4ca19..270672a 100644
--- a/ui/input-legacy.c
+++ b/ui/input-legacy.c
@@ -60,12 +60,13 @@ static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers =
static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers =
QTAILQ_HEAD_INITIALIZER(mouse_handlers);
-int index_from_key(const char *key)
+int index_from_key(const char *key, size_t key_length)
{
int i;
for (i = 0; QKeyCode_lookup[i] != NULL; i++) {
- if (!strcmp(key, QKeyCode_lookup[i])) {
+ if (!strncmp(key, QKeyCode_lookup[i], key_length) &&
+ !QKeyCode_lookup[i][key_length]) {
break;
}
}

View File

@ -0,0 +1,95 @@
From: Laszlo Ersek <lersek@redhat.com>
Date: Tue, 19 Jan 2016 14:17:20 +0100
Subject: [PATCH] e1000: eliminate infinite loops on out-of-bounds transfer
start
The start_xmit() and e1000_receive_iov() functions implement DMA transfers
iterating over a set of descriptors that the guest's e1000 driver
prepares:
- the TDLEN and RDLEN registers store the total size of the descriptor
area,
- while the TDH and RDH registers store the offset (in whole tx / rx
descriptors) into the area where the transfer is supposed to start.
Each time a descriptor is processed, the TDH and RDH register is bumped
(as appropriate for the transfer direction).
QEMU already contains logic to deal with bogus transfers submitted by the
guest:
- Normally, the transmit case wants to increase TDH from its initial value
to TDT. (TDT is allowed to be numerically smaller than the initial TDH
value; wrapping at or above TDLEN bytes to zero is normal.) The failsafe
that QEMU currently has here is a check against reaching the original
TDH value again -- a complete wraparound, which should never happen.
- In the receive case RDH is increased from its initial value until
"total_size" bytes have been received; preferably in a single step, or
in "s->rxbuf_size" byte steps, if the latter is smaller. However, null
RX descriptors are skipped without receiving data, while RDH is
incremented just the same. QEMU tries to prevent an infinite loop
(processing only null RX descriptors) by detecting whether RDH assumes
its original value during the loop. (Again, wrapping from RDLEN to 0 is
normal.)
What both directions miss is that the guest could program TDLEN and RDLEN
so low, and the initial TDH and RDH so high, that these registers will
immediately be truncated to zero, and then never reassume their initial
values in the loop -- a full wraparound will never occur.
The condition that expresses this is:
xdh_start >= s->mac_reg[XDLEN] / sizeof(desc)
i.e., TDH or RDH start out after the last whole rx or tx descriptor that
fits into the TDLEN or RDLEN sized area.
This condition could be checked before we enter the loops, but
pci_dma_read() / pci_dma_write() knows how to fill in buffers safely for
bogus DMA addresses, so we just extend the existing failsafes with the
above condition.
This is CVE-2016-1981.
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Petr Matousek <pmatouse@redhat.com>
Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Cc: Prasad Pandit <ppandit@redhat.com>
Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
Cc: Jason Wang <jasowang@redhat.com>
Cc: qemu-stable@nongnu.org
RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1296044
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
(cherry picked from commit dd793a74882477ca38d49e191110c17dfee51dcc)
---
hw/net/e1000.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index f02b9ce..a365357 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -816,7 +816,8 @@ start_xmit(E1000State *s)
* bogus values to TDT/TDLEN.
* there's nothing too intelligent we could do about this.
*/
- if (s->mac_reg[TDH] == tdh_start) {
+ if (s->mac_reg[TDH] == tdh_start ||
+ tdh_start >= s->mac_reg[TDLEN] / sizeof(desc)) {
DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
break;
@@ -1062,7 +1063,8 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
s->mac_reg[RDH] = 0;
/* see comment in start_xmit; same here */
- if (s->mac_reg[RDH] == rdh_start) {
+ if (s->mac_reg[RDH] == rdh_start ||
+ rdh_start >= s->mac_reg[RDLEN] / sizeof(desc)) {
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
set_ics(s, 0, E1000_ICS_RXO);

View File

@ -0,0 +1,49 @@
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Wed, 20 Jan 2016 01:26:46 +0530
Subject: [PATCH] usb: check page select value while processing iTD
While processing isochronous transfer descriptors(iTD), the page
select(PG) field value could lead to an OOB read access. Add
check to avoid it.
Reported-by: Qinghao Tang <luodalongde@gmail.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Message-id: 1453233406-12165-1-git-send-email-ppandit@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 49d925ce50383a286278143c05511d30ec41a36e)
---
hw/usb/hcd-ehci.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 51d39c6..2f492d9 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1404,21 +1404,23 @@ static int ehci_process_itd(EHCIState *ehci,
if (itd->transact[i] & ITD_XACT_ACTIVE) {
pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
off = itd->transact[i] & ITD_XACT_OFFSET_MASK;
- ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
- ptr2 = (itd->bufptr[pg+1] & ITD_BUFPTR_MASK);
len = get_field(itd->transact[i], ITD_XACT_LENGTH);
if (len > max * mult) {
len = max * mult;
}
-
- if (len > BUFF_SIZE) {
+ if (len > BUFF_SIZE || pg > 6) {
return -1;
}
+ ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
qemu_sglist_init(&ehci->isgl, ehci->device, 2, ehci->as);
if (off + len > 4096) {
/* transfer crosses page border */
+ if (pg == 6) {
+ return -1; /* avoid page pg + 1 */
+ }
+ ptr2 = (itd->bufptr[pg + 1] & ITD_BUFPTR_MASK);
uint32_t len2 = off + len - 4096;
uint32_t len1 = len - len2;
qemu_sglist_add(&ehci->isgl, ptr1 + off, len1);

View File

@ -0,0 +1,40 @@
From: John Snow <jsnow@redhat.com>
Date: Wed, 10 Feb 2016 13:29:40 -0500
Subject: [PATCH] ahci: Do not unmap NULL addresses
Definitely don't try to unmap a garbage address.
Reported-by: Zuozhi fzz <zuozhi.fzz@alibaba-inc.com>
Signed-off-by: John Snow <jsnow@redhat.com>
Message-id: 1454103689-13042-2-git-send-email-jsnow@redhat.com
(cherry picked from commit 99b4cb71069f109b79b27bc629fc0cf0886dbc4b)
---
hw/ide/ahci.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 833fd45..e939df0 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -587,6 +587,10 @@ static bool ahci_map_fis_address(AHCIDevice *ad)
static void ahci_unmap_fis_address(AHCIDevice *ad)
{
+ if (ad->res_fis == NULL) {
+ DPRINTF(ad->port_no, "Attempt to unmap NULL FIS address\n");
+ return;
+ }
dma_memory_unmap(ad->hba->as, ad->res_fis, 256,
DMA_DIRECTION_FROM_DEVICE, 256);
ad->res_fis = NULL;
@@ -603,6 +607,10 @@ static bool ahci_map_clb_address(AHCIDevice *ad)
static void ahci_unmap_clb_address(AHCIDevice *ad)
{
+ if (ad->lst == NULL) {
+ DPRINTF(ad->port_no, "Attempt to unmap NULL CLB address\n");
+ return;
+ }
dma_memory_unmap(ad->hba->as, ad->lst, 1024,
DMA_DIRECTION_FROM_DEVICE, 1024);
ad->lst = NULL;

View File

@ -0,0 +1,74 @@
From: Greg Kurz <gkurz@linux.vnet.ibm.com>
Date: Fri, 15 Jan 2016 16:00:18 +0100
Subject: [PATCH] target-ppc: rename and export maybe_bswap_register()
This helper will be used to support FP, Altivec and VSX registers when
the guest is little-endian.
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
(cherry picked from commit 376dbce0e3abe456fb8c7a3cd40dc369f8b33d30)
---
target-ppc/cpu.h | 1 +
target-ppc/gdbstub.c | 10 +++++-----
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index f15815f..d5a1a5f 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -2328,4 +2328,5 @@ int ppc_get_vcpu_dt_id(PowerPCCPU *cpu);
*/
PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id);
+void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len);
#endif /* !defined (__CPU_PPC_H__) */
diff --git a/target-ppc/gdbstub.c b/target-ppc/gdbstub.c
index 14675f4..b20bb0c 100644
--- a/target-ppc/gdbstub.c
+++ b/target-ppc/gdbstub.c
@@ -88,7 +88,7 @@ static int ppc_gdb_register_len(int n)
the proper ordering for the binary, and cannot be changed.
For system mode, TARGET_WORDS_BIGENDIAN is always set, and we must check
the current mode of the chip to see if we're running in little-endian. */
-static void maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len)
+void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len)
{
#ifndef CONFIG_USER_ONLY
if (!msr_le) {
@@ -158,7 +158,7 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
break;
}
}
- maybe_bswap_register(env, mem_buf, r);
+ ppc_maybe_bswap_register(env, mem_buf, r);
return r;
}
@@ -214,7 +214,7 @@ int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
break;
}
}
- maybe_bswap_register(env, mem_buf, r);
+ ppc_maybe_bswap_register(env, mem_buf, r);
return r;
}
@@ -227,7 +227,7 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
if (!r) {
return r;
}
- maybe_bswap_register(env, mem_buf, r);
+ ppc_maybe_bswap_register(env, mem_buf, r);
if (n < 32) {
/* gprs */
env->gpr[n] = ldtul_p(mem_buf);
@@ -277,7 +277,7 @@ int ppc_cpu_gdb_write_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
if (!r) {
return r;
}
- maybe_bswap_register(env, mem_buf, r);
+ ppc_maybe_bswap_register(env, mem_buf, r);
if (n < 32) {
/* gprs */
env->gpr[n] = ldq_p(mem_buf);

View File

@ -0,0 +1,45 @@
From: Greg Kurz <gkurz@linux.vnet.ibm.com>
Date: Fri, 15 Jan 2016 16:00:25 +0100
Subject: [PATCH] target-ppc: gdbstub: fix float registers for little-endian
guests
Let's reuse the ppc_maybe_bswap_register() helper, like we already do
with the general registers.
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
(cherry picked from commit 385abeb3e356452eace44f3fe15e18c2532dcaa7)
---
target-ppc/translate_init.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index d74f4f0..51fa03c 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8758,10 +8758,12 @@ static int gdb_get_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
stfq_p(mem_buf, env->fpr[n]);
+ ppc_maybe_bswap_register(env, mem_buf, 8);
return 8;
}
if (n == 32) {
stl_p(mem_buf, env->fpscr);
+ ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
return 0;
@@ -8770,10 +8772,12 @@ static int gdb_get_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
+ ppc_maybe_bswap_register(env, mem_buf, 8);
env->fpr[n] = ldfq_p(mem_buf);
return 8;
}
if (n == 32) {
+ ppc_maybe_bswap_register(env, mem_buf, 4);
helper_store_fpscr(env, ldl_p(mem_buf), 0xffffffff);
return 4;
}

View File

@ -0,0 +1,79 @@
From: Greg Kurz <gkurz@linux.vnet.ibm.com>
Date: Fri, 15 Jan 2016 16:00:31 +0100
Subject: [PATCH] target-ppc: gdbstub: introduce avr_need_swap()
This helper will be used to support Altivec registers in little-endian guests.
This patch does not change functionnality.
Note: I had to put the helper some lines away from the gdb_*_avr_reg()
routines to get a more readable patch.
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
(cherry picked from commit 87601e2d5c22d9c1fef0e09978d377f46336c1db)
---
target-ppc/translate_init.c | 37 +++++++++++++++++++++++--------------
1 file changed, 23 insertions(+), 14 deletions(-)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 51fa03c..c1d2db6 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8754,6 +8754,15 @@ static void dump_ppc_insns (CPUPPCState *env)
}
#endif
+static bool avr_need_swap(CPUPPCState *env)
+{
+#ifdef HOST_WORDS_BIGENDIAN
+ return false;
+#else
+ return true;
+#endif
+}
+
static int gdb_get_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
@@ -8787,13 +8796,13 @@ static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
static int gdb_get_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
-#ifdef HOST_WORDS_BIGENDIAN
- stq_p(mem_buf, env->avr[n].u64[0]);
- stq_p(mem_buf+8, env->avr[n].u64[1]);
-#else
- stq_p(mem_buf, env->avr[n].u64[1]);
- stq_p(mem_buf+8, env->avr[n].u64[0]);
-#endif
+ if (!avr_need_swap(env)) {
+ stq_p(mem_buf, env->avr[n].u64[0]);
+ stq_p(mem_buf+8, env->avr[n].u64[1]);
+ } else {
+ stq_p(mem_buf, env->avr[n].u64[1]);
+ stq_p(mem_buf+8, env->avr[n].u64[0]);
+ }
return 16;
}
if (n == 32) {
@@ -8810,13 +8819,13 @@ static int gdb_get_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
-#ifdef HOST_WORDS_BIGENDIAN
- env->avr[n].u64[0] = ldq_p(mem_buf);
- env->avr[n].u64[1] = ldq_p(mem_buf+8);
-#else
- env->avr[n].u64[1] = ldq_p(mem_buf);
- env->avr[n].u64[0] = ldq_p(mem_buf+8);
-#endif
+ if (!avr_need_swap(env)) {
+ env->avr[n].u64[0] = ldq_p(mem_buf);
+ env->avr[n].u64[1] = ldq_p(mem_buf+8);
+ } else {
+ env->avr[n].u64[1] = ldq_p(mem_buf);
+ env->avr[n].u64[0] = ldq_p(mem_buf+8);
+ }
return 16;
}
if (n == 32) {

View File

@ -0,0 +1,76 @@
From: Greg Kurz <gkurz@linux.vnet.ibm.com>
Date: Fri, 15 Jan 2016 16:00:38 +0100
Subject: [PATCH] target-ppc: gdbstub: fix altivec registers for little-endian
guests
Altivec registers are 128-bit wide. They are stored in memory as two
64-bit values that must be byteswapped when the guest is little-endian.
Let's reuse the ppc_maybe_bswap_register() helper for this.
We also need to fix the ordering of the 64-bit elements according to
the target endianness, for both system and user mode.
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
(cherry picked from commit ea499e71506c91aa259a7fdccf1d6b2022f5b530)
---
target-ppc/translate_init.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index c1d2db6..a72e4b6 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8757,9 +8757,9 @@ static void dump_ppc_insns (CPUPPCState *env)
static bool avr_need_swap(CPUPPCState *env)
{
#ifdef HOST_WORDS_BIGENDIAN
- return false;
+ return msr_le;
#else
- return true;
+ return !msr_le;
#endif
}
@@ -8803,14 +8803,18 @@ static int gdb_get_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
stq_p(mem_buf, env->avr[n].u64[1]);
stq_p(mem_buf+8, env->avr[n].u64[0]);
}
+ ppc_maybe_bswap_register(env, mem_buf, 8);
+ ppc_maybe_bswap_register(env, mem_buf + 8, 8);
return 16;
}
if (n == 32) {
stl_p(mem_buf, env->vscr);
+ ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
if (n == 33) {
stl_p(mem_buf, (uint32_t)env->spr[SPR_VRSAVE]);
+ ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
return 0;
@@ -8819,6 +8823,8 @@ static int gdb_get_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
+ ppc_maybe_bswap_register(env, mem_buf, 8);
+ ppc_maybe_bswap_register(env, mem_buf + 8, 8);
if (!avr_need_swap(env)) {
env->avr[n].u64[0] = ldq_p(mem_buf);
env->avr[n].u64[1] = ldq_p(mem_buf+8);
@@ -8829,10 +8835,12 @@ static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
return 16;
}
if (n == 32) {
+ ppc_maybe_bswap_register(env, mem_buf, 4);
env->vscr = ldl_p(mem_buf);
return 4;
}
if (n == 33) {
+ ppc_maybe_bswap_register(env, mem_buf, 4);
env->spr[SPR_VRSAVE] = (target_ulong)ldl_p(mem_buf);
return 4;
}

View File

@ -0,0 +1,66 @@
From: Greg Kurz <gkurz@linux.vnet.ibm.com>
Date: Fri, 15 Jan 2016 16:00:44 +0100
Subject: [PATCH] target-ppc: gdbstub: fix spe registers for little-endian
guests
Let's reuse the ppc_maybe_bswap_register() helper, like we already do
with the general registers.
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
(cherry picked from commit 95f5b540abd964ac3bc9c63434d07681a5a175eb)
---
target-ppc/translate_init.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index a72e4b6..879d283 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8852,6 +8852,7 @@ static int gdb_get_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
if (n < 32) {
#if defined(TARGET_PPC64)
stl_p(mem_buf, env->gpr[n] >> 32);
+ ppc_maybe_bswap_register(env, mem_buf, 4);
#else
stl_p(mem_buf, env->gprh[n]);
#endif
@@ -8859,10 +8860,12 @@ static int gdb_get_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
}
if (n == 32) {
stq_p(mem_buf, env->spe_acc);
+ ppc_maybe_bswap_register(env, mem_buf, 8);
return 8;
}
if (n == 33) {
stl_p(mem_buf, env->spe_fscr);
+ ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
return 0;
@@ -8873,7 +8876,11 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
if (n < 32) {
#if defined(TARGET_PPC64)
target_ulong lo = (uint32_t)env->gpr[n];
- target_ulong hi = (target_ulong)ldl_p(mem_buf) << 32;
+ target_ulong hi;
+
+ ppc_maybe_bswap_register(env, mem_buf, 4);
+
+ hi = (target_ulong)ldl_p(mem_buf) << 32;
env->gpr[n] = lo | hi;
#else
env->gprh[n] = ldl_p(mem_buf);
@@ -8881,10 +8888,12 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
return 4;
}
if (n == 32) {
+ ppc_maybe_bswap_register(env, mem_buf, 8);
env->spe_acc = ldq_p(mem_buf);
return 8;
}
if (n == 33) {
+ ppc_maybe_bswap_register(env, mem_buf, 4);
env->spe_fscr = ldl_p(mem_buf);
return 4;
}

View File

@ -0,0 +1,139 @@
From: Anton Blanchard <anton@samba.org>
Date: Fri, 15 Jan 2016 16:00:51 +0100
Subject: [PATCH] target-ppc: gdbstub: Add VSX support
Add the XML and functions to get and set VSX registers.
Signed-off-by: Anton Blanchard <anton@samba.org>
(fixed little-endian guests)
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
(cherry picked from commit 1438eff302cbc6c85d477fd7181b8a9aeea2efd7)
---
configure | 6 +++---
gdb-xml/power-vsx.xml | 44 ++++++++++++++++++++++++++++++++++++++++++++
target-ppc/translate_init.c | 24 ++++++++++++++++++++++++
3 files changed, 71 insertions(+), 3 deletions(-)
create mode 100644 gdb-xml/power-vsx.xml
diff --git a/configure b/configure
index adbe117..69a5e2d 100755
--- a/configure
+++ b/configure
@@ -5188,20 +5188,20 @@ case "$target_name" in
ppc64)
TARGET_BASE_ARCH=ppc
TARGET_ABI_DIR=ppc
- gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
+ gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml"
;;
ppc64le)
TARGET_ARCH=ppc64
TARGET_BASE_ARCH=ppc
TARGET_ABI_DIR=ppc
- gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
+ gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml"
;;
ppc64abi32)
TARGET_ARCH=ppc64
TARGET_BASE_ARCH=ppc
TARGET_ABI_DIR=ppc
echo "TARGET_ABI32=y" >> $config_target_mak
- gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
+ gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml"
;;
sh4|sh4eb)
TARGET_ARCH=sh4
diff --git a/gdb-xml/power-vsx.xml b/gdb-xml/power-vsx.xml
new file mode 100644
index 0000000..fd290e9
--- /dev/null
+++ b/gdb-xml/power-vsx.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008-2015 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!-- POWER7 VSX registers that do not overlap existing FP and VMX
+ registers. -->
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.vsx">
+ <reg name="vs0h" bitsize="64" type="uint64"/>
+ <reg name="vs1h" bitsize="64" type="uint64"/>
+ <reg name="vs2h" bitsize="64" type="uint64"/>
+ <reg name="vs3h" bitsize="64" type="uint64"/>
+ <reg name="vs4h" bitsize="64" type="uint64"/>
+ <reg name="vs5h" bitsize="64" type="uint64"/>
+ <reg name="vs6h" bitsize="64" type="uint64"/>
+ <reg name="vs7h" bitsize="64" type="uint64"/>
+ <reg name="vs8h" bitsize="64" type="uint64"/>
+ <reg name="vs9h" bitsize="64" type="uint64"/>
+ <reg name="vs10h" bitsize="64" type="uint64"/>
+ <reg name="vs11h" bitsize="64" type="uint64"/>
+ <reg name="vs12h" bitsize="64" type="uint64"/>
+ <reg name="vs13h" bitsize="64" type="uint64"/>
+ <reg name="vs14h" bitsize="64" type="uint64"/>
+ <reg name="vs15h" bitsize="64" type="uint64"/>
+ <reg name="vs16h" bitsize="64" type="uint64"/>
+ <reg name="vs17h" bitsize="64" type="uint64"/>
+ <reg name="vs18h" bitsize="64" type="uint64"/>
+ <reg name="vs19h" bitsize="64" type="uint64"/>
+ <reg name="vs20h" bitsize="64" type="uint64"/>
+ <reg name="vs21h" bitsize="64" type="uint64"/>
+ <reg name="vs22h" bitsize="64" type="uint64"/>
+ <reg name="vs23h" bitsize="64" type="uint64"/>
+ <reg name="vs24h" bitsize="64" type="uint64"/>
+ <reg name="vs25h" bitsize="64" type="uint64"/>
+ <reg name="vs26h" bitsize="64" type="uint64"/>
+ <reg name="vs27h" bitsize="64" type="uint64"/>
+ <reg name="vs28h" bitsize="64" type="uint64"/>
+ <reg name="vs29h" bitsize="64" type="uint64"/>
+ <reg name="vs30h" bitsize="64" type="uint64"/>
+ <reg name="vs31h" bitsize="64" type="uint64"/>
+</feature>
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 879d283..130e27e 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8900,6 +8900,26 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
return 0;
}
+static int gdb_get_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+ stq_p(mem_buf, env->vsr[n]);
+ ppc_maybe_bswap_register(env, mem_buf, 8);
+ return 8;
+ }
+ return 0;
+}
+
+static int gdb_set_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+ ppc_maybe_bswap_register(env, mem_buf, 8);
+ env->vsr[n] = ldq_p(mem_buf);
+ return 8;
+ }
+ return 0;
+}
+
static int ppc_fixup_cpu(PowerPCCPU *cpu)
{
CPUPPCState *env = &cpu->env;
@@ -8997,6 +9017,10 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)
gdb_register_coprocessor(cs, gdb_get_spe_reg, gdb_set_spe_reg,
34, "power-spe.xml", 0);
}
+ if (pcc->insns_flags2 & PPC2_VSX) {
+ gdb_register_coprocessor(cs, gdb_get_vsx_reg, gdb_set_vsx_reg,
+ 32, "power-vsx.xml", 0);
+ }
qemu_init_vcpu(cs);

View File

@ -0,0 +1,85 @@
From: Greg Kurz <gkurz@linux.vnet.ibm.com>
Date: Fri, 15 Jan 2016 16:00:12 +0100
Subject: [PATCH] target-ppc: kvm: fix floating point registers sync on
little-endian hosts
On VSX capable CPUs, the 32 FP registers are mapped to the high-bits
of the 32 first VSX registers. So if you have:
VSR31 = (uint128) 0x0102030405060708090a0b0c0d0e0f00
then
FPR31 = (uint64) 0x0102030405060708
The kernel stores the VSX registers in the fp_state struct following the
host endian element ordering.
On big-endian:
fp_state.fpr[31][0] = 0x0102030405060708
fp_state.fpr[31][1] = 0x090a0b0c0d0e0f00
On little-endian:
fp_state.fpr[31][0] = 0x090a0b0c0d0e0f00
fp_state.fpr[31][1] = 0x0102030405060708
The KVM_GET_ONE_REG and KVM_SET_ONE_REG ioctls preserve this ordering, but
QEMU considers it as big-endian and always copies element [0] to the
fpr[] array and element [1] to the vsr[] array. This does not work with
little-endian hosts, and you will get:
(qemu) p $f31
0x90a0b0c0d0e0f00
instead of:
(qemu) p $f31
0x102030405060708
This patch fixes the element ordering for little-endian hosts.
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
(cherry picked from commit 3a4b791b4c13e02537a5cc572fa3de70bc5f68da)
---
target-ppc/kvm.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 84ae447..7f789d6 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -640,8 +640,13 @@ static int kvm_put_fp(CPUState *cs)
for (i = 0; i < 32; i++) {
uint64_t vsr[2];
+#ifdef HOST_WORDS_BIGENDIAN
vsr[0] = float64_val(env->fpr[i]);
vsr[1] = env->vsr[i];
+#else
+ vsr[0] = env->vsr[i];
+ vsr[1] = float64_val(env->fpr[i]);
+#endif
reg.addr = (uintptr_t) &vsr;
reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i);
@@ -711,10 +716,17 @@ static int kvm_get_fp(CPUState *cs)
vsx ? "VSR" : "FPR", i, strerror(errno));
return ret;
} else {
+#ifdef HOST_WORDS_BIGENDIAN
env->fpr[i] = vsr[0];
if (vsx) {
env->vsr[i] = vsr[1];
}
+#else
+ env->fpr[i] = vsr[1];
+ if (vsx) {
+ env->vsr[i] = vsr[0];
+ }
+#endif
}
}
}

View File

@ -0,0 +1,34 @@
From: Fam Zheng <famz@redhat.com>
Date: Thu, 17 Sep 2015 13:04:10 +0800
Subject: [PATCH] vmdk: Create streamOptimized as version 3
VMware products accept only version 3 for streamOptimized, let's bump
the version.
Reported-by: Radoslav Gerganov <rgerganov@vmware.com>
Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit d62d9dc4b814950dcc8bd261a3e2e9300d9065e6)
---
block/vmdk.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/block/vmdk.c b/block/vmdk.c
index 4c71cde..27d86f0 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1662,7 +1662,13 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
}
magic = cpu_to_be32(VMDK4_MAGIC);
memset(&header, 0, sizeof(header));
- header.version = zeroed_grain ? 2 : 1;
+ if (compress) {
+ header.version = 3;
+ } else if (zeroed_grain) {
+ header.version = 2;
+ } else {
+ header.version = 1;
+ }
header.flags = VMDK4_FLAG_RGD | VMDK4_FLAG_NL_DETECT
| (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0)
| (zeroed_grain ? VMDK4_FLAG_ZERO_GRAIN : 0);

View File

@ -0,0 +1,48 @@
From: Fam Zheng <famz@redhat.com>
Date: Mon, 25 Jan 2016 10:26:23 +0800
Subject: [PATCH] vmdk: Fix converting to streamOptimized
Commit d62d9dc4b8 lifted streamOptimized images's version to 3, but we
now refuse to open version 3 images read-write. We need to make
streamOptimized an exception to allow converting to it. This fixes the
accidentally broken iotests case 059 for the same reason.
Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry picked from commit 3db1d98a20262228373bb973ca62b1ab64b29af4)
---
block/vmdk.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/block/vmdk.c b/block/vmdk.c
index 27d86f0..c551ebc 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -591,6 +591,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
VmdkExtent *extent;
BDRVVmdkState *s = bs->opaque;
int64_t l1_backup_offset = 0;
+ bool compressed;
ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
if (ret < 0) {
@@ -665,6 +666,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
header = footer.header;
}
+ compressed =
+ le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE;
if (le32_to_cpu(header.version) > 3) {
char buf[64];
snprintf(buf, sizeof(buf), "VMDK version %" PRId32,
@@ -672,7 +675,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
bdrv_get_device_name(bs), "vmdk", buf);
return -ENOTSUP;
- } else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR)) {
+ } else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR) &&
+ !compressed) {
/* VMware KB 2064959 explains that version 3 added support for
* persistent changed block tracking (CBT), and backup software can
* read it as version=1 if it doesn't care about the changed area

View File

@ -43,7 +43,7 @@
Summary: QEMU is a FAST! processor emulator
Name: qemu
Version: 2.3.1
Release: 11%{?dist}
Release: 12%{?dist}
Epoch: 2
License: GPLv2+ and LGPLv2+ and BSD
Group: Development/Tools
@ -145,6 +145,26 @@ Patch0034: 0034-scsi-initialise-info-object-with-appropriate-size.patch
# CVE-2015-8743: ne2000: OOB memory access in ioport r/w functions (bz
# #1294787)
Patch0035: 0035-net-ne2000-fix-bounds-check-in-ioport-operations.patch
# CVE-2015-8619: Fix sendkey out of bounds (bz #1292757)
Patch0036: 0036-hmp-fix-sendkey-out-of-bounds-write-CVE-2015-8619.patch
# CVE-2016-1981: infinite loop in e1000 (bz #1299995)
Patch0037: 0037-e1000-eliminate-infinite-loops-on-out-of-bounds-tran.patch
# Fix Out-of-bounds read in usb-ehci (bz #1300234, bz #1299455)
Patch0038: 0038-usb-check-page-select-value-while-processing-iTD.patch
# CVE-2016-2197: ahci: null pointer dereference (bz #1302952)
Patch0039: 0039-ahci-Do-not-unmap-NULL-addresses.patch
# Fix gdbstub for VSX registers for ppc64 (bz #1304377)
Patch0040: 0040-target-ppc-rename-and-export-maybe_bswap_register.patch
Patch0041: 0041-target-ppc-gdbstub-fix-float-registers-for-little-en.patch
Patch0042: 0042-target-ppc-gdbstub-introduce-avr_need_swap.patch
Patch0043: 0043-target-ppc-gdbstub-fix-altivec-registers-for-little-.patch
Patch0044: 0044-target-ppc-gdbstub-fix-spe-registers-for-little-endi.patch
Patch0045: 0045-target-ppc-gdbstub-Add-VSX-support.patch
Patch0046: 0046-target-ppc-kvm-fix-floating-point-registers-sync-on-.patch
# Fix qemu-img vmdk images to work with VMware (bz #1299185)
Patch0101: 0101-vmdk-Create-streamOptimized-as-version-3.patch
Patch0102: 0102-vmdk-Fix-converting-to-streamOptimized.patch
BuildRequires: SDL2-devel
BuildRequires: zlib-devel
@ -1247,6 +1267,14 @@ getent passwd qemu >/dev/null || \
%changelog
* Mon Feb 15 2016 Cole Robinson <crobinso@redhat.com> - 2:2.3.1-12
- CVE-2015-8619: Fix sendkey out of bounds (bz #1292757)
- CVE-2016-1981: infinite loop in e1000 (bz #1299995)
- Fix Out-of-bounds read in usb-ehci (bz #1300234, bz #1299455)
- CVE-2016-2197: ahci: null pointer dereference (bz #1302952)
- Fix gdbstub for VSX registers for ppc64 (bz #1304377)
- Fix qemu-img vmdk images to work with VMware (bz #1299185)
* Wed Jan 20 2016 Cole Robinson <crobinso@redhat.com> - 2:2.3.1-11
- CVE-2015-8567: net: vmxnet3: host memory leakage (bz #1289818)
- CVE-2016-1922: i386: avoid null pointer dereference (bz #1292766)