Index: /trunk/src/VBox/Main/src-client/RemoteUSBBackend.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/RemoteUSBBackend.cpp	(revision 96987)
+++ /trunk/src/VBox/Main/src-client/RemoteUSBBackend.cpp	(revision 96988)
@@ -1194,4 +1194,5 @@
     VRDEUSBREQREAPURBBODY *pBody = (VRDEUSBREQREAPURBBODY *)pvBody;
 
+    /* 'pvBody' memory buffer can contain multiple URBs. */
     while (cbBody >= sizeof(VRDEUSBREQREAPURBBODY))
     {
@@ -1212,5 +1213,4 @@
         /* Verify client's data. */
         if (   (pBody->flags & ~fu8ReapValidFlags) != 0
-            || sizeof(VRDEUSBREQREAPURBBODY) > cbBody
             || pBody->handle == 0)
         {
@@ -1229,5 +1229,5 @@
         }
 
-        uint32_t cbBodyData = 0; /* Data contained in the URB body structure for input URBs. */
+        uint32_t cbBodyData = 0; /* Data contained in the URB body structure for input URBs. i.e. beyond VRDEUSBREQREAPURBBODY. */
 
         requestDevice(pDevice);
@@ -1248,84 +1248,91 @@
         else
         {
-            LogFlow(("RemoteUSBBackend::reapURB: qurb = %p\n", qurb));
-
-            /* Update the URB error field. */
-            if (mClientVersion == VRDE_USB_VERSION_1)
+            LogFlow(("RemoteUSBBackend::reapURB: qurb = %p, u32Err = %d\n", qurb, qurb->u32Err));
+
+            /* Update the URB error field, if it does not yet indicate an error. */
+            if (qurb->u32Err == VUSBSTATUS_OK)
             {
-                switch(pBody->error)
+                if (mClientVersion == VRDE_USB_VERSION_1)
                 {
-                    case VRDE_USB_XFER_OK:    qurb->u32Err = VUSBSTATUS_OK;    break;
-                    case VRDE_USB_XFER_STALL: qurb->u32Err = VUSBSTATUS_STALL; break;
-                    case VRDE_USB_XFER_DNR:   qurb->u32Err = VUSBSTATUS_DNR;   break;
-                    case VRDE_USB_XFER_CRC:   qurb->u32Err = VUSBSTATUS_CRC;   break;
-                    default: Log(("RemoteUSBBackend::reapURB: Invalid error %d\n", pBody->error));
-                                              qurb->u32Err = VUSBSTATUS_DNR;   break;
+                    switch(pBody->error)
+                    {
+                        case VRDE_USB_XFER_OK:    qurb->u32Err = VUSBSTATUS_OK;    break;
+                        case VRDE_USB_XFER_STALL: qurb->u32Err = VUSBSTATUS_STALL; break;
+                        case VRDE_USB_XFER_DNR:   qurb->u32Err = VUSBSTATUS_DNR;   break;
+                        case VRDE_USB_XFER_CRC:   qurb->u32Err = VUSBSTATUS_CRC;   break;
+                        default: Log(("RemoteUSBBackend::reapURB: Invalid error %d\n", pBody->error));
+                                                  qurb->u32Err = VUSBSTATUS_DNR;   break;
+                    }
+                }
+                else if (   mClientVersion == VRDE_USB_VERSION_2
+                         || mClientVersion == VRDE_USB_VERSION_3)
+                {
+                    switch(pBody->error)
+                    {
+                        case VRDE_USB_XFER_OK:    qurb->u32Err = VUSBSTATUS_OK;            break;
+                        case VRDE_USB_XFER_STALL: qurb->u32Err = VUSBSTATUS_STALL;         break;
+                        case VRDE_USB_XFER_DNR:   qurb->u32Err = VUSBSTATUS_DNR;           break;
+                        case VRDE_USB_XFER_CRC:   qurb->u32Err = VUSBSTATUS_CRC;           break;
+                        case VRDE_USB_XFER_DO:    qurb->u32Err = VUSBSTATUS_DATA_OVERRUN;  break;
+                        case VRDE_USB_XFER_DU:    qurb->u32Err = VUSBSTATUS_DATA_UNDERRUN; break;
+
+                        /* Unmapped errors. */
+                        case VRDE_USB_XFER_BS:
+                        case VRDE_USB_XFER_DTM:
+                        case VRDE_USB_XFER_PCF:
+                        case VRDE_USB_XFER_UPID:
+                        case VRDE_USB_XFER_BO:
+                        case VRDE_USB_XFER_BU:
+                        case VRDE_USB_XFER_ERR:
+                        default: Log(("RemoteUSBBackend::reapURB: Invalid error %d\n", pBody->error));
+                                                  qurb->u32Err = VUSBSTATUS_DNR;   break;
+                    }
+                }
+                else
+                {
+                    qurb->u32Err = VUSBSTATUS_DNR;
                 }
             }
-            else if (   mClientVersion == VRDE_USB_VERSION_2
-                     || mClientVersion == VRDE_USB_VERSION_3)
+
+            /* Get the URB data. The URB is completed unless the client tells that this is a fragment of an IN URB. */
+            bool fURBCompleted = true;
+
+            if (qurb->fInput)
             {
-                switch(pBody->error)
+                if (pBody->len <= cbBody - sizeof(VRDEUSBREQREAPURBBODY))
+                    cbBodyData = pBody->len; /* VRDE_USB_DIRECTION_IN URBs include some data. */
+                else
                 {
-                    case VRDE_USB_XFER_OK:    qurb->u32Err = VUSBSTATUS_OK;            break;
-                    case VRDE_USB_XFER_STALL: qurb->u32Err = VUSBSTATUS_STALL;         break;
-                    case VRDE_USB_XFER_DNR:   qurb->u32Err = VUSBSTATUS_DNR;           break;
-                    case VRDE_USB_XFER_CRC:   qurb->u32Err = VUSBSTATUS_CRC;           break;
-                    case VRDE_USB_XFER_DO:    qurb->u32Err = VUSBSTATUS_DATA_OVERRUN;  break;
-                    case VRDE_USB_XFER_DU:    qurb->u32Err = VUSBSTATUS_DATA_UNDERRUN; break;
-
-                    /* Unmapped errors. */
-                    case VRDE_USB_XFER_BS:
-                    case VRDE_USB_XFER_DTM:
-                    case VRDE_USB_XFER_PCF:
-                    case VRDE_USB_XFER_UPID:
-                    case VRDE_USB_XFER_BO:
-                    case VRDE_USB_XFER_BU:
-                    case VRDE_USB_XFER_ERR:
-                    default: Log(("RemoteUSBBackend::reapURB: Invalid error %d\n", pBody->error));
-                                              qurb->u32Err = VUSBSTATUS_DNR;   break;
+                    cbBodyData = cbBody - sizeof(VRDEUSBREQREAPURBBODY);
+                    qurb->u32Err = VUSBSTATUS_DNR;
+                }
+
+                if (qurb->u32Err == VUSBSTATUS_OK)
+                {
+                    LogFlow(("RemoteUSBBackend::reapURB: copying data %d bytes\n", pBody->len));
+                    if (pBody->len > qurb->u32Len - qurb->u32TransferredLen)
+                    {
+                        /* Received more data than expected for this URB. If there more fragments follow,
+                         * they will be discarded because the URB handle will not be valid anymore.
+                         */
+                        qurb->u32Err = VUSBSTATUS_DNR;
+                        qurb->u32TransferredLen = qurb->u32Len;
+                    }
+                    else
+                    {
+                        memcpy ((uint8_t *)qurb->pvData + qurb->u32TransferredLen, &pBody[1], pBody->len);
+                        qurb->u32TransferredLen += pBody->len;
+                    }
+
+                    if (   qurb->u32Err == VUSBSTATUS_OK
+                        && (pBody->flags & VRDE_USB_REAP_FLAG_FRAGMENT) != 0)
+                    {
+                        /* If the client sends fragmented packets, accumulate the URB data. */
+                        fURBCompleted = false;
+                    }
                 }
             }
             else
-            {
-                qurb->u32Err = VUSBSTATUS_DNR;
-            }
-
-            /* Get the URB data. */
-            bool fURBCompleted = true;
-
-            if (qurb->fInput)
-            {
-                cbBodyData = pBody->len; /* VRDE_USB_DIRECTION_IN URBs include some data. */
-            }
-
-            if (   qurb->u32Err == VUSBSTATUS_OK
-                && qurb->fInput)
-            {
-                LogFlow(("RemoteUSBBackend::reapURB: copying data %d bytes\n", pBody->len));
-
-                uint32_t u32DataLen = qurb->u32TransferredLen + pBody->len;
-
-                if (u32DataLen > qurb->u32Len)
-                {
-                    /* Received more data than expected for this URB. If there more fragments follow,
-                     * they will be discarded because the URB handle will not be valid anymore.
-                     */
-                    qurb->u32Err = VUSBSTATUS_DNR;
-                }
-                else
-                {
-                    memcpy ((uint8_t *)qurb->pvData + qurb->u32TransferredLen, &pBody[1], pBody->len);
-                }
-
-                if (   qurb->u32Err == VUSBSTATUS_OK
-                    && (pBody->flags & VRDE_USB_REAP_FLAG_FRAGMENT) != 0)
-                {
-                    /* If the client sends fragmented packets, accumulate the URB data. */
-                    fURBCompleted = false;
-                }
-            }
-
-            qurb->u32TransferredLen += pBody->len; /* Update the value for all URBs. */
+                qurb->u32TransferredLen += pBody->len; /* Update the value for OUT URBs. */
 
             if (fURBCompleted)
@@ -1391,7 +1398,5 @@
 
         /* There is probably a further URB body. */
-        uint32_t cbBodySize = sizeof (VRDEUSBREQREAPURBBODY) + cbBodyData;
-
-        if (cbBodySize > cbBody)
+        if (cbBodyData > cbBody - sizeof(VRDEUSBREQREAPURBBODY))
         {
             vrc = VERR_INVALID_PARAMETER;
@@ -1399,6 +1404,6 @@
         }
 
-        pBody = (VRDEUSBREQREAPURBBODY *)((uint8_t *)pBody + cbBodySize);
-        cbBody -= cbBodySize;
+        cbBody -= sizeof(VRDEUSBREQREAPURBBODY) + cbBodyData;
+        pBody = (VRDEUSBREQREAPURBBODY *)((uint8_t *)pBody + sizeof(VRDEUSBREQREAPURBBODY) + cbBodyData);
     }
 
