[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-stable] [PATCH 27/35] e1000: eliminate infinite loops on out-of-bo
From: |
Michael Roth |
Subject: |
[Qemu-stable] [PATCH 27/35] e1000: eliminate infinite loops on out-of-bounds transfer start |
Date: |
Mon, 21 Mar 2016 12:28:25 -0500 |
From: Laszlo Ersek <address@hidden>
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)
Signed-off-by: Michael Roth <address@hidden>
---
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);
--
1.9.1
- [Qemu-stable] [PATCH 01/35] ehci: make idt processing more robust, (continued)
- [Qemu-stable] [PATCH 01/35] ehci: make idt processing more robust, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 14/35] net/dump: fix nfds->filename leak, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 21/35] s390x/css: fix control flags during csch, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 19/35] block/raw-posix: avoid bogus fixup for cylinders on DASD disks, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 16/35] net: ne2000: check ring buffer control registers, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 20/35] s390x/ioinst: set type and len for SEI response, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 24/35] qmp: Fix reference-counting of qnull on empty output visit, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 23/35] cpus: use broadcast on qemu_pause_cond, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 25/35] block: set device_list.tqe_prev to NULL on BDS removal, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 10/35] ivshmem: remove redundant assignment, fix crash with msi=off, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 27/35] e1000: eliminate infinite loops on out-of-bounds transfer start,
Michael Roth <=
- [Qemu-stable] [PATCH 26/35] block: qemu-iotests - add test for snapshot, commit, snapshot bug, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 29/35] hw/virtio: fix double use of a virtio flag, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 30/35] hw/virtio: group virtio flags into an enum, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 32/35] vhost-user: don't merge regions with different fds, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 31/35] fw_cfg: unbreak migration compatibility for 2.4 and earlier machines, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 33/35] target-arm: Make reserved ranges in ID_AA64* spaces RAZ, not UNDEF, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 22/35] fw_cfg: avoid calculating invalid current entry pointer, Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 34/35] quorum: Fix crash in quorum_aio_cb(), Michael Roth, 2016/03/21
- [Qemu-stable] [PATCH 28/35] spapr: skip configuration section during migration of older machines, Michael Roth, 2016/03/21