summaryrefslogtreecommitdiff
path: root/hw/usb/hcd-uhci.c
diff options
context:
space:
mode:
authorGonglei <arei.gonglei@huawei.com>2016-02-19 15:33:58 +0800
committerGerd Hoffmann <kraxel@redhat.com>2016-02-23 10:38:01 +0100
commit5f77e06baa84323e5bbc96c2c7f4fe627078b210 (patch)
tree14988e1e4f582f689658be931b4bc48f4bb69b81 /hw/usb/hcd-uhci.c
parentfe3c546c5ff2a6210f9a4d8561cc64051ca8603e (diff)
downloadqemu-5f77e06baa84323e5bbc96c2c7f4fe627078b210.tar.gz
qemu-5f77e06baa84323e5bbc96c2c7f4fe627078b210.tar.bz2
qemu-5f77e06baa84323e5bbc96c2c7f4fe627078b210.zip
usb: add pid check at the first of uhci_handle_td()
pid can be gotten from uhci device memory in uhci_handle_td(), so the guest can trigger assert qemu if we get an invalid pid. And the uhci spec 2.1.2 tells us The Host Controller sets Host Controller Process Error bit to 1 when it detects a fatal error and indicates that the Host Controller suffered a consistency check failure while processing a Transfer Descriptor. An example of a consistency check failure would be finding an illegal PID field while processing the packet header portion of the TD. When this error occurs, the Host Controller clears the Run/Stop bit in the Command register to prevent further schedule execution. We'd better to set UHCI_STS_HCPERR and kick an interrupt, check the pid value at the first of uhci_handle_td function. https://bugzilla.redhat.com/show_bug.cgi?id=1070027 Signed-off-by: Gonglei <arei.gonglei@huawei.com> Message-id: 1455867238-4720-1-git-send-email-arei.gonglei@huawei.com [ applied minor codestyle fix ] Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw/usb/hcd-uhci.c')
-rw-r--r--hw/usb/hcd-uhci.c22
1 files changed, 16 insertions, 6 deletions
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 5ccfb8395a..c370240be2 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -773,8 +773,22 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
bool spd;
bool queuing = (q != NULL);
uint8_t pid = td->token & 0xff;
- UHCIAsync *async = uhci_async_find_td(s, td_addr);
+ UHCIAsync *async;
+
+ switch (pid) {
+ case USB_TOKEN_OUT:
+ case USB_TOKEN_SETUP:
+ case USB_TOKEN_IN:
+ break;
+ default:
+ /* invalid pid : frame interrupted */
+ s->status |= UHCI_STS_HCPERR;
+ s->cmd &= ~UHCI_CMD_RS;
+ uhci_update_irq(s);
+ return TD_RESULT_STOP_FRAME;
+ }
+ async = uhci_async_find_td(s, td_addr);
if (async) {
if (uhci_queue_verify(async->queue, qh_addr, td, td_addr, queuing)) {
assert(q == NULL || q == async->queue);
@@ -880,11 +894,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
break;
default:
- /* invalid pid : frame interrupted */
- uhci_async_free(async);
- s->status |= UHCI_STS_HCPERR;
- uhci_update_irq(s);
- return TD_RESULT_STOP_FRAME;
+ abort(); /* Never to execute */
}
if (async->packet.status == USB_RET_ASYNC) {