xhci: limit the number of link trbs we are willing to process

Needed to avoid we run in circles forever in case the guest builds
an endless loop with link trbs.

Reported-by: Li Qiang <liqiang6-s@360.cn>
Tested-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 1476096382-7981-1-git-send-email-kraxel@redhat.com
This commit is contained in:
Gerd Hoffmann 2016-10-10 12:46:22 +02:00
parent 6b39b06339
commit 05f43d44e4

View File

@ -54,6 +54,8 @@
* to the specs when it gets them */ * to the specs when it gets them */
#define ER_FULL_HACK #define ER_FULL_HACK
#define TRB_LINK_LIMIT 4
#define LEN_CAP 0x40 #define LEN_CAP 0x40
#define LEN_OPER (0x400 + 0x10 * MAXPORTS) #define LEN_OPER (0x400 + 0x10 * MAXPORTS)
#define LEN_RUNTIME ((MAXINTRS + 1) * 0x20) #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) dma_addr_t *addr)
{ {
PCIDevice *pci_dev = PCI_DEVICE(xhci); PCIDevice *pci_dev = PCI_DEVICE(xhci);
uint32_t link_cnt = 0;
while (1) { while (1) {
TRBType type; TRBType type;
@ -1026,6 +1029,9 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
ring->dequeue += TRB_SIZE; ring->dequeue += TRB_SIZE;
return type; return type;
} else { } else {
if (++link_cnt > TRB_LINK_LIMIT) {
return 0;
}
ring->dequeue = xhci_mask64(trb->parameter); ring->dequeue = xhci_mask64(trb->parameter);
if (trb->control & TRB_LK_TC) { if (trb->control & TRB_LK_TC) {
ring->ccs = !ring->ccs; ring->ccs = !ring->ccs;
@ -1043,6 +1049,7 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
bool ccs = ring->ccs; bool ccs = ring->ccs;
/* hack to bundle together the two/three TDs that make a setup transfer */ /* hack to bundle together the two/three TDs that make a setup transfer */
bool control_td_set = 0; bool control_td_set = 0;
uint32_t link_cnt = 0;
while (1) { while (1) {
TRBType type; TRBType type;
@ -1058,6 +1065,9 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
type = TRB_TYPE(trb); type = TRB_TYPE(trb);
if (type == TR_LINK) { if (type == TR_LINK) {
if (++link_cnt > TRB_LINK_LIMIT) {
return -length;
}
dequeue = xhci_mask64(trb.parameter); dequeue = xhci_mask64(trb.parameter);
if (trb.control & TRB_LK_TC) { if (trb.control & TRB_LK_TC) {
ccs = !ccs; ccs = !ccs;