From 7d975d98102d49741d97c5ab0f1507b6f8dd04ac Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Feb 15 2016 22:05:41 +0000 Subject: 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) --- diff --git a/0009-hmp-fix-sendkey-out-of-bounds-write-CVE-2015-8619.patch b/0009-hmp-fix-sendkey-out-of-bounds-write-CVE-2015-8619.patch new file mode 100644 index 0000000..5961343 --- /dev/null +++ b/0009-hmp-fix-sendkey-out-of-bounds-write-CVE-2015-8619.patch @@ -0,0 +1,119 @@ +From: Wolfgang Bumiller +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 +Signed-off-by: Wolfgang Bumiller +Message-Id: <20160113080958.GA18934@olga> +[Comparison with "<" dumbed down, test for junk after strtoul() +tweaked] +Signed-off-by: Markus Armbruster + +(cherry picked from commit 64ffbe04eaafebf4045a3ace52a360c14959d196) +--- + 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 2140605..1904203 100644 +--- a/hmp.c ++++ b/hmp.c +@@ -1734,21 +1734,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)); +@@ -1761,16 +1758,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->type = KEY_VALUE_KIND_NUMBER; + keylist->value->u.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; + } +@@ -1792,7 +1790,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 c249db4..5739bdd 100644 +--- a/include/ui/console.h ++++ b/include/ui/console.h +@@ -433,7 +433,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(int opengl); +diff --git a/ui/input-legacy.c b/ui/input-legacy.c +index e0a39f0..3f28bbc 100644 +--- a/ui/input-legacy.c ++++ b/ui/input-legacy.c +@@ -57,12 +57,13 @@ struct QEMUPutLEDEntry { + static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = + QTAILQ_HEAD_INITIALIZER(led_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; + } + } diff --git a/0010-e1000-eliminate-infinite-loops-on-out-of-bounds-tran.patch b/0010-e1000-eliminate-infinite-loops-on-out-of-bounds-tran.patch new file mode 100644 index 0000000..03e7b33 --- /dev/null +++ b/0010-e1000-eliminate-infinite-loops-on-out-of-bounds-tran.patch @@ -0,0 +1,95 @@ +From: Laszlo Ersek +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" +Cc: Petr Matousek +Cc: Stefano Stabellini +Cc: Prasad Pandit +Cc: Michael Roth +Cc: Jason Wang +Cc: qemu-stable@nongnu.org +RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1296044 +Signed-off-by: Laszlo Ersek +Reviewed-by: Jason Wang +Signed-off-by: Jason Wang +(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 bec06e9..34d0823 100644 +--- a/hw/net/e1000.c ++++ b/hw/net/e1000.c +@@ -908,7 +908,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; +@@ -1165,7 +1166,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); diff --git a/0011-usb-check-page-select-value-while-processing-iTD.patch b/0011-usb-check-page-select-value-while-processing-iTD.patch new file mode 100644 index 0000000..d63c083 --- /dev/null +++ b/0011-usb-check-page-select-value-while-processing-iTD.patch @@ -0,0 +1,49 @@ +From: Prasad J Pandit +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 +Signed-off-by: Prasad J Pandit +Message-id: 1453233406-12165-1-git-send-email-ppandit@redhat.com +Signed-off-by: Gerd Hoffmann +(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 d07f228..c40013e 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); diff --git a/0012-ahci-Do-not-unmap-NULL-addresses.patch b/0012-ahci-Do-not-unmap-NULL-addresses.patch new file mode 100644 index 0000000..d851e1e --- /dev/null +++ b/0012-ahci-Do-not-unmap-NULL-addresses.patch @@ -0,0 +1,40 @@ +From: John Snow +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 +Signed-off-by: John Snow +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 17f1cbd..cdc9299 100644 +--- a/hw/ide/ahci.c ++++ b/hw/ide/ahci.c +@@ -661,6 +661,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; +@@ -677,6 +681,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; diff --git a/0013-target-ppc-rename-and-export-maybe_bswap_register.patch b/0013-target-ppc-rename-and-export-maybe_bswap_register.patch new file mode 100644 index 0000000..caf6386 --- /dev/null +++ b/0013-target-ppc-rename-and-export-maybe_bswap_register.patch @@ -0,0 +1,74 @@ +From: Greg Kurz +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 +Signed-off-by: David Gibson +(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 9706000..1e2516e 100644 +--- a/target-ppc/cpu.h ++++ b/target-ppc/cpu.h +@@ -2355,4 +2355,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); diff --git a/0014-target-ppc-gdbstub-fix-float-registers-for-little-en.patch b/0014-target-ppc-gdbstub-fix-float-registers-for-little-en.patch new file mode 100644 index 0000000..dc71eda --- /dev/null +++ b/0014-target-ppc-gdbstub-fix-float-registers-for-little-en.patch @@ -0,0 +1,45 @@ +From: Greg Kurz +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 +Signed-off-by: David Gibson +(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 e88dc7f..d31d7f6 100644 +--- a/target-ppc/translate_init.c ++++ b/target-ppc/translate_init.c +@@ -8755,10 +8755,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; +@@ -8767,10 +8769,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; + } diff --git a/0015-target-ppc-gdbstub-introduce-avr_need_swap.patch b/0015-target-ppc-gdbstub-introduce-avr_need_swap.patch new file mode 100644 index 0000000..67de0b1 --- /dev/null +++ b/0015-target-ppc-gdbstub-introduce-avr_need_swap.patch @@ -0,0 +1,79 @@ +From: Greg Kurz +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 +Signed-off-by: David Gibson +(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 d31d7f6..18e9e56 100644 +--- a/target-ppc/translate_init.c ++++ b/target-ppc/translate_init.c +@@ -8751,6 +8751,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) { +@@ -8784,13 +8793,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) { +@@ -8807,13 +8816,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) { diff --git a/0016-target-ppc-gdbstub-fix-altivec-registers-for-little-.patch b/0016-target-ppc-gdbstub-fix-altivec-registers-for-little-.patch new file mode 100644 index 0000000..8eb5309 --- /dev/null +++ b/0016-target-ppc-gdbstub-fix-altivec-registers-for-little-.patch @@ -0,0 +1,76 @@ +From: Greg Kurz +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 +Signed-off-by: David Gibson +(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 18e9e56..80d53e4 100644 +--- a/target-ppc/translate_init.c ++++ b/target-ppc/translate_init.c +@@ -8754,9 +8754,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 + } + +@@ -8800,14 +8800,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; +@@ -8816,6 +8820,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); +@@ -8826,10 +8832,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; + } diff --git a/0017-target-ppc-gdbstub-fix-spe-registers-for-little-endi.patch b/0017-target-ppc-gdbstub-fix-spe-registers-for-little-endi.patch new file mode 100644 index 0000000..80b858e --- /dev/null +++ b/0017-target-ppc-gdbstub-fix-spe-registers-for-little-endi.patch @@ -0,0 +1,66 @@ +From: Greg Kurz +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 +Signed-off-by: David Gibson +(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 80d53e4..5ea168c 100644 +--- a/target-ppc/translate_init.c ++++ b/target-ppc/translate_init.c +@@ -8849,6 +8849,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 +@@ -8856,10 +8857,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; +@@ -8870,7 +8873,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); +@@ -8878,10 +8885,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; + } diff --git a/0018-target-ppc-gdbstub-Add-VSX-support.patch b/0018-target-ppc-gdbstub-Add-VSX-support.patch new file mode 100644 index 0000000..1d4219f --- /dev/null +++ b/0018-target-ppc-gdbstub-Add-VSX-support.patch @@ -0,0 +1,139 @@ +From: Anton Blanchard +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 +(fixed little-endian guests) +Signed-off-by: Greg Kurz +Signed-off-by: David Gibson + +(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 b9552fd..7811180 100755 +--- a/configure ++++ b/configure +@@ -5617,20 +5617,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 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c +index 5ea168c..8069f3c 100644 +--- a/target-ppc/translate_init.c ++++ b/target-ppc/translate_init.c +@@ -8897,6 +8897,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; +@@ -9002,6 +9022,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); + diff --git a/0019-target-ppc-kvm-fix-floating-point-registers-sync-on-.patch b/0019-target-ppc-kvm-fix-floating-point-registers-sync-on-.patch new file mode 100644 index 0000000..4e3b651 --- /dev/null +++ b/0019-target-ppc-kvm-fix-floating-point-registers-sync-on-.patch @@ -0,0 +1,85 @@ +From: Greg Kurz +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 +Signed-off-by: David Gibson +(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 ac70f08..acd3275 100644 +--- a/target-ppc/kvm.c ++++ b/target-ppc/kvm.c +@@ -650,8 +650,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); + +@@ -721,10 +726,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 + } + } + } diff --git a/0101-vmdk-Create-streamOptimized-as-version-3.patch b/0101-vmdk-Create-streamOptimized-as-version-3.patch new file mode 100644 index 0000000..44c84fa --- /dev/null +++ b/0101-vmdk-Create-streamOptimized-as-version-3.patch @@ -0,0 +1,34 @@ +From: Fam Zheng +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 +Signed-off-by: Fam Zheng +Signed-off-by: Kevin Wolf +(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 6f819e4..26b76d9 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -1654,7 +1654,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); diff --git a/0102-vmdk-Fix-converting-to-streamOptimized.patch b/0102-vmdk-Fix-converting-to-streamOptimized.patch new file mode 100644 index 0000000..aeb724e --- /dev/null +++ b/0102-vmdk-Fix-converting-to-streamOptimized.patch @@ -0,0 +1,48 @@ +From: Fam Zheng +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 +Signed-off-by: Kevin Wolf +Signed-off-by: Max Reitz +(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 26b76d9..e46271a 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -570,6 +570,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->bs, sizeof(magic), &header, sizeof(header)); + if (ret < 0) { +@@ -644,6 +645,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, +@@ -651,7 +654,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, + error_setg(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, + bdrv_get_device_or_node_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 diff --git a/qemu.spec b/qemu.spec index 1b7191f..6b93a66 100644 --- a/qemu.spec +++ b/qemu.spec @@ -40,7 +40,7 @@ Summary: QEMU is a FAST! processor emulator Name: qemu Version: 2.5.0 -Release: 5%{?dist} +Release: 6%{?dist} Epoch: 2 License: GPLv2+ and LGPLv2+ and BSD Group: Development/Tools @@ -88,6 +88,26 @@ Patch0006: 0006-net-rocker-fix-an-incorrect-array-bounds-check.patch Patch0007: 0007-net-ne2000-fix-bounds-check-in-ioport-operations.patch # CVE-2016-1568: Use-after-free vulnerability in ahci (bz #1297023) Patch0008: 0008-ide-ahci-reset-ncq-object-to-unused-on-error.patch +# CVE-2015-8619: Fix sendkey out of bounds (bz #1292757) +Patch0009: 0009-hmp-fix-sendkey-out-of-bounds-write-CVE-2015-8619.patch +# CVE-2016-1981: infinite loop in e1000 (bz #1299995) +Patch0010: 0010-e1000-eliminate-infinite-loops-on-out-of-bounds-tran.patch +# Fix Out-of-bounds read in usb-ehci (bz #1300234, bz #1299455) +Patch0011: 0011-usb-check-page-select-value-while-processing-iTD.patch +# CVE-2016-2197: ahci: null pointer dereference (bz #1302952) +Patch0012: 0012-ahci-Do-not-unmap-NULL-addresses.patch +# Fix gdbstub for VSX registers for ppc64 (bz #1304377) +Patch0013: 0013-target-ppc-rename-and-export-maybe_bswap_register.patch +Patch0014: 0014-target-ppc-gdbstub-fix-float-registers-for-little-en.patch +Patch0015: 0015-target-ppc-gdbstub-introduce-avr_need_swap.patch +Patch0016: 0016-target-ppc-gdbstub-fix-altivec-registers-for-little-.patch +Patch0017: 0017-target-ppc-gdbstub-fix-spe-registers-for-little-endi.patch +Patch0018: 0018-target-ppc-gdbstub-Add-VSX-support.patch +Patch0019: 0019-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 @@ -1182,6 +1202,14 @@ getent passwd qemu >/dev/null || \ %changelog +* Mon Feb 15 2016 Cole Robinson - 2:2.5.0-6 +- 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) + * Thu Feb 04 2016 Fedora Release Engineering - 2:2.5.0-5 - Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild