VirtualBox

Changeset 83566 in vbox for trunk/src/VBox/Devices/Storage


Ignore:
Timestamp:
Apr 5, 2020 4:23:16 PM (5 years ago)
Author:
vboxsync
Message:

DevVirtioSCSI.cpp: Defined and enforced limits on virtioScsiConfig.uCdbSize and uSenseSize. Use stack buffer for the request in virtioScsiR3ReqSubmit, as it cannot be more than 274 bytes big now. bugref:9440

File:
1 edited

Legend:

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

    r83565 r83566  
    3333#include <VBox/vmm/pdmstorageifs.h>
    3434#include <VBox/vmm/pdmcritsect.h>
     35#include <VBox/AssertGuest.h>
    3536#include <VBox/msi.h>
    3637#include <VBox/version.h>
     
    9697
    9798#define VIRTIOSCSI_SENSE_SIZE_DEFAULT               96          /**< VirtIO 1.0: 96 on reset, guest can change       */
     99#define VIRTIOSCSI_SENSE_SIZE_MAX                   4096        /**< Picked out of thin air by bird.                 */
    98100#define VIRTIOSCSI_CDB_SIZE_DEFAULT                 32          /**< VirtIO 1.0: 32 on reset, guest can change       */
     101#define VIRTIOSCSI_CDB_SIZE_MAX                     255         /**< Picked out of thin air by bird.                 */
    99102#define VIRTIOSCSI_PI_BYTES_IN                      1           /**< Value TBD (see section 5.6.6.1)                 */
    100103#define VIRTIOSCSI_PI_BYTES_OUT                     1           /**< Value TBD (see section 5.6.6.1)                 */
     
    646649{
    647650    if (uCmd < 0x1f)
    648         return 6;
     651        return RT_MIN(6, cbMax);
    649652    if (uCmd >= 0x20 && uCmd < 0x60)
    650         return 10;
     653        return RT_MIN(10, cbMax);
    651654    if (uCmd >= 0x60 && uCmd < 0x80)
    652655        return cbMax;
    653656    if (uCmd >= 0x80 && uCmd < 0xa0)
    654         return 16;
     657        return RT_MIN(16, cbMax);
    655658    if (uCmd >= 0xa0 && uCmd < 0xc0)
    656         return 12;
     659        return RT_MIN(12, cbMax);
    657660    return cbMax;
    658661}
     
    11071110
    11081111    /*
     1112     * Validate configuration values we use here before we start.
     1113     */
     1114    /** @todo Report these as errors to the guest or does the caller do that? */
     1115    uint32_t const cbCdb   = pThis->virtioScsiConfig.uCdbSize;
     1116    ASSERT_GUEST_LOGREL_MSG_RETURN(cbCdb <= VIRTIOSCSI_CDB_SIZE_MAX, ("cbCdb=%#x\n", cbCdb), VERR_OUT_OF_RANGE);
     1117    uint32_t const cbSense = pThis->virtioScsiConfig.uSenseSize;
     1118    ASSERT_GUEST_LOGREL_MSG_RETURN(cbSense <= VIRTIOSCSI_SENSE_SIZE_MAX, ("cbSense=%#x\n", cbSense), VERR_OUT_OF_RANGE);
     1119
     1120    /*
    11091121     * Extract command header and CDB from guest physical memory
     1122     * The max size is rather small here (19 + 255 = 274), so put
     1123     * it on the stack.
    11101124     */
    1111     size_t cbReqHdr = sizeof(REQ_CMD_HDR_T) + pThis->virtioScsiConfig.uCdbSize;
    1112 
     1125    size_t const cbReqHdr = sizeof(REQ_CMD_HDR_T) + cbCdb;
    11131126    AssertReturn(pDescChain->cbPhysSend >= cbReqHdr, VERR_INVALID_PARAMETER);
    11141127
    1115     PVIRTIOSCSI_REQ_CMD_T pVirtqReq = (PVIRTIOSCSI_REQ_CMD_T)RTMemAllocZ(cbReqHdr);
    1116     AssertReturn(pVirtqReq, VERR_NO_MEMORY);
    1117     uint8_t *pb = (uint8_t *)pVirtqReq;
    1118     for (size_t cb = RT_MIN(pDescChain->cbPhysSend, cbReqHdr); cb; )
    1119     {
    1120         size_t cbSeg = cb;
     1128    AssertCompile(VIRTIOSCSI_CDB_SIZE_MAX < 4096);
     1129    union
     1130    {
     1131        /*VIRTIOSCSI_REQ_CMD_T    ReqCmd; - not needed */
     1132        struct
     1133        {
     1134            REQ_CMD_HDR_T       ReqHdr;
     1135            uint8_t             abCdb[VIRTIOSCSI_CDB_SIZE_MAX];
     1136        };
     1137        uint8_t                 ab[sizeof(REQ_CMD_HDR_T) + VIRTIOSCSI_CDB_SIZE_MAX];
     1138        uint64_t                au64Align[(sizeof(REQ_CMD_HDR_T) + VIRTIOSCSI_CDB_SIZE_MAX) / sizeof(uint64_t)];
     1139    } VirtqReq;
     1140    RT_ZERO(VirtqReq);
     1141
     1142    for (size_t offReq = 0; offReq < cbReqHdr; )
     1143    {
     1144        size_t cbSeg = cbReqHdr - offReq;
    11211145        RTGCPHYS GCPhys = virtioCoreSgBufGetNextSegment(pDescChain->pSgPhysSend, &cbSeg);
    1122         PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pb, cbSeg);
    1123         pb += cbSeg;
    1124         cb -= cbSeg;
    1125     }
    1126 
    1127     uint8_t uType = pVirtqReq->ReqHdr.abVirtioLun[0];
    1128     uint8_t  uTarget  = pVirtqReq->ReqHdr.abVirtioLun[1];
    1129     uint32_t uScsiLun = (pVirtqReq->ReqHdr.abVirtioLun[2] << 8 | pVirtqReq->ReqHdr.abVirtioLun[3]) & 0x3fff;
     1146        PDMDevHlpPCIPhysRead(pDevIns, GCPhys, &VirtqReq.ab[offReq], cbSeg);
     1147        offReq += cbSeg;
     1148    }
     1149
     1150    uint8_t  const uType    = VirtqReq.ReqHdr.abVirtioLun[0];
     1151    uint8_t  const uTarget  = VirtqReq.ReqHdr.abVirtioLun[1];
     1152    uint32_t       uScsiLun = RT_MAKE_U16(VirtqReq.ReqHdr.abVirtioLun[3], VirtqReq.ReqHdr.abVirtioLun[2]) & 0x3fff;
    11301153
    11311154    bool fBadLUNFormat = false;
     
    11451168
    11461169    LogFunc(("[%s] (Target: %d LUN: %d)  CDB: %.*Rhxs\n",
    1147              SCSICmdText(pVirtqReq->uCdb[0]), uTarget, uScsiLun,
    1148              virtioScsiEstimateCdbLen(pVirtqReq->uCdb[0], pThis->virtioScsiConfig.uCdbSize), pVirtqReq->uCdb));
     1170             SCSICmdText(VirtqReq.abCdb[0]), uTarget, uScsiLun,
     1171             virtioScsiEstimateCdbLen(VirtqReq.abCdb[0], cbCdb), &VirtqReq.abCdb[0]));
    11491172
    11501173    Log3Func(("cmd id: %RX64, attr: %x, prio: %d, crn: %x\n",
    1151               pVirtqReq->ReqHdr.uId, pVirtqReq->ReqHdr.uTaskAttr, pVirtqReq->ReqHdr.uPrio, pVirtqReq->ReqHdr.uCrn));
     1174              VirtqReq.ReqHdr.uId, VirtqReq.ReqHdr.uTaskAttr, VirtqReq.ReqHdr.uPrio, VirtqReq.ReqHdr.uCrn));
    11521175
    11531176    /*
    1154      * Calculate request offsets
     1177     * Calculate request offsets and data sizes.
    11551178     */
    1156     off_t uDataOutOff = sizeof(REQ_CMD_HDR_T)  + pThis->virtioScsiConfig.uCdbSize;
    1157     off_t uDataInOff  = sizeof(REQ_RESP_HDR_T) + pThis->virtioScsiConfig.uSenseSize;
    1158     uint32_t cbDataOut = pDescChain->cbPhysSend - uDataOutOff;
    1159     uint32_t cbDataIn  = pDescChain->cbPhysReturn - uDataInOff;
     1179    uint32_t const offDataOut = sizeof(REQ_CMD_HDR_T)  + cbCdb;
     1180    uint32_t const offDataIn  = sizeof(REQ_RESP_HDR_T) + cbSense;
     1181    uint32_t const cbDataOut  = pDescChain->cbPhysSend - offDataOut;
     1182    /** @todo r=bird: Validate cbPhysReturn properly? I've just RT_MAX'ed it for now. */
     1183    uint32_t const cbDataIn   = RT_MAX(pDescChain->cbPhysReturn, offDataIn) - offDataIn;
     1184    Assert(offDataOut <= UINT16_MAX);
     1185    Assert(offDataIn  <= UINT16_MAX);
    11601186
    11611187    /*
     
    11731199        respHdr.uResidual  = cbDataIn + cbDataOut;
    11741200        virtioScsiR3ReqErr(pDevIns, pThis, pThisCC, qIdx, pDescChain, &respHdr , NULL);
    1175         RTMemFreeZ(pVirtqReq, cbReqHdr);
    11761201        return VINF_SUCCESS;
    11771202    }
     
    11931218        respHdr.uResidual  = cbDataOut + cbDataIn;
    11941219        virtioScsiR3ReqErr(pDevIns, pThis, pThisCC, qIdx, pDescChain, &respHdr, abSense);
    1195         RTMemFreeZ(pVirtqReq, cbReqHdr);
    11961220        return VINF_SUCCESS;
    11971221
     
    12111235        respHdr.uResidual  = cbDataOut + cbDataIn;
    12121236        virtioScsiR3ReqErr(pDevIns, pThis, pThisCC, qIdx, pDescChain, &respHdr, abSense);
    1213         RTMemFreeZ(pVirtqReq, cbReqHdr);
    12141237        return VINF_SUCCESS;
    12151238    }
     
    12251248        respHdr.uResidual  = cbDataIn + cbDataOut;
    12261249        virtioScsiR3ReqErr(pDevIns, pThis, pThisCC, qIdx, pDescChain, &respHdr, NULL);
    1227         RTMemFreeZ(pVirtqReq, cbReqHdr);
    12281250        return VINF_SUCCESS;
    12291251    }
     
    12441266        respHdr.uResidual  = cbDataIn + cbDataOut;
    12451267        virtioScsiR3ReqErr(pDevIns, pThis, pThisCC, qIdx, pDescChain, &respHdr , abSense);
    1246         RTMemFreeZ(pVirtqReq, cbReqHdr);
    12471268        return VINF_SUCCESS;
    12481269    }
     
    12581279                                      PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR);
    12591280
    1260     if (RT_FAILURE(rc))
    1261     {
    1262         RTMemFreeZ(pVirtqReq, cbReqHdr);
    1263         AssertMsgRCReturn(rc, ("Failed to allocate I/O request, rc=%Rrc\n", rc), rc);
    1264     }
     1281    AssertMsgRCReturn(rc, ("Failed to allocate I/O request, rc=%Rrc\n", rc), rc);
    12651282
    12661283    pReq->hIoReq      = hIoReq;
     
    12701287    pReq->cbDataOut   = cbDataOut;
    12711288    pReq->pDescChain  = pDescChain;
    1272     pReq->uDataInOff  = uDataInOff;
    1273     pReq->uDataOutOff = uDataOutOff;
    1274 
    1275     pReq->cbSenseAlloc = pThis->virtioScsiConfig.uSenseSize;
     1289    pReq->uDataInOff  = offDataIn;
     1290    pReq->uDataOutOff = offDataOut;
     1291
     1292    pReq->cbSenseAlloc = cbSense;
    12761293    pReq->pbSense      = (uint8_t *)RTMemAllocZ(pReq->cbSenseAlloc);
    12771294    AssertMsgReturnStmt(pReq->pbSense, ("Out of memory allocating sense buffer"),
    1278                         virtioScsiR3FreeReq(pTarget, pReq); RTMemFreeZ(pVirtqReq, cbReqHdr);, VERR_NO_MEMORY);
     1295                        virtioScsiR3FreeReq(pTarget, pReq);, VERR_NO_MEMORY);
    12791296
    12801297    /* Note: DrvSCSI allocates one virtual memory buffer for input and output phases of the request */
    12811298    rc = pIMediaEx->pfnIoReqSendScsiCmd(pIMediaEx, pReq->hIoReq, uScsiLun,
    1282                                         pVirtqReq->uCdb, (size_t)pThis->virtioScsiConfig.uCdbSize,
     1299                                        &VirtqReq.abCdb[0], cbCdb,
    12831300                                        PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN, &pReq->enmTxDir,
    12841301                                        RT_MAX(cbDataIn, cbDataOut),
     
    13161333    }
    13171334
    1318     RTMemFreeZ(pVirtqReq, cbReqHdr);
    13191335    return VINF_SUCCESS;
    13201336}
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