db3405
From: Prasad J Pandit <pjp@fedoraproject.org>
db3405
Date: Wed, 20 Jan 2016 01:26:46 +0530
db3405
Subject: [PATCH] usb: check page select value while processing iTD
db3405
db3405
While processing isochronous transfer descriptors(iTD), the page
db3405
select(PG) field value could lead to an OOB read access. Add
db3405
check to avoid it.
db3405
db3405
Reported-by: Qinghao Tang <luodalongde@gmail.com>
db3405
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
db3405
Message-id: 1453233406-12165-1-git-send-email-ppandit@redhat.com
db3405
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
db3405
(cherry picked from commit 49d925ce50383a286278143c05511d30ec41a36e)
db3405
---
db3405
 hw/usb/hcd-ehci.c | 10 ++++++----
db3405
 1 file changed, 6 insertions(+), 4 deletions(-)
db3405
db3405
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
db3405
index 51d39c6..2f492d9 100644
db3405
--- a/hw/usb/hcd-ehci.c
db3405
+++ b/hw/usb/hcd-ehci.c
db3405
@@ -1404,21 +1404,23 @@ static int ehci_process_itd(EHCIState *ehci,
db3405
         if (itd->transact[i] & ITD_XACT_ACTIVE) {
db3405
             pg   = get_field(itd->transact[i], ITD_XACT_PGSEL);
db3405
             off  = itd->transact[i] & ITD_XACT_OFFSET_MASK;
db3405
-            ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
db3405
-            ptr2 = (itd->bufptr[pg+1] & ITD_BUFPTR_MASK);
db3405
             len  = get_field(itd->transact[i], ITD_XACT_LENGTH);
db3405
 
db3405
             if (len > max * mult) {
db3405
                 len = max * mult;
db3405
             }
db3405
-
db3405
-            if (len > BUFF_SIZE) {
db3405
+            if (len > BUFF_SIZE || pg > 6) {
db3405
                 return -1;
db3405
             }
db3405
 
db3405
+            ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
db3405
             qemu_sglist_init(&ehci->isgl, ehci->device, 2, ehci->as);
db3405
             if (off + len > 4096) {
db3405
                 /* transfer crosses page border */
db3405
+                if (pg == 6) {
db3405
+                    return -1;  /* avoid page pg + 1 */
db3405
+                }
db3405
+                ptr2 = (itd->bufptr[pg + 1] & ITD_BUFPTR_MASK);
db3405
                 uint32_t len2 = off + len - 4096;
db3405
                 uint32_t len1 = len - len2;
db3405
                 qemu_sglist_add(&ehci->isgl, ptr1 + off, len1);