VirtualBox

Changeset 90580 in vbox


Ignore:
Timestamp:
Aug 9, 2021 3:53:16 PM (3 years ago)
Author:
vboxsync
Message:

Devices/Security: Continue work on the TPM device emulation and driver interfacing with swtpm, EFI firmware detects the TPM and starts talking to it, bugref:10075

Location:
trunk/src/VBox/Devices/Security
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Security/DevTpm.cpp

    r90512 r90580  
    875875        && uReg < TPM_CRB_LOCALITY_REG_DATA_BUFFER + TPM_CRB_LOCALITY_REG_DATA_BUFFER_SIZE
    876876        && bLoc == pThis->bLoc
    877         && pThis->enmState == DEVTPMSTATE_CMD_RECEPTION)
     877        && (   pThis->enmState == DEVTPMSTATE_READY
     878            || pThis->enmState == DEVTPMSTATE_CMD_RECEPTION))
    878879    {
     880        pThis->enmState = DEVTPMSTATE_CMD_RECEPTION;
    879881        memcpy(&pThis->abCmdResp[uReg - TPM_CRB_LOCALITY_REG_DATA_BUFFER], &u64, cb);
    880882        return VINF_SUCCESS;
     
    886888        {
    887889            /* See chapter 6.5.3.2.2.1. */
     890#if 0
    888891            if (u64 & TPM_CRB_LOCALITY_REG_CTRL_RST_ESTABLISHMENT)
    889892                /** @todo */;
     893#endif
    890894
    891895            /*
     
    10831087    /** @todo */
    10841088    RT_NOREF(pThis, pThisCC);
     1089    pThis->enmState = DEVTPMSTATE_CMD_COMPLETION;
    10851090}
    10861091
  • trunk/src/VBox/Devices/Security/DrvTpmEmu.cpp

    r90530 r90580  
    115115
    116116
     117/** @name Capabilities as returned by SWTPMCMD_INIT.
     118 * @{ */
     119#define SWTPMCMD_INIT_F_DELETE_VOLATILE RT_BIT_32(0);
     120/** @} */
     121
     122
    117123/**
    118124 * Response data for a SWTPMCMD_GET_CAPABILITY command.
     
    151157
    152158/**
     159 * Additional command data for SWTPMCMD_SET_LOCALITY.
     160 */
     161typedef struct SWTPMCMDSETLOCALITY
     162{
     163    /** The locality to set */
     164    uint8_t                     bLoc;
     165} SWTPMCMDSETLOCALITY;
     166/** Pointer to a command data struct for SWTPMCMD_SET_LOCALITY. */
     167typedef SWTPMCMDSETLOCALITY *PSWTPMCMDSETLOCALITY;
     168/** Pointer to a const command data struct for SWTPMCMD_SET_LOCALITY. */
     169typedef const SWTPMCMDSETLOCALITY *PCSWTPMCMDSETLOCALITY;
     170
     171
     172/**
    153173 * Additional command data for SWTPMCMD_GET_CONFIG.
    154174 */
     
    186206    /** Size of the chunk returned in this response. */
    187207    uint32_t                    cbThis;
    188     /** The data returned. */
    189     uint8_t                     abData[3 * _1K];
    190208} SWTPMRESPGETCONFIG;
    191209/** Pointer to a response data struct for SWTPMCMD_GET_CONFIG. */
     
    193211/** Pointer to a const response data struct for SWTPMCMD_GET_CONFIG. */
    194212typedef const SWTPMRESPGETCONFIG *PCSWTPMRESPGETCONFIG;
    195 /** @} */
     213
     214
     215/**
     216 * Response data for a SWTPMCMD_GET_TPMESTABLISHED command.
     217 */
     218typedef struct SWTPMRESPGETTPMEST
     219{
     220    /** Flag whether the TPM established bit is set for the TPM. */
     221    uint8_t                     fEst;
     222} SWTPMRESPGETTPMEST;
     223/** Pointer to a response data struct for SWTPMCMD_GET_TPMESTABLISHED. */
     224typedef SWTPMRESPGETTPMEST *PSWTPMRESPGETTPMEST;
     225/** Pointer to a const response data struct for SWTPMCMD_GET_TPMESTABLISHED. */
     226typedef const SWTPMRESPGETTPMEST *PCSWTPMRESPGETTPMEST;
     227
     228
     229/**
     230 * Additional command data for SWTPMCMD_RESET_TPMESTABLISHED.
     231 */
     232typedef struct SWTPMCMDRSTEST
     233{
     234    /** The locality resetting trying to reset the established bit. */
     235    uint8_t                    bLoc;
     236} SWTPMCMDRSTEST;
     237/** Pointer to a response data struct for SWTPMCMD_GET_TPMESTABLISHED. */
     238typedef SWTPMCMDRSTEST *PSWTPMCMDRSTEST;
     239/** Pointer to a const response data struct for SWTPMCMD_GET_TPMESTABLISHED. */
     240typedef const SWTPMCMDRSTEST *PCSWTPMCMDRSTEST;
    196241
    197242
     
    224269    /** Flag to signal whether the thread was woken up from external. */
    225270    bool volatile       fWokenUp;
     271    /** Currently set locality. */
     272    uint8_t             bLoc;
    226273
    227274    /** TPM version offered by the emulator. */
    228275    TPMVERSION          enmTpmVers;
     276    /** Capabilities offered by the TPM emulator. */
     277    uint32_t            fCaps;
    229278} DRVTPMEMU;
    230279/** Pointer to the TPM emulator instance data. */
    231280typedef DRVTPMEMU *PDRVTPMEMU;
     281
     282/** The special no current locality selected value. */
     283#define TPM_NO_LOCALITY_SELECTED    0xff
    232284
    233285
     
    282334                *pu32Resp = RT_BE2H_U32(u32Resp);
    283335                if (*pu32Resp == 0)
    284                     rc = RTSocketRead(pThis->hSockCtrl, pvResp, cbResp, NULL /*pcbRead*/);
     336                {
     337                    if (cbResp)
     338                        rc = RTSocketRead(pThis->hSockCtrl, pvResp, cbResp, NULL /*pcbRead*/);
     339                }
     340                else
     341                    rc = VERR_NET_IO_ERROR;
    285342            }
    286343        }
    287344    }
     345
     346    return rc;
     347}
     348
     349
     350/**
     351 * Continue receiving a response from a previous call of drvTpmEmuExecCtrlCmdEx() or
     352 * drvTpmEmuExecCtrlCmdNoPayload().
     353 *
     354 * @param   pThis               Pointer to the TPM emulator driver instance data.
     355 * @param   enmCmd              The command to execute.
     356 * @param   pvResp              Where to store additional resposne data.
     357 * @param   cbResp              Size of the additional response data in bytes.
     358 * @param   cMillies            Number of milliseconds to wait before aborting the receive with a timeout error.
     359 */
     360static int drvTpmEmuExecCtrlCmdRespCont(PDRVTPMEMU pThis, void *pvResp, size_t cbResp, RTMSINTERVAL cMillies)
     361{
     362    int rc = RTSocketSelectOne(pThis->hSockCtrl, cMillies);
     363    if (RT_SUCCESS(rc))
     364        rc = RTSocketRead(pThis->hSockCtrl, pvResp, cbResp, NULL /*pcbRead*/);
    288365
    289366    return rc;
     
    318395
    319396/**
     397 * Executes the given command over the control connection to the TPM emulator - variant with no response payload other than the result.
     398 *
     399 * @returns VBox status code.
     400 * @retval  VERR_NET_IO_ERROR if the executed command returned an error in the response status field.
     401 * @param   pThis               Pointer to the TPM emulator driver instance data.
     402 * @param   enmCmd              The command to execute.
     403 * @param   pvCmd               Additional command data to send.
     404 * @param   cbCmd               Size of the additional command data in bytes.
     405 * @param   pu32Resp            Where to store the response code from the reply.
     406 * @param   cMillies            Number of milliseconds to wait before aborting the command with a timeout error.
     407 */
     408static int drvTpmEmuExecCtrlCmdNoResp(PDRVTPMEMU pThis, SWTPMCMD enmCmd, const void *pvCmd, size_t cbCmd, uint32_t *pu32Resp,
     409                                      RTMSINTERVAL cMillies)
     410{
     411    return drvTpmEmuExecCtrlCmdEx(pThis, enmCmd, pvCmd, cbCmd, pu32Resp,
     412                                  NULL /*pvResp*/, 0 /*cbResp*/, cMillies);
     413}
     414
     415
     416/**
    320417 * Queries the version of the TPM offered by the remote emulator.
    321418 *
     
    327424    SWTPMCMDGETCONFIG Cmd;
    328425    SWTPMRESPGETCONFIG Resp;
     426    uint8_t abData[_4K];
    329427    uint32_t u32Resp = 0;
    330428
     
    332430    Cmd.u64Flags = RT_H2BE_U64(SWTPM_GET_CONFIG_F_TPM_SPECIFICATION);
    333431    Cmd.u32Offset = 0;
    334     int rc = drvTpmEmuExecCtrlCmdEx(pThis, SWTPMCMD_GET_CONFIG, &Cmd, sizeof(Cmd), &u32Resp,
     432    int rc = drvTpmEmuExecCtrlCmdEx(pThis, SWTPMCMD_GET_INFO, &Cmd, sizeof(Cmd), &u32Resp,
    335433                                    &Resp, sizeof(Resp), RT_MS_10SEC);
    336434    if (RT_SUCCESS(rc))
    337435    {
     436        /*
     437         * Currently it is not necessary to get the information in chunks, a single
     438         * transaction is enough. To fend off future versions of swtpm requiring this
     439         * we return an error here if the total length is not equal to the length of the chunk.
     440         */
    338441        if (RT_BE2H_U32(Resp.cbTotal) == RT_BE2H_U32(Resp.cbThis))
    339442        {
    340             RTJSONVAL hJsonVal = NIL_RTJSONVAL;
    341             rc = RTJsonParseFromBuf(&hJsonVal, &Resp.abData[0], sizeof(Resp.abData), NULL /*pErrInfo*/);
     443            /* Fetch the response body. */
     444            rc = drvTpmEmuExecCtrlCmdRespCont(pThis, &abData[0], RT_BE2H_U32(Resp.cbThis), RT_MS_10SEC);
    342445            if (RT_SUCCESS(rc))
    343446            {
    344                 /** @todo */
    345                 RTJsonValueRelease(hJsonVal);
     447                RTJSONVAL hJsonVal = NIL_RTJSONVAL;
     448                rc = RTJsonParseFromBuf(&hJsonVal, &abData[0], RT_BE2H_U32(Resp.cbThis), NULL /*pErrInfo*/);
     449                if (RT_SUCCESS(rc))
     450                {
     451                    RTJSONVAL hJsonTpmSpec = NIL_RTJSONVAL;
     452                    rc = RTJsonValueQueryByName(hJsonVal, "TPMSpecification", &hJsonTpmSpec);
     453                    if (RT_SUCCESS(rc))
     454                    {
     455                        RTJSONVAL hJsonTpmFam = NIL_RTJSONVAL;
     456                        rc = RTJsonValueQueryByName(hJsonTpmSpec, "family", &hJsonTpmFam);
     457                        if (RT_SUCCESS(rc))
     458                        {
     459                            const char *pszFam = NULL;
     460                            rc = RTJsonValueQueryString(hJsonTpmFam, &pszFam);
     461                            if (RT_SUCCESS(rc))
     462                            {
     463                                if (!RTStrCmp(pszFam, "1.2"))
     464                                    pThis->enmTpmVers = TPMVERSION_1_2;
     465                                else if (!RTStrCmp(pszFam, "2.0"))
     466                                    pThis->enmTpmVers = TPMVERSION_2_0;
     467                                else
     468                                    pThis->enmTpmVers = TPMVERSION_UNKNOWN;
     469                            }
     470
     471                            RTJsonValueRelease(hJsonTpmFam);
     472                        }
     473
     474                        RTJsonValueRelease(hJsonTpmSpec);
     475                    }
     476
     477                    RTJsonValueRelease(hJsonVal);
     478                }
    346479            }
    347480        }
     
    361494 * @param   pThis               Pointer to the TPM emulator driver instance data.
    362495 */
    363 static int drvTpmEmuQueryAndValidateCaps(PDRVTPMEMU pThis)
     496static int drvTpmEmuQueryCaps(PDRVTPMEMU pThis)
    364497{
    365498    SWTPMRESPGETCAPABILITY Resp;
    366499    int rc = drvTpmEmuExecCtrlCmdNoPayload(pThis, SWTPMCMD_GET_CAPABILITY, &Resp, sizeof(Resp), RT_MS_10SEC);
    367500    if (RT_SUCCESS(rc))
    368     {
    369         /** @todo */
    370     }
     501        pThis->fCaps = RT_BE2H_U32(Resp.u32Caps);
     502
     503    return rc;
     504}
     505
     506
     507/**
     508 * Sets the given locality for the emulated TPM.
     509 *
     510 * @returns VBox status code.
     511 * @param   pThis               Pointer to the TPM emulator driver instance data.
     512 * @param   bLoc                The locality to set.
     513 */
     514static int drvTpmEmuSetLocality(PDRVTPMEMU pThis, uint8_t bLoc)
     515{
     516    SWTPMCMDSETLOCALITY Cmd;
     517    uint32_t u32Resp = 0;
     518
     519    Cmd.bLoc = bLoc;
     520    int rc = drvTpmEmuExecCtrlCmdNoResp(pThis, SWTPMCMD_SET_LOCALITY, &Cmd, sizeof(Cmd), &u32Resp, RT_MS_10SEC);
     521    if (   RT_SUCCESS(rc)
     522        && u32Resp != 0)
     523        rc = VERR_NET_IO_ERROR;
    371524
    372525    return rc;
     
    377530static DECLCALLBACK(int) drvTpmEmuStartup(PPDMITPMCONNECTOR pInterface, size_t cbCmdResp)
    378531{
    379     RT_NOREF(pInterface, cbCmdResp);
    380     return VERR_NOT_IMPLEMENTED;
     532    RT_NOREF(cbCmdResp);
     533    PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
     534
     535    SWTPMCMDTPMINIT Cmd;
     536    uint32_t u32Resp = 0;
     537
     538    RT_ZERO(Cmd);
     539    Cmd.u32Flags = 0;
     540    return drvTpmEmuExecCtrlCmdEx(pThis, SWTPMCMD_INIT, &Cmd, sizeof(Cmd), &u32Resp,
     541                                  NULL, 0, RT_MS_10SEC);
    381542}
    382543
     
    385546static DECLCALLBACK(int) drvTpmEmuShutdown(PPDMITPMCONNECTOR pInterface)
    386547{
     548    PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
     549
     550    return drvTpmEmuExecCtrlCmdNoPayload(pThis, SWTPMCMD_SHUTDOWN, NULL, 0, RT_MS_10SEC);
     551}
     552
     553
     554/** @interface_method_impl{PDMITPMCONNECTOR,pfnReset} */
     555static DECLCALLBACK(int) drvTpmEmuReset(PPDMITPMCONNECTOR pInterface)
     556{
    387557    RT_NOREF(pInterface);
    388558    return VERR_NOT_IMPLEMENTED;
     
    390560
    391561
    392 /** @interface_method_impl{PDMITPMCONNECTOR,pfnReset} */
    393 static DECLCALLBACK(int) drvTpmEmuReset(PPDMITPMCONNECTOR pInterface)
    394 {
    395     RT_NOREF(pInterface);
    396     return VERR_NOT_IMPLEMENTED;
    397 }
    398 
    399 
    400562/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetVersion} */
    401563static DECLCALLBACK(TPMVERSION) drvTpmEmuGetVersion(PPDMITPMCONNECTOR pInterface)
     
    409571static DECLCALLBACK(bool) drvTpmEmuGetEstablishedFlag(PPDMITPMCONNECTOR pInterface)
    410572{
    411     RT_NOREF(pInterface);
     573    PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
     574
     575    SWTPMRESPGETTPMEST Resp;
     576    int rc = drvTpmEmuExecCtrlCmdNoPayload(pThis, SWTPMCMD_GET_TPMESTABLISHED, &Resp, sizeof(Resp), RT_MS_10SEC);
     577    if (RT_SUCCESS(rc)
     578        && Resp.fEst != 0)
     579        return true;
     580
    412581    return false;
    413582}
     
    417586static DECLCALLBACK(int) drvTpmEmuResetEstablishedFlag(PPDMITPMCONNECTOR pInterface, uint8_t bLoc)
    418587{
    419     RT_NOREF(pInterface, bLoc);
    420     return VERR_NOT_IMPLEMENTED;
     588    PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
     589
     590    SWTPMCMDRSTEST Cmd;
     591    uint32_t u32Resp = 0;
     592
     593    Cmd.bLoc = bLoc;
     594    int rc = drvTpmEmuExecCtrlCmdNoResp(pThis, SWTPMCMD_RESET_TPMESTABLISHED, &Cmd, sizeof(Cmd), &u32Resp, RT_MS_10SEC);
     595    if (   RT_SUCCESS(rc)
     596        && u32Resp != 0)
     597        rc = VERR_NET_IO_ERROR;
     598
     599    return rc;
    421600}
    422601
     
    425604static DECLCALLBACK(int) drvTpmEmuCmdExec(PPDMITPMCONNECTOR pInterface, uint8_t bLoc, const void *pvCmd, size_t cbCmd, void *pvResp, size_t cbResp)
    426605{
    427     RT_NOREF(pInterface, bLoc, pvCmd, cbCmd, pvResp, cbResp);
    428     return VERR_NOT_IMPLEMENTED;
     606    PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
     607
     608    int rc = VINF_SUCCESS;
     609    if (pThis->bLoc != bLoc)
     610        rc = drvTpmEmuSetLocality(pThis, bLoc);
     611
     612    if (RT_SUCCESS(rc))
     613    {
     614        RT_NOREF(pInterface, bLoc, pvCmd, cbCmd, pvResp, cbResp);
     615    }
     616
     617    return rc;
    429618}
    430619
     
    526715    pThis->hSockData                                = NIL_RTSOCKET;
    527716    pThis->enmTpmVers                               = TPMVERSION_UNKNOWN;
     717    pThis->bLoc                                     = TPM_NO_LOCALITY_SELECTED;
    528718
    529719    pThis->hPollSet                                 = NIL_RTPOLLSET;
     
    604794                                   pDrvIns->iInstance, szLocation);
    605795
     796    rc = drvTpmEmuQueryCaps(pThis);
     797    if (RT_FAILURE(rc))
     798        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
     799                                   N_("DrvTpmEmu#%d failed to query capabilities offered by %s"),
     800                                   pDrvIns->iInstance, szLocation);
     801
     802    if (!(pThis->fCaps & SWTPM_CAP_GET_CONFIG))
     803        return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_SUPPORTED, RT_SRC_POS,
     804                                   N_("DrvTpmEmu#%d Emulated TPM misses the GET_CONFIG capability"),
     805                                   pDrvIns->iInstance, szLocation);
     806
    606807    rc = drvTpmEmuQueryTpmVersion(pThis);
    607808    if (RT_FAILURE(rc))
     
    610811                                   pDrvIns->iInstance, szLocation);
    611812
    612     rc = drvTpmEmuQueryAndValidateCaps(pThis);
    613     if (RT_FAILURE(rc))
    614         return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
    615                                    N_("DrvTpmEmu#%d failed to query and validate all capabilities offeres by %s"),
     813    if (pThis->enmTpmVers == TPMVERSION_UNKNOWN)
     814        return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_SUPPORTED, RT_SRC_POS,
     815                                   N_("DrvTpmEmu#%d Emulated TPM version of %s is not supported"),
    616816                                   pDrvIns->iInstance, szLocation);
    617817
    618     LogRel(("DrvTpmEmu#%d: Connected to %s\n", pDrvIns->iInstance, szLocation));
     818    const char *pszTpmVers = NULL;
     819    uint32_t fCapsReq =   SWTPM_CAP_INIT | SWTPM_CAP_SHUTDOWN | SWTPM_CAP_GET_TPMESTABLISHED
     820                        | SWTPM_CAP_SET_LOCALITY | SWTPM_CAP_CANCEL_TPM_CMD | SWTPM_CAP_GET_STATEBLOB
     821                        | SWTPM_CAP_SET_STATEBLOB | SWTPM_CAP_STOP | SWTPM_CAP_SET_BUFFERSIZE;
     822    switch (pThis->enmTpmVers)
     823    {
     824        case TPMVERSION_1_2:
     825            /* No additional capabilities needed. */
     826            pszTpmVers = "1.2";
     827            break;
     828        case TPMVERSION_2_0:
     829            fCapsReq |= SWTPM_CAP_RESET_TPMESTABLISHED;
     830            pszTpmVers = "2.0";
     831            break;
     832        default:
     833            AssertLogRelReturn(("DrvTpmEmu#%d Emulated TPM version %d is not correctly handled", pDrvIns->iInstance, pThis->enmTpmVers),
     834                               VERR_INVALID_STATE);
     835    }
     836
     837    if ((pThis->fCaps & fCapsReq) != fCapsReq)
     838        return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_SUPPORTED, RT_SRC_POS,
     839                                   N_("DrvTpmEmu#%d Emulated TPM version of %s does not offer required set of capabilities (%#x requested vs. %#x offered)"),
     840                                   pDrvIns->iInstance, szLocation, fCapsReq, pThis->fCaps);
     841
     842    LogRel(("DrvTpmEmu#%d: Connected to %s, emulating TPM version %s\n", pDrvIns->iInstance, szLocation, pszTpmVers));
    619843    return VINF_SUCCESS;
    620844}
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