[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
01/01: gnu: qemu: Add fixes for CVE-2015-8619, CVE-2016-1981, CVE-2016-2
From: |
Mark H. Weaver |
Subject: |
01/01: gnu: qemu: Add fixes for CVE-2015-8619, CVE-2016-1981, CVE-2016-2197. |
Date: |
Mon, 22 Feb 2016 15:26:28 +0000 |
mhw pushed a commit to branch master
in repository guix.
commit 5879f0d649d5112830e8e712d8245ab8d2db5133
Author: Mark H Weaver <address@hidden>
Date: Mon Feb 22 10:17:48 2016 -0500
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 +++++++
gnu/packages/patches/qemu-usb-ehci-oob-read.patch | 49 +++++++++
gnu/packages/qemu.scm | 6 +-
6 files changed, 312 insertions(+), 1 deletions(-)
diff --git a/gnu-system.am b/gnu-system.am
index 33032e9..0d297b4 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 0000000..5961343
--- /dev/null
+++ b/gnu/packages/patches/qemu-CVE-2015-8619.patch
@@ -0,0 +1,119 @@
+From: Wolfgang Bumiller <address@hidden>
+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 <address@hidden>
+Signed-off-by: Wolfgang Bumiller <address@hidden>
+Message-Id: <address@hidden>
+[Comparison with "<" dumbed down, test for junk after strtoul()
+tweaked]
+Signed-off-by: Markus Armbruster <address@hidden>
+
+(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 0000000..03e7b33
--- /dev/null
+++ b/gnu/packages/patches/qemu-CVE-2016-1981.patch
@@ -0,0 +1,95 @@
+From: Laszlo Ersek <address@hidden>
+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" <address@hidden>
+Cc: Petr Matousek <address@hidden>
+Cc: Stefano Stabellini <address@hidden>
+Cc: Prasad Pandit <address@hidden>
+Cc: Michael Roth <address@hidden>
+Cc: Jason Wang <address@hidden>
+Cc: address@hidden
+RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1296044
+Signed-off-by: Laszlo Ersek <address@hidden>
+Reviewed-by: Jason Wang <address@hidden>
+Signed-off-by: Jason Wang <address@hidden>
+(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 0000000..d851e1e
--- /dev/null
+++ b/gnu/packages/patches/qemu-CVE-2016-2197.patch
@@ -0,0 +1,40 @@
+From: John Snow <address@hidden>
+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 <address@hidden>
+Signed-off-by: John Snow <address@hidden>
+Message-id: address@hidden
+(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 0000000..d63c083
--- /dev/null
+++ b/gnu/packages/patches/qemu-usb-ehci-oob-read.patch
@@ -0,0 +1,49 @@
+From: Prasad J Pandit <address@hidden>
+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 <address@hidden>
+Signed-off-by: Prasad J Pandit <address@hidden>
+Message-id: address@hidden
+Signed-off-by: Gerd Hoffmann <address@hidden>
+(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 7624cdc..1104a2d 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