Skip to content

Commit

Permalink
Support TPM PCR Poisoning
Browse files Browse the repository at this point in the history
To support Fleetwood secure inter-node communication, we need to
“poison” the PCRs of all still functional non-master node TPMs
just prior to transferring control to PHyp, and report that
poisoned state to HDAT.

Change-Id: Ic104ef2e44fc98895b9b435fdf8ba4c5e4972818
RTC:191001
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/58244
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com>
Reviewed-by: Michael Baiocchi <mbaiocch@us.ibm.com>
Reviewed-by: ILYA SMIRNOV <ismirno@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
  • Loading branch information
popfuture authored and dcrowell77 committed May 23, 2018
1 parent 11b5f7d commit e9eacec
Show file tree
Hide file tree
Showing 6 changed files with 393 additions and 99 deletions.
27 changes: 25 additions & 2 deletions src/include/usr/secureboot/trustedbootif.H
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,18 @@ namespace TRUSTEDBOOT
void* host_update_master_tpm( void *io_pArgs );

/**
* @brief Extend a measurement into the TPMs and log atomically
* @brief Extend a measurement into the TPM(s) and log atomically
* @param[in] i_pcr PCR to write to
* @param[in] i_eventType Event type to log
* @param[in] i_digest Digest value to write to PCR
* @param[in] i_digestSize Byte size of i_digest data
* @param[in] i_logMsg Null terminated log message, truncated at 128 chars
* @param[in] i_sendAsync Perform extension asynchronously, default true
* @param[in] i_pTpm A specific TPM to singly extend a measurement into,
default is nullptr, which indicates all of the TPMs will be
extended.
* @param[in] i_mirrorToLog After extending the measurement, mirror to log.
* default is true. Typically, false is used to poison the TPM.
* @return errlHndl_t NULL if successful, otherwise a pointer to the
* error log.
* Digest will be right padded with zeros or truncated to match TPM digest
Expand All @@ -152,7 +157,9 @@ namespace TRUSTEDBOOT
const uint8_t* i_digest,
size_t i_digestSize,
const char* i_logMsg,
bool i_sendAsync = true);
bool i_sendAsync = true,
const TpmTarget* i_pTpm = nullptr,
bool i_mirrorToLog = true);

/**
* @brief Extend a separator into the TPMs and log atomically
Expand Down Expand Up @@ -250,6 +257,22 @@ namespace TRUSTEDBOOT
errlHndl_t GetRandom(const TpmTarget* i_pTpm, uint64_t& o_randNum);
#endif

/**
* @brief Poison a TPM. Poisoning a TPM's PCR means extending a random
* number measurement to the TPM, but not to the corresponding log
* entry. This includes extending random numbers to every bank/PCR
* combo in use by the firmware (sha1/sha256 banks of PCR 0-7). The
* random number along with the absent log entry makes remote
* attestation impossible with that TPM for that boot.
*
* @parm[in] i_pTpm Pointer to the TPM target to be poisoned. Must be a TPM
* and must not be nullptr
*
* @return errlHndl_t nullptr if successful or error log otherwise. Failure
* to poison a TPM will result in deconfiguring the TPM.
*/
errlHndl_t poisonTpm(const TpmTarget* i_pTpm);

/**
* @brief Helper function for validating TPM handles. Returns an error log
* if the supplied TPM is null, not a TPM target, or not functional.
Expand Down
44 changes: 43 additions & 1 deletion src/usr/runtime/populate_hbruntime.C
Original file line number Diff line number Diff line change
Expand Up @@ -1732,6 +1732,43 @@ errlHndl_t populate_TpmInfoByNode(const uint64_t i_instance)
// fill in the values for each Secure Boot TPM Instance Info in the array
for (auto pTpm : tpmList)
{
uint8_t poisonedFlag = 0;
#ifdef CONFIG_TPMDD
if (!TARGETING::UTIL::isCurrentMasterNode()) // if not master node TPM
{

auto l_tpmHwasState = pTpm->getAttr<TARGETING::ATTR_HWAS_STATE>();
if (l_tpmHwasState.functional)
{

// poison the TPM's PCRs
l_elog = TRUSTEDBOOT::poisonTpm(pTpm);
if (l_elog)
{
l_tpmHwasState = pTpm->getAttr<TARGETING::ATTR_HWAS_STATE>();
if (l_tpmHwasState.functional)
{
// The TPM was still functional, we have a software bug
// on our hands. We need to break out of here and quit.
break;
}
else
{
// There was a hardware problem with the TPM. It was
// marked failed and deconfigured, so we commit the
// error log and move on as though it were not
// functional to begin with
ERRORLOG::errlCommit(l_elog, RUNTIME_COMP_ID);
}
}
else
{
poisonedFlag = 1;
}
}
}
#endif // CONFIG_TPMDD

auto l_tpmInstInfo = reinterpret_cast<HDAT::hdatSbTpmInstInfo_t*>
(l_baseAddr + l_currOffset);

Expand Down Expand Up @@ -1806,7 +1843,7 @@ errlHndl_t populate_TpmInfoByNode(const uint64_t i_instance)
}

// Set TPM configuration flag
l_tpmInstInfo->hdatTpmConfigFlags.pcrPoisonedFlag = 0;
l_tpmInstInfo->hdatTpmConfigFlags.pcrPoisonedFlag = poisonedFlag;

// advance the current offset to account for this tpm instance info
l_currOffset += sizeof(*l_tpmInstInfo);
Expand All @@ -1816,6 +1853,11 @@ errlHndl_t populate_TpmInfoByNode(const uint64_t i_instance)

}

if (l_elog)
{
break;
}

for (auto tpmInstPair : fixList)
{
const auto pTpm = tpmInstPair.first;
Expand Down
14 changes: 8 additions & 6 deletions src/usr/secureboot/trusted/base/trustedbootMsg.H
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,14 @@ namespace TRUSTEDBOOT
/// PCREXTEND message data
struct PcrExtendMsgData
{
TPM_Pcr mPcrIndex;
TPM_Alg_Id mAlgId;
EventTypes mEventType;
size_t mDigestSize;
uint8_t mDigest[TPM_ALG_SHA256_SIZE];
char mLogMsg[MAX_TPM_LOG_MSG];
TPM_Pcr mPcrIndex;
TPM_Alg_Id mAlgId;
EventTypes mEventType;
size_t mDigestSize;
uint8_t mDigest[TPM_ALG_SHA256_SIZE];
char mLogMsg[MAX_TPM_LOG_MSG];
const TpmTarget* mSingleTpm;
bool mMirrorToLog;
};

struct GetRandomMsgData
Expand Down
87 changes: 11 additions & 76 deletions src/usr/secureboot/trusted/base/trustedboot_base.C
Original file line number Diff line number Diff line change
Expand Up @@ -200,15 +200,18 @@ errlHndl_t pcrExtend(TPM_Pcr i_pcr,
const uint8_t* i_digest,
size_t i_digestSize,
const char* i_logMsg,
bool i_sendAsync)
bool i_sendAsync,
const TpmTarget* i_pTpm,
const bool i_mirrorToLog)
{
errlHndl_t err = NULL;
#ifdef CONFIG_TPMDD
MessageMode mode = MSG_MODE_ASYNC;

TRACDCOMP( g_trac_trustedboot, ENTER_MRK"pcrExtend()" );
TRACUCOMP( g_trac_trustedboot,
ENTER_MRK"pcrExtend() pcr=%d msg='%s'", i_pcr, i_logMsg);
ENTER_MRK"pcrExtend() pcr=%d msg='%s'",
i_pcr, i_logMsg? i_logMsg: "(null)");
TRACUBIN(g_trac_trustedboot, "pcrExtend() digest:", i_digest, i_digestSize);

// msgData will be freed when message is freed
Expand All @@ -219,16 +222,21 @@ errlHndl_t pcrExtend(TPM_Pcr i_pcr,
msgData->mEventType = i_eventType;
msgData->mDigestSize = (i_digestSize < sizeof(msgData->mDigest) ?
i_digestSize : sizeof(msgData->mDigest));
msgData->mSingleTpm = i_pTpm;
msgData->mMirrorToLog = i_mirrorToLog;


// copy over the incoming digest and truncate to what we need
memcpy(msgData->mDigest, i_digest, msgData->mDigestSize);

// Truncate logMsg if required
memcpy(msgData->mLogMsg, i_logMsg,
if (i_logMsg)
{
memcpy(msgData->mLogMsg, i_logMsg,
(strlen(i_logMsg) < sizeof(msgData->mLogMsg) ? strlen(i_logMsg) :
sizeof(msgData->mLogMsg)-1) // Leave room for NULL termination
);
}

if (!i_sendAsync)
{
Expand Down Expand Up @@ -794,77 +802,4 @@ errlHndl_t testCmpPrimaryAndBackupTpm()
return l_err;
}

#ifdef CONFIG_TPMDD
errlHndl_t GetRandom(const TpmTarget* i_pTpm, uint64_t& o_randNum)
{
errlHndl_t err = nullptr;
Message* msg = nullptr;

do {

auto pData = new struct GetRandomMsgData;
memset(pData, 0, sizeof(*pData));

pData->i_pTpm = const_cast<TpmTarget*>(i_pTpm);

msg = Message::factory(MSG_TYPE_GETRANDOM, sizeof(*pData),
reinterpret_cast<uint8_t*>(pData), MSG_MODE_SYNC);

assert(msg != nullptr, "BUG! Message is null");
pData = nullptr; // Message owns msgData now

int rc = msg_sendrecv(systemData.msgQ, msg->iv_msg);
if (0 == rc)
{
err = msg->iv_errl;
msg->iv_errl = nullptr; // taking over ownership of error log
if (err != nullptr)
{
break;
}
}
else // sendrecv failure
{
/*@
* @errortype ERRL_SEV_UNRECOVERABLE
* @moduleid MOD_TPM_GETRANDOM
* @reasoncode RC_SENDRECV_FAIL
* @userdata1 rc from msq_sendrecv()
* @userdata2 TPM HUID if it's not nullptr
* @devdesc msg_sendrecv() failed
* @custdesc Trusted boot failure
*/
err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
MOD_TPM_GETRANDOM,
RC_SENDRECV_FAIL,
rc,
TARGETING::get_huid(i_pTpm),
true);
break;
}

pData = reinterpret_cast<struct GetRandomMsgData*>(msg->iv_data);
assert(pData != nullptr,
"BUG! Completed send/recv to random num generator has null data ptr!");

o_randNum = pData->o_randNum;

} while (0);

if (msg != nullptr)
{
delete msg; // also deletes the msg->iv_data
msg = nullptr;
}

if (err)
{
err->collectTrace(SECURE_COMP_NAME);
err->collectTrace(TRBOOT_COMP_NAME);
}

return err;
}
#endif // CONFIG_TPMDD

} // end TRUSTEDBOOT

0 comments on commit e9eacec

Please sign in to comment.