Needed to avoid we run in circles forever in case the guest builds an endless loop with link trbs.
Reported-by: Li Qiang <liqiang...@360.cn> Tested-by: P J P <ppan...@redhat.com> Signed-off-by: Gerd Hoffmann <kra...@redhat.com> Message-id: 1476096382-7981-1-git-send-email-kra...@redhat.com --- hw/usb/hcd-xhci.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 726435c..ee4fa48 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -54,6 +54,8 @@ * to the specs when it gets them */ #define ER_FULL_HACK +#define TRB_LINK_LIMIT 4 + #define LEN_CAP 0x40 #define LEN_OPER (0x400 + 0x10 * MAXPORTS) #define LEN_RUNTIME ((MAXINTRS + 1) * 0x20) @@ -1000,6 +1002,7 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb, dma_addr_t *addr) { PCIDevice *pci_dev = PCI_DEVICE(xhci); + uint32_t link_cnt = 0; while (1) { TRBType type; @@ -1026,6 +1029,9 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb, ring->dequeue += TRB_SIZE; return type; } else { + if (++link_cnt > TRB_LINK_LIMIT) { + return 0; + } ring->dequeue = xhci_mask64(trb->parameter); if (trb->control & TRB_LK_TC) { ring->ccs = !ring->ccs; @@ -1043,6 +1049,7 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) bool ccs = ring->ccs; /* hack to bundle together the two/three TDs that make a setup transfer */ bool control_td_set = 0; + uint32_t link_cnt = 0; while (1) { TRBType type; @@ -1058,6 +1065,9 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) type = TRB_TYPE(trb); if (type == TR_LINK) { + if (++link_cnt > TRB_LINK_LIMIT) { + return -length; + } dequeue = xhci_mask64(trb.parameter); if (trb.control & TRB_LK_TC) { ccs = !ccs; -- 1.8.3.1