ehci: Verify a queue's ep direction does not change
ehci_fill_queue assumes that there is a one on one relationship between an ep and a qh, this patch adds a check to ensure this. Note I don't expect this to ever trigger, this is just something I noticed the guest might do while working on other stuff. The only way this check can trigger is if a guest mixes in and out qtd-s in a single qh for a non control ep. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
51e0c5d029
commit
bbbc39ccac
@ -527,6 +527,19 @@ static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd)
|
||||
}
|
||||
}
|
||||
|
||||
static bool ehci_verify_pid(EHCIQueue *q, EHCIqtd *qtd)
|
||||
{
|
||||
int ep = get_field(q->qh.epchar, QH_EPCHAR_EP);
|
||||
int pid = ehci_get_pid(qtd);
|
||||
|
||||
/* Note the pid changing is normal for ep 0 (the control ep) */
|
||||
if (q->last_pid && ep != 0 && pid != q->last_pid) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Finish executing and writeback a packet outside of the regular
|
||||
fetchqh -> fetchqtd -> execute -> writeback cycle */
|
||||
static void ehci_writeback_async_complete_packet(EHCIPacket *p)
|
||||
@ -634,6 +647,7 @@ static int ehci_reset_queue(EHCIQueue *q)
|
||||
packets = ehci_cancel_queue(q);
|
||||
q->dev = NULL;
|
||||
q->qtdaddr = 0;
|
||||
q->last_pid = 0;
|
||||
return packets;
|
||||
}
|
||||
|
||||
@ -1368,6 +1382,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
|
||||
}
|
||||
|
||||
p->pid = ehci_get_pid(&p->qtd);
|
||||
p->queue->last_pid = p->pid;
|
||||
endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
|
||||
ep = usb_ep_get(p->queue->dev, p->pid, endp);
|
||||
|
||||
@ -1883,6 +1898,10 @@ static int ehci_fill_queue(EHCIPacket *p)
|
||||
if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
|
||||
break;
|
||||
}
|
||||
if (!ehci_verify_pid(q, &qtd)) {
|
||||
ehci_trace_guest_bug(q->ehci, "guest queued token with wrong pid");
|
||||
break;
|
||||
}
|
||||
p = ehci_alloc_packet(q);
|
||||
p->qtdaddr = qtdaddr;
|
||||
p->qtd = qtd;
|
||||
|
@ -248,6 +248,7 @@ struct EHCIQueue {
|
||||
EHCIqh qh; /* copy of current QH (being worked on) */
|
||||
uint32_t qhaddr; /* address QH read from */
|
||||
uint32_t qtdaddr; /* address QTD read from */
|
||||
int last_pid; /* pid of last packet executed */
|
||||
USBDevice *dev;
|
||||
QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user