|
|
5544c1 |
From 46bfd14f89404e4a0eb93c3d9c5b9745724cee2d Mon Sep 17 00:00:00 2001
|
|
Hans de Goede |
c8dfc6 |
From: Hans de Goede <hdegoede@redhat.com>
|
|
Hans de Goede |
c8dfc6 |
Date: Wed, 29 Aug 2012 10:37:37 +0200
|
|
|
5544c1 |
Subject: [PATCH] ehci: Validate qh is not changed unexpectedly by the guest
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
-combine the qh check with the check for devaddr changes
|
|
Hans de Goede |
c8dfc6 |
-also ensure that p gets set to NULL when the queue gets cancelled on
|
|
Hans de Goede |
c8dfc6 |
devaddr change, which was not done properly before this patch
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
|
5544c1 |
(cherry picked from commit dafe31fc2a8653b535d58f8c7b250c0827b14420)
|
|
|
5544c1 |
|
|
|
5544c1 |
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
|
|
Hans de Goede |
c8dfc6 |
---
|
|
Hans de Goede |
c8dfc6 |
hw/usb/hcd-ehci.c | 39 ++++++++++++++++++++++++++++-----------
|
|
Hans de Goede |
c8dfc6 |
1 file changed, 28 insertions(+), 11 deletions(-)
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
|
Hans de Goede |
c8dfc6 |
index e7c36f4..35eb441 100644
|
|
Hans de Goede |
c8dfc6 |
--- a/hw/usb/hcd-ehci.c
|
|
Hans de Goede |
c8dfc6 |
+++ b/hw/usb/hcd-ehci.c
|
|
Hans de Goede |
c8dfc6 |
@@ -780,6 +780,14 @@ static void ehci_cancel_queue(EHCIQueue *q)
|
|
Hans de Goede |
c8dfc6 |
} while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
+static void ehci_reset_queue(EHCIQueue *q)
|
|
Hans de Goede |
c8dfc6 |
+{
|
|
Hans de Goede |
c8dfc6 |
+ trace_usb_ehci_queue_action(q, "reset");
|
|
Hans de Goede |
c8dfc6 |
+ ehci_cancel_queue(q);
|
|
Hans de Goede |
c8dfc6 |
+ q->dev = NULL;
|
|
Hans de Goede |
c8dfc6 |
+ q->qtdaddr = 0;
|
|
Hans de Goede |
c8dfc6 |
+}
|
|
Hans de Goede |
c8dfc6 |
+
|
|
Hans de Goede |
c8dfc6 |
static void ehci_free_queue(EHCIQueue *q)
|
|
Hans de Goede |
c8dfc6 |
{
|
|
Hans de Goede |
c8dfc6 |
EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues;
|
|
Hans de Goede |
c8dfc6 |
@@ -1755,8 +1763,9 @@ out:
|
|
Hans de Goede |
c8dfc6 |
static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
|
Hans de Goede |
c8dfc6 |
{
|
|
Hans de Goede |
c8dfc6 |
EHCIPacket *p;
|
|
Hans de Goede |
c8dfc6 |
- uint32_t entry, devaddr;
|
|
Hans de Goede |
c8dfc6 |
+ uint32_t entry, devaddr, endp;
|
|
Hans de Goede |
c8dfc6 |
EHCIQueue *q;
|
|
Hans de Goede |
c8dfc6 |
+ EHCIqh qh;
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
entry = ehci_get_fetch_addr(ehci, async);
|
|
Hans de Goede |
c8dfc6 |
q = ehci_find_queue_by_qh(ehci, entry, async);
|
|
Hans de Goede |
c8dfc6 |
@@ -1774,17 +1783,25 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
get_dwords(ehci, NLPTR_GET(q->qhaddr),
|
|
Hans de Goede |
c8dfc6 |
- (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
|
|
Hans de Goede |
c8dfc6 |
- ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
|
|
Hans de Goede |
c8dfc6 |
+ (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
|
|
Hans de Goede |
c8dfc6 |
+ ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh;;
|
|
Hans de Goede |
c8dfc6 |
+
|
|
Hans de Goede |
c8dfc6 |
+ /*
|
|
Hans de Goede |
c8dfc6 |
+ * The overlay area of the qh should never be changed by the guest,
|
|
Hans de Goede |
c8dfc6 |
+ * except when idle, in which case the reset is a nop.
|
|
Hans de Goede |
c8dfc6 |
+ */
|
|
Hans de Goede |
c8dfc6 |
+ devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR);
|
|
Hans de Goede |
c8dfc6 |
+ endp = get_field(qh.epchar, QH_EPCHAR_EP);
|
|
Hans de Goede |
c8dfc6 |
+ if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
|
|
Hans de Goede |
c8dfc6 |
+ (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
|
|
Hans de Goede |
c8dfc6 |
+ (memcmp(&qh.current_qtd, &q->qh.current_qtd,
|
|
Hans de Goede |
c8dfc6 |
+ 9 * sizeof(uint32_t)) != 0) ||
|
|
Hans de Goede |
c8dfc6 |
+ (q->dev != NULL && q->dev->addr != devaddr)) {
|
|
Hans de Goede |
c8dfc6 |
+ ehci_reset_queue(q);
|
|
Hans de Goede |
c8dfc6 |
+ p = NULL;
|
|
Hans de Goede |
c8dfc6 |
+ }
|
|
Hans de Goede |
c8dfc6 |
+ q->qh = qh;
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
- devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
|
|
Hans de Goede |
c8dfc6 |
- if (q->dev != NULL && q->dev->addr != devaddr) {
|
|
Hans de Goede |
c8dfc6 |
- if (!QTAILQ_EMPTY(&q->packets)) {
|
|
Hans de Goede |
c8dfc6 |
- /* should not happen (guest bug) */
|
|
Hans de Goede |
c8dfc6 |
- ehci_cancel_queue(q);
|
|
Hans de Goede |
c8dfc6 |
- }
|
|
Hans de Goede |
c8dfc6 |
- q->dev = NULL;
|
|
Hans de Goede |
c8dfc6 |
- }
|
|
Hans de Goede |
c8dfc6 |
if (q->dev == NULL) {
|
|
Hans de Goede |
c8dfc6 |
q->dev = ehci_find_device(q->ehci, devaddr);
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
--
|
|
|
5544c1 |
1.7.12.1
|
|
Hans de Goede |
c8dfc6 |
|