Package: qemu / 1:2.8+dfsg-6+deb9u9

xhci-apply-limits-to-loops-CVE-2017-5973.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Mon, 6 Feb 2017 13:21:09 +0100
Subject: xhci: apply limits to loops
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Commit-Id: f89b60f6e5fee3923bedf80e82b4e5efc1bb156b
Bug-Debian: http://bugs.debian.org/855611

Limits should be big enough that normal guest should not hit it.
Add a tracepoint to log them, just in case.  Also, while being
at it, log the existing link trb limit too.

Reported-by: 李强 <liqiang6-s@360.cn>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 1486383669-6421-1-git-send-email-kraxel@redhat.com

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 4acf0c6..cd0960e 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -54,6 +54,8 @@
 #define ER_FULL_HACK
 
 #define TRB_LINK_LIMIT  4
+#define COMMAND_LIMIT   256
+#define TRANSFER_LIMIT  256
 
 #define LEN_CAP         0x40
 #define LEN_OPER        (0x400 + 0x10 * MAXPORTS)
@@ -1027,6 +1029,7 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
             return type;
         } else {
             if (++link_cnt > TRB_LINK_LIMIT) {
+                trace_usb_xhci_enforced_limit("trb-link");
                 return 0;
             }
             ring->dequeue = xhci_mask64(trb->parameter);
@@ -2150,6 +2153,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
     XHCIRing *ring;
     USBEndpoint *ep = NULL;
     uint64_t mfindex;
+    unsigned int count = 0;
     int length;
     int i;
 
@@ -2258,6 +2262,10 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
             epctx->retry = xfer;
             break;
         }
+        if (count++ > TRANSFER_LIMIT) {
+            trace_usb_xhci_enforced_limit("transfers");
+            break;
+        }
     }
 
     ep = xhci_epid_to_usbep(epctx);
@@ -2729,7 +2737,7 @@ static void xhci_process_commands(XHCIState *xhci)
     TRBType type;
     XHCIEvent event = {ER_COMMAND_COMPLETE, CC_SUCCESS};
     dma_addr_t addr;
-    unsigned int i, slotid = 0;
+    unsigned int i, slotid = 0, count = 0;
 
     DPRINTF("xhci_process_commands()\n");
     if (!xhci_running(xhci)) {
@@ -2843,6 +2851,11 @@ static void xhci_process_commands(XHCIState *xhci)
         }
         event.slotid = slotid;
         xhci_event(xhci, &event, 0);
+
+        if (count++ > COMMAND_LIMIT) {
+            trace_usb_xhci_enforced_limit("commands");
+            return;
+        }
     }
 }
 
diff --git a/hw/usb/trace-events b/hw/usb/trace-events
index 2d42fd4..a2c85f0 100644
--- a/hw/usb/trace-events
+++ b/hw/usb/trace-events
@@ -175,6 +175,7 @@ usb_xhci_xfer_retry(void *xfer) "%p"
 usb_xhci_xfer_success(void *xfer, uint32_t bytes) "%p: len %d"
 usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d"
 usb_xhci_unimplemented(const char *item, int nr) "%s (0x%x)"
+usb_xhci_enforced_limit(const char *item) "%s"
 
 # hw/usb/desc.c
 usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
-- 
2.1.4