VirtualBox

Changeset 73775 in vbox for trunk


Ignore:
Timestamp:
Aug 20, 2018 10:27:35 AM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
124458
Message:

VUSB/Linux: Fixed double reap of discarded URBs, causing potential crashes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp

    r69500 r73775  
    133133    /** This split element is reaped. */
    134134    bool                            fSplitElementReaped;
     135    /** This URB was discarded. */
     136    bool                            fDiscarded;
    135137    /** Size to transfer in remaining fragments of a split URB */
    136138    uint32_t                        cbSplitRemaining;
     
    152154     * Only the split head will appear in this list. (USBPROXYURBLNX) */
    153155    RTLISTANCHOR        ListInFlight;
    154     /** The list of landed linux URBs. Doubly linked.
    155      * Only the split head will appear in this list. (USBPROXYURBLNX) */
    156     RTLISTANCHOR        ListTaxing;
    157156    /** Are we using sysfs to find the active configuration? */
    158157    bool                fUsingSysfs;
     
    240239    RTListForEachSafe(&pDevLnx->ListInFlight, pUrbLnx, pUrbLnxNext, USBPROXYURBLNX, NodeList)
    241240    {
    242         RTListNodeRemove(&pUrbLnx->NodeList);
    243 
    244         ioctl(RTFileToNative(pDevLnx->hFile), USBDEVFS_DISCARDURB, &pUrbLnx->KUrb); /* not sure if this is required.. */
    245         if (!pUrbLnx->KUrb.status)
    246             pUrbLnx->KUrb.status = -ENODEV;
    247 
    248         /* insert into the taxing list. */
    249         if (    !pUrbLnx->pSplitHead
    250             ||  pUrbLnx == pUrbLnx->pSplitHead)
    251             RTListAppend(&pDevLnx->ListTaxing, &pUrbLnx->NodeList);
     241        if (!pUrbLnx->fDiscarded)
     242        {
     243            pUrbLnx->fDiscarded = true;
     244            /* Cancel the URB. It will be reaped normally. */
     245            ioctl(RTFileToNative(pDevLnx->hFile), USBDEVFS_DISCARDURB, &pUrbLnx->KUrb);
     246            if (!pUrbLnx->KUrb.status)
     247                pUrbLnx->KUrb.status = -ENODEV;
     248        }
    252249    }
    253250
     
    354351    pUrbLnx->fCanceledBySubmit = false;
    355352    pUrbLnx->fSplitElementReaped = false;
     353    pUrbLnx->fDiscarded = false;
    356354    LogFlowFunc(("returns pUrbLnx=%p\n", pUrbLnx));
    357355    return pUrbLnx;
     
    670668        RTListInit(&pDevLnx->ListFree);
    671669        RTListInit(&pDevLnx->ListInFlight);
    672         RTListInit(&pDevLnx->ListTaxing);
    673670        pDevLnx->pszPath = RTStrDupN(pszPath, cchPath);
    674671        if (pDevLnx->pszPath)
     
    16741671    PUSBPROXYDEVLNX pDevLnx = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX);
    16751672
    1676     /*
    1677      * Any URBs pending delivery?
    1678      */
    1679     if (!RTListIsEmpty(&pDevLnx->ListTaxing))
    1680     {
    1681         RTCritSectEnter(&pDevLnx->CritSect);
    1682         pUrbLnx = RTListGetFirst(&pDevLnx->ListTaxing, USBPROXYURBLNX, NodeList);
    1683         if (pUrbLnx)
    1684         {
    1685             /* unlink from the pending delivery list */
    1686             RTListNodeRemove(&pUrbLnx->NodeList);
    1687 
    1688             /* temporarily into the active list, so free works right. */
    1689             RTListAppend(&pDevLnx->ListInFlight, &pUrbLnx->NodeList);
    1690         }
    1691         RTCritSectLeave(&pDevLnx->CritSect);
    1692     }
    1693     if (!pUrbLnx)
    1694     {
    1695         /*
    1696          * Block for requested period.
    1697          *
    1698          * It seems to me that the path of poll() is shorter and
    1699          * involves less semaphores than ioctl() on usbfs. So, we'll
    1700          * do a poll regardless of whether cMillies == 0 or not.
    1701          */
    1702         if (cMillies)
    1703         {
    1704             int cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies;
    1705 
    1706             for (;;)
     1673     /*
     1674     * Block for requested period.
     1675     *
     1676     * It seems to me that the path of poll() is shorter and
     1677     * involves less semaphores than ioctl() on usbfs. So, we'll
     1678     * do a poll regardless of whether cMillies == 0 or not.
     1679     */
     1680    if (cMillies)
     1681    {
     1682        int cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies;
     1683
     1684        for (;;)
     1685        {
     1686            struct pollfd pfd[2];
     1687            pfd[0].fd = RTFileToNative(pDevLnx->hFile);
     1688            pfd[0].events = POLLOUT | POLLWRNORM /* completed async */
     1689                          | POLLERR | POLLHUP    /* disconnected */;
     1690            pfd[0].revents = 0;
     1691
     1692            pfd[1].fd = RTPipeToNative(pDevLnx->hPipeWakeupR);
     1693            pfd[1].events = POLLIN | POLLHUP;
     1694            pfd[1].revents = 0;
     1695
     1696            int rc = poll(&pfd[0], 2, cMilliesWait);
     1697            Log(("usbProxyLinuxUrbReap: poll rc = %d\n", rc));
     1698            if (rc >= 1)
    17071699            {
    1708                 struct pollfd pfd[2];
    1709                 pfd[0].fd = RTFileToNative(pDevLnx->hFile);
    1710                 pfd[0].events = POLLOUT | POLLWRNORM /* completed async */
    1711                               | POLLERR | POLLHUP    /* disconnected */;
    1712                 pfd[0].revents = 0;
    1713 
    1714                 pfd[1].fd = RTPipeToNative(pDevLnx->hPipeWakeupR);
    1715                 pfd[1].events = POLLIN | POLLHUP;
    1716                 pfd[1].revents = 0;
    1717 
    1718                 int rc = poll(&pfd[0], 2, cMilliesWait);
    1719                 Log(("usbProxyLinuxUrbReap: poll rc = %d\n", rc));
    1720                 if (rc >= 1)
     1700                /* If the pipe caused the return drain it. */
     1701                if (pfd[1].revents & POLLIN)
    17211702                {
    1722                     /* If the pipe caused the return drain it. */
    1723                     if (pfd[1].revents & POLLIN)
    1724                     {
    1725                         uint8_t bRead;
    1726                         size_t cbIgnored = 0;
    1727                         RTPipeRead(pDevLnx->hPipeWakeupR, &bRead, 1, &cbIgnored);
    1728                     }
     1703                    uint8_t bRead;
     1704                    size_t cbIgnored = 0;
     1705                    RTPipeRead(pDevLnx->hPipeWakeupR, &bRead, 1, &cbIgnored);
     1706                }
     1707                break;
     1708            }
     1709            if (rc >= 0)
     1710                return NULL;
     1711
     1712            if (errno != EAGAIN)
     1713            {
     1714                Log(("usb-linux: Reap URB - poll -> %d errno=%d pProxyDev=%s\n", rc, errno, usbProxyGetName(pProxyDev)));
     1715                return NULL;
     1716            }
     1717            Log(("usbProxyLinuxUrbReap: poll again - weird!!!\n"));
     1718        }
     1719    }
     1720
     1721    /*
     1722     * Reap URBs, non-blocking.
     1723     */
     1724    for (;;)
     1725    {
     1726        struct usbdevfs_urb *pKUrb;
     1727        while (ioctl(RTFileToNative(pDevLnx->hFile), USBDEVFS_REAPURBNDELAY, &pKUrb))
     1728            if (errno != EINTR)
     1729            {
     1730                if (errno == ENODEV)
     1731                    usbProxLinuxUrbUnplugged(pProxyDev);
     1732                else
     1733                    Log(("usb-linux: Reap URB. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
     1734                return NULL;
     1735            }
     1736        pUrbLnx = (PUSBPROXYURBLNX)pKUrb;
     1737
     1738        /* split list: Is the entire split list done yet? */
     1739        if (pUrbLnx->pSplitHead)
     1740        {
     1741            pUrbLnx->fSplitElementReaped = true;
     1742
     1743            /* for variable size URBs, we may need to queue more if the just-reaped URB was completely filled */
     1744            if (pUrbLnx->cbSplitRemaining && (pKUrb->actual_length == pKUrb->buffer_length) && !pUrbLnx->pSplitNext)
     1745            {
     1746                bool fUnplugged = false;
     1747                bool fSucceeded;
     1748
     1749                Assert(pUrbLnx->pSplitHead);
     1750                Assert((pKUrb->endpoint & 0x80) && !(pKUrb->flags & USBDEVFS_URB_SHORT_NOT_OK));
     1751                PUSBPROXYURBLNX pNew = usbProxyLinuxSplitURBFragment(pProxyDev, pUrbLnx->pSplitHead, pUrbLnx);
     1752                if (!pNew)
     1753                {
     1754                    Log(("usb-linux: Allocating URB fragment failed. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
     1755                    return NULL;
     1756                }
     1757                PVUSBURB pUrb = (PVUSBURB)pUrbLnx->KUrb.usercontext;
     1758                fSucceeded = usbProxyLinuxSubmitURB(pProxyDev, pNew, pUrb, &fUnplugged);
     1759                if (fUnplugged)
     1760                    usbProxLinuxUrbUnplugged(pProxyDev);
     1761                if (!fSucceeded)
     1762                    return NULL;
     1763                continue;   /* try reaping another URB */
     1764            }
     1765            PUSBPROXYURBLNX pCur;
     1766            for (pCur = pUrbLnx->pSplitHead; pCur; pCur = pCur->pSplitNext)
     1767                if (!pCur->fSplitElementReaped)
     1768                {
     1769                    pUrbLnx = NULL;
    17291770                    break;
    17301771                }
    1731                 if (rc >= 0)
    1732                     return NULL;
    1733 
    1734                 if (errno != EAGAIN)
    1735                 {
    1736                     Log(("usb-linux: Reap URB - poll -> %d errno=%d pProxyDev=%s\n", rc, errno, usbProxyGetName(pProxyDev)));
    1737                     return NULL;
    1738                 }
    1739                 Log(("usbProxyLinuxUrbReap: poll again - weird!!!\n"));
    1740             }
    1741         }
    1742 
    1743         /*
    1744          * Reap URBs, non-blocking.
    1745          */
    1746         for (;;)
    1747         {
    1748             struct usbdevfs_urb *pKUrb;
    1749             while (ioctl(RTFileToNative(pDevLnx->hFile), USBDEVFS_REAPURBNDELAY, &pKUrb))
    1750                 if (errno != EINTR)
    1751                 {
    1752                     if (errno == ENODEV)
    1753                         usbProxLinuxUrbUnplugged(pProxyDev);
    1754                     else
    1755                         Log(("usb-linux: Reap URB. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
    1756                     return NULL;
    1757                 }
    1758             pUrbLnx = (PUSBPROXYURBLNX)pKUrb;
    1759 
    1760             /* split list: Is the entire split list done yet? */
    1761             if (pUrbLnx->pSplitHead)
    1762             {
    1763                 pUrbLnx->fSplitElementReaped = true;
    1764 
    1765                 /* for variable size URBs, we may need to queue more if the just-reaped URB was completely filled */
    1766                 if (pUrbLnx->cbSplitRemaining && (pKUrb->actual_length == pKUrb->buffer_length) && !pUrbLnx->pSplitNext)
    1767                 {
    1768                     bool fUnplugged = false;
    1769                     bool fSucceeded;
    1770 
    1771                     Assert(pUrbLnx->pSplitHead);
    1772                     Assert((pKUrb->endpoint & 0x80) && !(pKUrb->flags & USBDEVFS_URB_SHORT_NOT_OK));
    1773                     PUSBPROXYURBLNX pNew = usbProxyLinuxSplitURBFragment(pProxyDev, pUrbLnx->pSplitHead, pUrbLnx);
    1774                     if (!pNew)
    1775                     {
    1776                         Log(("usb-linux: Allocating URB fragment failed. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
    1777                         return NULL;
    1778                     }
    1779                     PVUSBURB pUrb = (PVUSBURB)pUrbLnx->KUrb.usercontext;
    1780                     fSucceeded = usbProxyLinuxSubmitURB(pProxyDev, pNew, pUrb, &fUnplugged);
    1781                     if (fUnplugged)
    1782                         usbProxLinuxUrbUnplugged(pProxyDev);
    1783                     if (!fSucceeded)
    1784                         return NULL;
    1785                     continue;   /* try reaping another URB */
    1786                 }
    1787                 PUSBPROXYURBLNX pCur;
    1788                 for (pCur = pUrbLnx->pSplitHead; pCur; pCur = pCur->pSplitNext)
    1789                     if (!pCur->fSplitElementReaped)
    1790                     {
    1791                         pUrbLnx = NULL;
    1792                         break;
    1793                     }
    1794                 if (!pUrbLnx)
    1795                     continue;
    1796                 pUrbLnx = pUrbLnx->pSplitHead;
    1797             }
    1798             break;
    1799         }
     1772            if (!pUrbLnx)
     1773                continue;
     1774            pUrbLnx = pUrbLnx->pSplitHead;
     1775        }
     1776        break;
    18001777    }
    18011778
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette