Skip to content

Commit

Permalink
hw/usb/hcd-xhci: Fix unbounded loop in xhci_ring_chain_length() (CVE-…
Browse files Browse the repository at this point in the history
…2020-14394)

The loop condition in xhci_ring_chain_length() is under control of
the guest, and additionally the code does not check for failed DMA
transfers (e.g. if reaching the end of the RAM), so the loop there
could run for a very long time or even forever. Fix it by checking
the return value of dma_memory_read() and by introducing a maximum
loop length.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/646
Message-Id: <20220804131300.96368-1-thuth@redhat.com>
Reviewed-by: Mauro Matteo Cascella <mcascell@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
  • Loading branch information
huth committed Aug 16, 2022
1 parent 9c23d71 commit effaf5a
Showing 1 changed file with 19 additions and 4 deletions.
23 changes: 19 additions & 4 deletions hw/usb/hcd-xhci.c
Expand Up @@ -21,6 +21,7 @@

#include "qemu/osdep.h"
#include "qemu/timer.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/queue.h"
#include "migration/vmstate.h"
Expand Down Expand Up @@ -725,10 +726,14 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
bool control_td_set = 0;
uint32_t link_cnt = 0;

while (1) {
do {
TRBType type;
dma_memory_read(xhci->as, dequeue, &trb, TRB_SIZE,
MEMTXATTRS_UNSPECIFIED);
if (dma_memory_read(xhci->as, dequeue, &trb, TRB_SIZE,
MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n",
__func__);
return -1;
}
le64_to_cpus(&trb.parameter);
le32_to_cpus(&trb.status);
le32_to_cpus(&trb.control);
Expand Down Expand Up @@ -762,7 +767,17 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
if (!control_td_set && !(trb.control & TRB_TR_CH)) {
return length;
}
}

/*
* According to the xHCI spec, Transfer Ring segments should have
* a maximum size of 64 kB (see chapter "6 Data Structures")
*/
} while (length < TRB_LINK_LIMIT * 65536 / TRB_SIZE);

qemu_log_mask(LOG_GUEST_ERROR, "%s: exceeded maximum tranfer ring size!\n",
__func__);

return -1;
}

static void xhci_er_reset(XHCIState *xhci, int v)
Expand Down

0 comments on commit effaf5a

Please sign in to comment.