- bsc#963783 - VUL-1: CVE-2016-1981: xen: net: e1000 infinite loop

in start_xmit and e1000_receive_iov routines
  CVE-2016-1981-qemuu-e1000-eliminate-infinite-loops-on-out-of-bounds-transfer.patch
  CVE-2016-1981-qemut-e1000-eliminate-infinite-loops-on-out-of-bounds-transfer.patch

OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=396
This commit is contained in:
Charles Arnold 2016-01-27 20:31:39 +00:00 committed by Git OBS Bridge
parent 39134eb9d2
commit fbfd58d3a2
4 changed files with 201 additions and 2 deletions

View File

@ -0,0 +1,94 @@
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.
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>
RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1296044
Signed-off-by: Laszlo Ersek <address@hidden>
Reviewed-by: Jason Wang <address@hidden>
---
Notes:
Regarding the public posting: we made an honest effort to vet this
vulnerability, and the impact seems low -- no host side reads/writes,
"just" a DoS (infinite loop). We decided the patch could be posted
publicly, for the usual review process. Jason and Prasad checked the
patch in the internal discussion already, but comments, improvements
etc. are clearly welcome. The CVE request is underway. Thanks.
hw/net/e1000.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
Index: xen-4.6.0-testing/tools/qemu-xen-traditional-dir-remote/hw/e1000.c
===================================================================
--- xen-4.6.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/e1000.c
+++ xen-4.6.0-testing/tools/qemu-xen-traditional-dir-remote/hw/e1000.c
@@ -537,7 +537,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;
@@ -727,7 +728,8 @@ e1000_receive(void *opaque, const uint8_
s->mac_reg[RDH] = 0;
s->check_rxov = 1;
/* 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,94 @@
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.
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>
RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1296044
Signed-off-by: Laszlo Ersek <address@hidden>
Reviewed-by: Jason Wang <address@hidden>
---
Notes:
Regarding the public posting: we made an honest effort to vet this
vulnerability, and the impact seems low -- no host side reads/writes,
"just" a DoS (infinite loop). We decided the patch could be posted
publicly, for the usual review process. Jason and Prasad checked the
patch in the internal discussion already, but comments, improvements
etc. are clearly welcome. The CVE request is underway. Thanks.
hw/net/e1000.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
Index: xen-4.6.0-testing/tools/qemu-xen-dir-remote/hw/net/e1000.c
===================================================================
--- xen-4.6.0-testing.orig/tools/qemu-xen-dir-remote/hw/net/e1000.c
+++ xen-4.6.0-testing/tools/qemu-xen-dir-remote/hw/net/e1000.c
@@ -815,7 +815,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;
@@ -1059,7 +1060,8 @@ e1000_receive_iov(NetClientState *nc, co
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

@ -1,3 +1,11 @@
-------------------------------------------------------------------
Wed Jan 27 08:23:26 MST 2016 - carnold@suse.com
- bsc#963783 - VUL-1: CVE-2016-1981: xen: net: e1000 infinite loop
in start_xmit and e1000_receive_iov routines
CVE-2016-1981-qemuu-e1000-eliminate-infinite-loops-on-out-of-bounds-transfer.patch
CVE-2016-1981-qemut-e1000-eliminate-infinite-loops-on-out-of-bounds-transfer.patch
------------------------------------------------------------------- -------------------------------------------------------------------
Wed Jan 20 08:21:42 MST 2016 - carnold@suse.com Wed Jan 20 08:21:42 MST 2016 - carnold@suse.com

View File

@ -1,7 +1,7 @@
# #
# spec file for package xen # spec file for package xen
# #
# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. # Copyright (c) 2016 SUSE LINUX Products GmbH, Nuernberg, Germany.
# #
# All modifications and additions to the file contributed by third parties # All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed # remain the property of their copyright owners, unless otherwise agreed
@ -15,7 +15,6 @@
# Please submit bugfixes or comments via http://bugs.opensuse.org/ # Please submit bugfixes or comments via http://bugs.opensuse.org/
# #
# needssslcertforbuild # needssslcertforbuild
Name: xen Name: xen
@ -277,6 +276,8 @@ Patch281: CVE-2013-4537-qemut-ssi-sd-fix-buffer-overrun-on-invalid-state-l
Patch282: CVE-2015-1779-qemuu-incrementally-decode-websocket-frames.patch Patch282: CVE-2015-1779-qemuu-incrementally-decode-websocket-frames.patch
Patch283: CVE-2015-1779-qemuu-limit-size-of-HTTP-headers-from-websockets-clients.patch Patch283: CVE-2015-1779-qemuu-limit-size-of-HTTP-headers-from-websockets-clients.patch
Patch284: CVE-2013-4539-qemut-tsc210x-fix-buffer-overrun-on-invalid-state-load.patch Patch284: CVE-2013-4539-qemut-tsc210x-fix-buffer-overrun-on-invalid-state-load.patch
Patch285: CVE-2016-1981-qemuu-e1000-eliminate-infinite-loops-on-out-of-bounds-transfer.patch
Patch286: CVE-2016-1981-qemut-e1000-eliminate-infinite-loops-on-out-of-bounds-transfer.patch
# Our platform specific patches # Our platform specific patches
Patch321: xen-destdir.patch Patch321: xen-destdir.patch
Patch322: vif-bridge-no-iptables.patch Patch322: vif-bridge-no-iptables.patch
@ -620,6 +621,8 @@ Authors:
%patch282 -p1 %patch282 -p1
%patch283 -p1 %patch283 -p1
%patch284 -p1 %patch284 -p1
%patch285 -p1
%patch286 -p1
# Our platform specific patches # Our platform specific patches
%patch321 -p1 %patch321 -p1
%patch322 -p1 %patch322 -p1