From 5879f0d649d5112830e8e712d8245ab8d2db5133 Mon Sep 17 00:00:00 2001 From: Mark H Weaver Date: Mon, 22 Feb 2016 10:17:48 -0500 Subject: [PATCH] gnu: qemu: Add fixes for CVE-2015-8619, CVE-2016-1981, CVE-2016-2197. * gnu/packages/patches/qemu-CVE-2015-8619.patch, gnu/packages/patches/qemu-CVE-2016-1981.patch, gnu/packages/patches/qemu-CVE-2016-2197.patch, gnu/packages/patches/qemu-usb-ehci-oob-read.patch: New files. * gnu-system.am (dist_patch_DATA): Add them. * gnu/packages/qemu.scm (qemu)[source]: Add patches. --- gnu-system.am | 4 + gnu/packages/patches/qemu-CVE-2015-8619.patch | 119 ++++++++++++++++++ gnu/packages/patches/qemu-CVE-2016-1981.patch | 95 ++++++++++++++ gnu/packages/patches/qemu-CVE-2016-2197.patch | 40 ++++++ .../patches/qemu-usb-ehci-oob-read.patch | 49 ++++++++ gnu/packages/qemu.scm | 6 +- 6 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 gnu/packages/patches/qemu-CVE-2015-8619.patch create mode 100644 gnu/packages/patches/qemu-CVE-2016-1981.patch create mode 100644 gnu/packages/patches/qemu-CVE-2016-2197.patch create mode 100644 gnu/packages/patches/qemu-usb-ehci-oob-read.patch diff --git a/gnu-system.am b/gnu-system.am index 33032e9070..0d297b42c8 100644 --- a/gnu-system.am +++ b/gnu-system.am @@ -684,10 +684,14 @@ dist_patch_DATA = \ gnu/packages/patches/qemu-CVE-2015-8558.patch \ gnu/packages/patches/qemu-CVE-2015-8567.patch \ gnu/packages/patches/qemu-CVE-2015-8613.patch \ + gnu/packages/patches/qemu-CVE-2015-8619.patch \ gnu/packages/patches/qemu-CVE-2015-8701.patch \ gnu/packages/patches/qemu-CVE-2015-8743.patch \ gnu/packages/patches/qemu-CVE-2016-1568.patch \ gnu/packages/patches/qemu-CVE-2016-1922.patch \ + gnu/packages/patches/qemu-CVE-2016-1981.patch \ + gnu/packages/patches/qemu-CVE-2016-2197.patch \ + gnu/packages/patches/qemu-usb-ehci-oob-read.patch \ gnu/packages/patches/qemu-virtio-9p-use-accessor-to-get-thread-pool.patch \ gnu/packages/patches/qt4-ldflags.patch \ gnu/packages/patches/ratpoison-shell.patch \ diff --git a/gnu/packages/patches/qemu-CVE-2015-8619.patch b/gnu/packages/patches/qemu-CVE-2015-8619.patch new file mode 100644 index 0000000000..5961343d1e --- /dev/null +++ b/gnu/packages/patches/qemu-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/gnu/packages/patches/qemu-CVE-2016-1981.patch b/gnu/packages/patches/qemu-CVE-2016-1981.patch new file mode 100644 index 0000000000..03e7b333c9 --- /dev/null +++ b/gnu/packages/patches/qemu-CVE-2016-1981.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/gnu/packages/patches/qemu-CVE-2016-2197.patch b/gnu/packages/patches/qemu-CVE-2016-2197.patch new file mode 100644 index 0000000000..d851e1ec75 --- /dev/null +++ b/gnu/packages/patches/qemu-CVE-2016-2197.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/gnu/packages/patches/qemu-usb-ehci-oob-read.patch b/gnu/packages/patches/qemu-usb-ehci-oob-read.patch new file mode 100644 index 0000000000..d63c0832b8 --- /dev/null +++ b/gnu/packages/patches/qemu-usb-ehci-oob-read.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/gnu/packages/qemu.scm b/gnu/packages/qemu.scm index 7624cdcae9..1104a2da6a 100644 --- a/gnu/packages/qemu.scm +++ b/gnu/packages/qemu.scm @@ -71,7 +71,11 @@ "qemu-CVE-2015-8613.patch" "qemu-CVE-2015-8701.patch" "qemu-CVE-2015-8743.patch" - "qemu-CVE-2016-1568.patch"))))) + "qemu-CVE-2016-1568.patch" + "qemu-CVE-2015-8619.patch" + "qemu-CVE-2016-1981.patch" + "qemu-usb-ehci-oob-read.patch" + "qemu-CVE-2016-2197.patch"))))) (build-system gnu-build-system) (arguments '(#:phases (alist-replace