VirtualBox

Changeset 56658 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Jun 26, 2015 12:51:57 PM (10 years ago)
Author:
vboxsync
Message:

Storage/AHCI: Fix possible use after free after an I/O error occurred. The first I/O request with an I/O error is saved for the error log page but is also put on the per port free requerst list. When the guest reads the error page the request is freed but is still on the free request list and could be used later

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DevAHCI.cpp

    r56641 r56658  
    57165716    for (unsigned i = 0; i < RT_ELEMENTS(pAhciPort->aActiveTasks); i++)
    57175717    {
    5718         PAHCIREQ pAhciReq = (PAHCIREQ)ASMAtomicXchgPtr((void * volatile *)&pAhciPort->aActiveTasks[i], NULL);
    5719 
    5720         if (   VALID_PTR(pAhciReq)
    5721             && pAhciReq != pAhciReqExcept)
    5722         {
    5723             bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_CANCELED, AHCITXSTATE_ACTIVE);
    5724             if (fXchg)
     5718        PAHCIREQ pAhciReq = ASMAtomicReadPtrT(&pAhciPort->aActiveTasks[i], PAHCIREQ);
     5719        if (pAhciReq != pAhciReqExcept)
     5720        {
     5721            pAhciReq = (PAHCIREQ)ASMAtomicXchgPtr((void * volatile *)&pAhciPort->aActiveTasks[i], NULL);
     5722
     5723            if (VALID_PTR(pAhciReq))
    57255724            {
    5726                 /* Task is active and was canceled. */
    5727                 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0,
    5728                                  ("Task was canceled but none is active\n"));
    5729                 ASMAtomicDecU32(&pAhciPort->cTasksActive);
    5730 
    5731                 /*
    5732                  * Clear the pointer in the cached array. The controller will allocate a
    5733                  * a new task structure for this tag.
    5734                  */
    5735                 ASMAtomicWriteNullPtr(&pAhciPort->aActiveTasks[i]);
    5736                 LogRel(("AHCI#%uP%u: Cancelled task %u\n", pAhciPort->CTX_SUFF(pDevIns)->iInstance,
    5737                         pAhciPort->iLUN, pAhciReq->uTag));
     5725                bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_CANCELED, AHCITXSTATE_ACTIVE);
     5726                if (fXchg)
     5727                {
     5728                    /* Task is active and was canceled. */
     5729                    AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0,
     5730                                     ("Task was canceled but none is active\n"));
     5731                    ASMAtomicDecU32(&pAhciPort->cTasksActive);
     5732
     5733                    /*
     5734                     * Clear the pointer in the cached array. The controller will allocate a
     5735                     * a new task structure for this tag.
     5736                     */
     5737                    ASMAtomicWriteNullPtr(&pAhciPort->aActiveTasks[i]);
     5738                    LogRel(("AHCI#%uP%u: Cancelled task %u\n", pAhciPort->CTX_SUFF(pDevIns)->iInstance,
     5739                            pAhciPort->iLUN, pAhciReq->uTag));
     5740                }
     5741                else
     5742                    AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_FREE,
     5743                              ("Invalid task state, must be free!\n"));
    57385744            }
    5739             else
    5740                 AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_FREE,
    5741                           ("Invalid task state, must be free!\n"));
    57425745        }
    57435746    }
     
    59605963    pAhciReq = RTListGetFirst(pAhciPort->pListReqsFree, AHCIREQ, NodeList);
    59615964    if (pAhciReq)
     5965    {
     5966        AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_FREE, ("Should be free!\n"));
    59625967        RTListNodeRemove(&pAhciReq->NodeList);
     5968    }
    59635969    RTCritSectLeave(&pAhciPort->CritSectReqsFree);
    59645970
     
    59785984static void ahciR3ReqFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
    59795985{
     5986    AssertMsg(pAhciReq->enmTxState != AHCITXSTATE_FREE, ("Double free!\n"));
    59805987    pAhciReq->enmTxState = AHCITXSTATE_FREE;
    59815988
     
    60176024    bool fPortReset = ASMAtomicReadBool(&pAhciPort->fPortReset);
    60186025    bool fXchg = ASMAtomicCmpXchgPtr(&pAhciPort->aActiveTasks[pAhciReq->uTag], NULL, pAhciReq);
     6026    bool fReqErrSaved = false;
    60196027
    60206028    /*
     
    60956103                pAhciReq->uATARegError    = ID_ERR;
    60966104                pAhciReq->uATARegStatus   = ATA_STAT_READY | ATA_STAT_ERR;
    6097                 ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciReq, NULL);
     6105                fReqErrSaved = ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciReq, NULL);
    60986106            }
    60996107            else
     
    62076215        PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
    62086216
    6209     if (pAhciReq && !(pAhciReq->fFlags & AHCI_REQ_IS_ON_STACK))
     6217    /* Don't free the request yet when it is saved for the error log page. */
     6218    if (   pAhciReq
     6219        && !(pAhciReq->fFlags & AHCI_REQ_IS_ON_STACK)
     6220        && !fReqErrSaved)
    62106221        ahciR3ReqFree(pAhciPort, pAhciReq);
    62116222    return fCanceled;
     
    64716482                                ahciTrimRangesDestroy(pTaskErr);
    64726483                            else if (pTaskErr->enmTxDir != AHCITXDIR_FLUSH)
    6473                                 ahciIoBufFree(pAhciPort, pTaskErr, false /* fCopyToGuest */);
     6484                                ahciReqMemFree(pAhciPort, pTaskErr, true /* fForceFree */);
    64746485
    64756486                            /* Finally free the error task state structure because it is completely unused now. */
Note: See TracChangeset for help on using the changeset viewer.

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