From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:42433) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T9WH4-0004mJ-DF for qemu-devel@nongnu.org; Thu, 06 Sep 2012 03:13:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1T9WGp-0006MB-HS for qemu-devel@nongnu.org; Thu, 06 Sep 2012 03:13:14 -0400 Received: from mx1.redhat.com ([209.132.183.28]:31814) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T9WGp-0006Lq-8v for qemu-devel@nongnu.org; Thu, 06 Sep 2012 03:12:59 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q867Cw9v019262 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 6 Sep 2012 03:12:58 -0400 From: Gerd Hoffmann Date: Thu, 6 Sep 2012 09:12:07 +0200 Message-Id: <1346915575-12369-7-git-send-email-kraxel@redhat.com> In-Reply-To: <1346915575-12369-1-git-send-email-kraxel@redhat.com> References: <1346915575-12369-1-git-send-email-kraxel@redhat.com> Subject: [Qemu-devel] [PATCH 06/54] ehci: Validate qh is not changed unexpectedly by the guest List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Hans de Goede From: Hans de Goede -combine the qh check with the check for devaddr changes -also ensure that p gets set to NULL when the queue gets cancelled on devaddr change, which was not done properly before this patch Signed-off-by: Hans de Goede --- hw/usb/hcd-ehci.c | 41 +++++++++++++++++++++++++++++------------ 1 files changed, 29 insertions(+), 12 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index e7c36f4..35eb441 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -780,6 +780,14 @@ static void ehci_cancel_queue(EHCIQueue *q) } while ((p = QTAILQ_FIRST(&q->packets)) != NULL); } +static void ehci_reset_queue(EHCIQueue *q) +{ + trace_usb_ehci_queue_action(q, "reset"); + ehci_cancel_queue(q); + q->dev = NULL; + q->qtdaddr = 0; +} + static void ehci_free_queue(EHCIQueue *q) { EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues; @@ -1755,8 +1763,9 @@ out: static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) { EHCIPacket *p; - uint32_t entry, devaddr; + uint32_t entry, devaddr, endp; EHCIQueue *q; + EHCIqh qh; entry = ehci_get_fetch_addr(ehci, async); q = ehci_find_queue_by_qh(ehci, entry, async); @@ -1774,17 +1783,25 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) } get_dwords(ehci, NLPTR_GET(q->qhaddr), - (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2); - ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh); + (uint32_t *) &qh, sizeof(EHCIqh) >> 2); + ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh); + + /* + * The overlay area of the qh should never be changed by the guest, + * except when idle, in which case the reset is a nop. + */ + devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR); + endp = get_field(qh.epchar, QH_EPCHAR_EP); + if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) || + (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) || + (memcmp(&qh.current_qtd, &q->qh.current_qtd, + 9 * sizeof(uint32_t)) != 0) || + (q->dev != NULL && q->dev->addr != devaddr)) { + ehci_reset_queue(q); + p = NULL; + } + q->qh = qh; - devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR); - if (q->dev != NULL && q->dev->addr != devaddr) { - if (!QTAILQ_EMPTY(&q->packets)) { - /* should not happen (guest bug) */ - ehci_cancel_queue(q); - } - q->dev = NULL; - } if (q->dev == NULL) { q->dev = ehci_find_device(q->ehci, devaddr); } -- 1.7.1