572 lines
20 KiB
C
572 lines
20 KiB
C
/* IBM_PROLOG_BEGIN_TAG */
|
|
/* This is an automatically generated prolog. */
|
|
/* */
|
|
/* $Source: src/usr/secureboot/trusted/tpmLogMgr.C $ */
|
|
/* */
|
|
/* OpenPOWER HostBoot Project */
|
|
/* */
|
|
/* Contributors Listed Below - COPYRIGHT 2015,2016 */
|
|
/* [+] International Business Machines Corp. */
|
|
/* */
|
|
/* */
|
|
/* Licensed under the Apache License, Version 2.0 (the "License"); */
|
|
/* you may not use this file except in compliance with the License. */
|
|
/* You may obtain a copy of the License at */
|
|
/* */
|
|
/* http://www.apache.org/licenses/LICENSE-2.0 */
|
|
/* */
|
|
/* Unless required by applicable law or agreed to in writing, software */
|
|
/* distributed under the License is distributed on an "AS IS" BASIS, */
|
|
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
|
|
/* implied. See the License for the specific language governing */
|
|
/* permissions and limitations under the License. */
|
|
/* */
|
|
/* IBM_PROLOG_END_TAG */
|
|
/**
|
|
* @file TpmLogMgr.C
|
|
*
|
|
* @brief TPM Event log manager
|
|
*/
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// NOTE: This file is exportable as TSS-Lite for skiboot/PHYP //
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
// ----------------------------------------------
|
|
// Includes
|
|
// ----------------------------------------------
|
|
#include <string.h>
|
|
#include "tpmLogMgr.H"
|
|
#ifdef __HOSTBOOT_MODULE
|
|
#include <sys/mm.h>
|
|
#include <util/align.H>
|
|
#include <secureboot/trustedboot_reasoncodes.H>
|
|
#else
|
|
#include "trustedboot_reasoncodes.H"
|
|
#endif
|
|
#include "trustedbootUtils.H"
|
|
#include "trustedboot.H"
|
|
|
|
#ifdef __cplusplus
|
|
namespace TRUSTEDBOOT
|
|
{
|
|
#endif
|
|
|
|
uint32_t TCG_EfiSpecIdEventStruct_size(TCG_EfiSpecIdEventStruct* val)
|
|
{
|
|
return (sizeof(TCG_EfiSpecIdEventStruct) + val->vendorInfoSize);
|
|
}
|
|
|
|
#ifdef __HOSTBOOT_MODULE
|
|
errlHndl_t TpmLogMgr_initialize(TpmLogMgr* val)
|
|
{
|
|
errlHndl_t err = TB_SUCCESS;
|
|
const char vendorInfo[] = "IBM";
|
|
const char eventSignature[] = "Spec ID Event03";
|
|
TCG_EfiSpecIdEventStruct* eventData = NULL;
|
|
|
|
TCG_PCR_EVENT eventLogEntry;
|
|
|
|
TRACUCOMP( g_trac_trustedboot, ">>initialize()");
|
|
|
|
if (NULL == val)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM LOG INIT FAIL");
|
|
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPMLOGMGR_INIT_FAIL
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPMLOGMGR_INITIALIZE
|
|
* @userdata1 0
|
|
* @userdata2 0
|
|
* @devdesc TPM log buffer init failure.
|
|
* @custdesc TPM log buffer init failure.
|
|
*/
|
|
err = tpmCreateErrorLog( MOD_TPMLOGMGR_INITIALIZE,
|
|
RC_TPMLOGMGR_INIT_FAIL, 0, 0);
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
memset(val, 0, sizeof(TpmLogMgr));
|
|
val->logMaxSize = TPMLOG_BUFFER_SIZE;
|
|
|
|
mutex_init( &val->logMutex );
|
|
mutex_lock( &val->logMutex );
|
|
|
|
// Assign our new event pointer to the start
|
|
val->newEventPtr = val->eventLog;
|
|
memset(val->eventLog, 0, TPMLOG_BUFFER_SIZE);
|
|
|
|
eventData = (TCG_EfiSpecIdEventStruct*) eventLogEntry.event;
|
|
|
|
// Add the header event log
|
|
// Values here come from the PC ClientSpecificPlatformProfile spec
|
|
eventLogEntry.eventType = EV_NO_ACTION;
|
|
eventLogEntry.pcrIndex = 0;
|
|
eventLogEntry.eventSize = sizeof(TCG_EfiSpecIdEventStruct) +
|
|
sizeof(vendorInfo);
|
|
|
|
memcpy(eventData->signature, eventSignature,
|
|
sizeof(eventSignature));
|
|
eventData->platformClass = htole32(TPM_PLATFORM_SERVER);
|
|
eventData->specVersionMinor = TPM_SPEC_MINOR;
|
|
eventData->specVersionMajor = TPM_SPEC_MAJOR;
|
|
eventData->specErrata = TPM_SPEC_ERRATA;
|
|
eventData->uintnSize = 1;
|
|
eventData->numberOfAlgorithms = htole32(HASH_COUNT);
|
|
eventData->digestSizes[0].algorithmId = htole16(TPM_ALG_SHA256);
|
|
eventData->digestSizes[0].digestSize = htole16(TPM_ALG_SHA256_SIZE);
|
|
eventData->digestSizes[1].algorithmId = htole16(TPM_ALG_SHA1);
|
|
eventData->digestSizes[1].digestSize = htole16(TPM_ALG_SHA1_SIZE);
|
|
eventData->vendorInfoSize = sizeof(vendorInfo);
|
|
memcpy(eventData->vendorInfo, vendorInfo, sizeof(vendorInfo));
|
|
val->newEventPtr = TCG_PCR_EVENT_logMarshal(&eventLogEntry,
|
|
val->newEventPtr);
|
|
|
|
// Done, move our pointers
|
|
val->logSize += TCG_PCR_EVENT_marshalSize(&eventLogEntry);
|
|
|
|
mutex_unlock( &val->logMutex );
|
|
|
|
// Debug display of raw data
|
|
TRACUBIN(g_trac_trustedboot, "tpmInitialize: Header Entry",
|
|
val->eventLog, val->logSize);
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
"<<initialize() LS:%d - %s",
|
|
val->logSize,
|
|
((TB_SUCCESS == err) ? "No Error" : "With Error") );
|
|
}
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
errlHndl_t TpmLogMgr_initializeUsingExistingLog(TpmLogMgr* val,
|
|
uint8_t* eventLogPtr,
|
|
uint32_t eventLogSize)
|
|
{
|
|
errlHndl_t err = TB_SUCCESS;
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
">>initializeUsingExistingLog()");
|
|
|
|
do
|
|
{
|
|
|
|
mutex_init( &val->logMutex );
|
|
mutex_lock( &val->logMutex );
|
|
|
|
val->logMaxSize = eventLogSize;
|
|
val->eventLogInMem = eventLogPtr;
|
|
|
|
// Ok, walk the log to figure out how big this is
|
|
val->logSize = TpmLogMgr_calcLogSize(val);
|
|
|
|
if (0 == val->logSize)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM LOG INIT WALK FAIL");
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPMLOGMGR_LOGWALKFAIL
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPMLOGMGR_INITIALIZEEXISTLOG
|
|
* @userdata1 0
|
|
* @userdata2 0
|
|
* @devdesc TPM log header entry is missing.
|
|
* @custdesc TPM log invalid format
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPMLOGMGR_INITIALIZEEXISTLOG,
|
|
RC_TPMLOGMGR_LOGWALKFAIL,
|
|
0,
|
|
0);
|
|
break;
|
|
}
|
|
// We are good, let's move the newEventLogPtr
|
|
val->newEventPtr = val->eventLogInMem + val->logSize;
|
|
|
|
}
|
|
while(0);
|
|
|
|
if (TB_SUCCESS != err)
|
|
{
|
|
val->eventLogInMem = NULL;
|
|
val->newEventPtr = NULL;
|
|
val->logMaxSize = 0;
|
|
val->logSize = 0;
|
|
}
|
|
|
|
mutex_unlock( &val->logMutex );
|
|
|
|
return err;
|
|
}
|
|
|
|
errlHndl_t TpmLogMgr_addEvent(TpmLogMgr* val,
|
|
TCG_PCR_EVENT2* logEvent)
|
|
{
|
|
errlHndl_t err = TB_SUCCESS;
|
|
size_t newLogSize = TCG_PCR_EVENT2_marshalSize(logEvent);
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
">>tpmAddEvent() PCR:%d Type:%d Size:%d",
|
|
logEvent->pcrIndex, logEvent->eventType, (int)newLogSize);
|
|
|
|
mutex_lock( &val->logMutex );
|
|
|
|
do
|
|
{
|
|
|
|
// Need to ensure we have room for the new event
|
|
// We have to leave room for the log full event as well
|
|
if (NULL == val->newEventPtr ||
|
|
val->logSize + newLogSize > val->logMaxSize)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM LOG ADD FAIL PNULL(%d) LS(%d) New LS(%d)"
|
|
" Max LS(%d)",
|
|
(NULL == val->newEventPtr ? 0 : 1),
|
|
(int)val->logSize, (int)newLogSize,
|
|
(int)val->logMaxSize);
|
|
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPMLOGMGR_ADDEVENT_FAIL
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPMLOGMGR_ADDEVENT
|
|
* @userdata1[0:31] Max log size
|
|
* @userdata1[32:63] Log buffer NULL
|
|
* @userdata2[0:31] Current Log Size
|
|
* @userdata2[32:63] New entry size
|
|
* @devdesc TPM log buffer add failure.
|
|
* @custdesc TPM log overflow
|
|
*/
|
|
err = tpmCreateErrorLog( MOD_TPMLOGMGR_ADDEVENT,
|
|
RC_TPMLOGMGR_ADDEVENT_FAIL,
|
|
(uint64_t)val->logMaxSize << 32 |
|
|
(NULL == val->newEventPtr ? 0 : 1),
|
|
(uint64_t)val->logSize << 32 |
|
|
newLogSize);
|
|
|
|
break;
|
|
}
|
|
|
|
val->newEventPtr = TCG_PCR_EVENT2_logMarshal(logEvent,
|
|
val->newEventPtr);
|
|
|
|
if (NULL == val->newEventPtr)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM LOG MARSHAL Fail");
|
|
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPMLOGMGR_ADDEVENTMARSH_FAIL
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPMLOGMGR_ADDEVENT
|
|
* @userdata1 0
|
|
* @userdata2 0
|
|
* @devdesc log buffer marshal failure.
|
|
* @custdesc TPM log operation failure
|
|
*/
|
|
err = tpmCreateErrorLog( MOD_TPMLOGMGR_ADDEVENT,
|
|
RC_TPMLOGMGR_ADDEVENTMARSH_FAIL,
|
|
0,
|
|
0);
|
|
break;
|
|
}
|
|
|
|
val->logSize += newLogSize;
|
|
|
|
|
|
} while ( 0 );
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
"<<tpmAddEvent() LS:%d - %s",
|
|
(int)val->logSize,
|
|
((TB_SUCCESS == err) ? "No Error" : "With Error") );
|
|
|
|
mutex_unlock( &val->logMutex );
|
|
return err;
|
|
}
|
|
|
|
uint32_t TpmLogMgr_getLogSize(TpmLogMgr* val)
|
|
{
|
|
return val->logSize;
|
|
}
|
|
|
|
#ifdef __HOSTBOOT_MODULE
|
|
void TpmLogMgr_dumpLog(TpmLogMgr* val)
|
|
{
|
|
|
|
// Debug display of raw data
|
|
TRACUCOMP(g_trac_trustedboot, "tpmDumpLog Size : %d",
|
|
(int)val->logSize);
|
|
|
|
// Debug display of raw data
|
|
if (NULL == val->eventLogInMem)
|
|
{
|
|
TRACUBIN(g_trac_trustedboot, "tpmDumpLog",
|
|
val->eventLog, val->logSize);
|
|
}
|
|
else
|
|
{
|
|
TRACUBIN(g_trac_trustedboot, "tpmDumpLog From Memory",
|
|
val->eventLogInMem, val->logSize);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
uint32_t TpmLogMgr_calcLogSize(TpmLogMgr* val)
|
|
{
|
|
uint32_t logSize = 0;
|
|
TCG_PCR_EVENT event;
|
|
TCG_PCR_EVENT2 event2;
|
|
bool errorFound = false;
|
|
const uint8_t* prevLogHandle = NULL;
|
|
const uint8_t* nextLogHandle = NULL;
|
|
|
|
TRACUCOMP( g_trac_trustedboot, ">>calcLogSize");
|
|
|
|
// Start walking events
|
|
prevLogHandle = TpmLogMgr_getLogStartPtr(val);
|
|
do
|
|
{
|
|
|
|
// First need to deal with the header entry
|
|
nextLogHandle = TCG_PCR_EVENT_logUnmarshal(&event,
|
|
prevLogHandle,
|
|
sizeof(TCG_PCR_EVENT),
|
|
&errorFound);
|
|
|
|
if (NULL == nextLogHandle || errorFound ||
|
|
EV_NO_ACTION != event.eventType ||
|
|
0 == event.eventSize)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot, "Header Marshal Failure");
|
|
prevLogHandle = NULL;
|
|
break;
|
|
}
|
|
|
|
if (( nextLogHandle - TpmLogMgr_getLogStartPtr(val)) >
|
|
val->logMaxSize)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot, "calcLogSize overflow");
|
|
prevLogHandle = NULL;
|
|
break;
|
|
}
|
|
prevLogHandle = nextLogHandle;
|
|
|
|
// Now iterate through all the other events
|
|
while (NULL != prevLogHandle)
|
|
{
|
|
nextLogHandle = TCG_PCR_EVENT2_logUnmarshal(
|
|
&event2,
|
|
prevLogHandle,
|
|
sizeof(TCG_PCR_EVENT2),
|
|
&errorFound);
|
|
if (NULL == nextLogHandle || errorFound)
|
|
{
|
|
// Failed parsing so we must have hit the end of log
|
|
break;
|
|
}
|
|
if (( nextLogHandle - TpmLogMgr_getLogStartPtr(val)) >
|
|
val->logMaxSize)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot, "calcLogSize overflow");
|
|
prevLogHandle = NULL;
|
|
break;
|
|
}
|
|
prevLogHandle = nextLogHandle;
|
|
}
|
|
}
|
|
while (0);
|
|
|
|
if (NULL == prevLogHandle)
|
|
{
|
|
logSize = 0;
|
|
}
|
|
else
|
|
{
|
|
logSize = (prevLogHandle - TpmLogMgr_getLogStartPtr(val));
|
|
}
|
|
TRACUCOMP( g_trac_trustedboot, "<<calcLogSize : %d", logSize);
|
|
|
|
return logSize;
|
|
}
|
|
|
|
const uint8_t* TpmLogMgr_getFirstEvent(TpmLogMgr* val)
|
|
{
|
|
TCG_PCR_EVENT event;
|
|
bool err = false;
|
|
const uint8_t* result = NULL;
|
|
|
|
// Header event in the log is always first, we skip over that
|
|
const uint8_t* firstEvent = TpmLogMgr_getLogStartPtr(val);
|
|
memset(&event, 0, sizeof(TCG_PCR_EVENT));
|
|
|
|
firstEvent = TCG_PCR_EVENT_logUnmarshal(&event, firstEvent,
|
|
sizeof(TCG_PCR_EVENT),
|
|
&err);
|
|
if (NULL != firstEvent && !err &&
|
|
firstEvent < val->newEventPtr)
|
|
{
|
|
result = firstEvent;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
const uint8_t* TpmLogMgr_getNextEvent(TpmLogMgr* val,
|
|
const uint8_t* i_handle,
|
|
TCG_PCR_EVENT2* i_eventLog,
|
|
bool* o_err)
|
|
{
|
|
const uint8_t* l_resultPtr = NULL;
|
|
if (NULL == i_handle)
|
|
{
|
|
*o_err = true;
|
|
}
|
|
else
|
|
{
|
|
memset(i_eventLog, 0, sizeof(TCG_PCR_EVENT2));
|
|
TRACUCOMP( g_trac_trustedboot, "TPM getNextEvent 0x%p", i_handle);
|
|
l_resultPtr = TCG_PCR_EVENT2_logUnmarshal(i_eventLog, i_handle,
|
|
sizeof(TCG_PCR_EVENT2),
|
|
o_err);
|
|
if (NULL == l_resultPtr)
|
|
{
|
|
// An error was detected, ensure o_err is set
|
|
*o_err = true;
|
|
}
|
|
else if (l_resultPtr >= val->newEventPtr)
|
|
{
|
|
l_resultPtr = NULL;
|
|
}
|
|
}
|
|
|
|
return l_resultPtr;
|
|
}
|
|
|
|
TCG_PCR_EVENT2 TpmLogMgr_genLogEventPcrExtend(TPM_Pcr i_pcr,
|
|
TPM_Alg_Id i_algId_1,
|
|
const uint8_t* i_digest_1,
|
|
size_t i_digestSize_1,
|
|
TPM_Alg_Id i_algId_2,
|
|
const uint8_t* i_digest_2,
|
|
size_t i_digestSize_2,
|
|
uint32_t i_logType,
|
|
const char* i_logMsg)
|
|
{
|
|
TCG_PCR_EVENT2 eventLog;
|
|
size_t fullDigestSize_1 = 0;
|
|
size_t fullDigestSize_2 = 0;
|
|
|
|
fullDigestSize_1 = getDigestSize(i_algId_1);
|
|
if (NULL != i_digest_2)
|
|
{
|
|
fullDigestSize_2 = getDigestSize(i_algId_2);
|
|
}
|
|
|
|
memset(&eventLog, 0, sizeof(eventLog));
|
|
eventLog.pcrIndex = i_pcr;
|
|
eventLog.eventType = i_logType;
|
|
|
|
// Update digest information
|
|
eventLog.digests.count = 1;
|
|
eventLog.digests.digests[0].algorithmId = i_algId_1;
|
|
memcpy(&(eventLog.digests.digests[0].digest),
|
|
i_digest_1,
|
|
(i_digestSize_1 < fullDigestSize_1 ?
|
|
i_digestSize_1 : fullDigestSize_1));
|
|
|
|
if (NULL != i_digest_2)
|
|
{
|
|
eventLog.digests.count = 2;
|
|
eventLog.digests.digests[1].algorithmId = i_algId_2;
|
|
memcpy(&(eventLog.digests.digests[1].digest),
|
|
i_digest_2,
|
|
(i_digestSize_2 < fullDigestSize_2 ?
|
|
i_digestSize_2 : fullDigestSize_2));
|
|
}
|
|
// Event field data
|
|
eventLog.event.eventSize = strlen(i_logMsg);
|
|
memset(eventLog.event.event, 0, sizeof(eventLog.event.event));
|
|
memcpy(eventLog.event.event, i_logMsg,
|
|
(strlen(i_logMsg) > MAX_TPM_LOG_MSG ?
|
|
MAX_TPM_LOG_MSG - 1 // Leave room for NULL termination
|
|
: strlen(i_logMsg)) );
|
|
|
|
return eventLog;
|
|
}
|
|
|
|
|
|
uint8_t* TpmLogMgr_getLogStartPtr(TpmLogMgr* val)
|
|
{
|
|
#ifdef __HOSTBOOT_MODULE
|
|
return (val->eventLogInMem == NULL ?
|
|
reinterpret_cast<uint8_t*>(&(val->eventLog)) : val->eventLogInMem);
|
|
#else
|
|
return val->eventLogInMem;
|
|
#endif
|
|
}
|
|
|
|
#ifdef __HOSTBOOT_MODULE
|
|
errlHndl_t TpmLogMgr_getDevtreeInfo(TpmLogMgr* val,
|
|
uint64_t & io_logAddr,
|
|
size_t & o_allocationSize,
|
|
uint64_t & o_xscomAddr,
|
|
uint32_t & o_i2cMasterOffset)
|
|
{
|
|
errlHndl_t err = NULL;
|
|
|
|
mutex_lock( &val->logMutex );
|
|
|
|
assert(io_logAddr != 0, "Invalid starting log address");
|
|
assert(val->eventLogInMem == NULL,
|
|
"getDevtreeInfo can only be called once");
|
|
|
|
io_logAddr -= ALIGN_PAGE(TPMLOG_DEVTREE_SIZE);
|
|
// Align to 64KB for Opal
|
|
io_logAddr = ALIGN_DOWN_X(io_logAddr,64*KILOBYTE);
|
|
|
|
val->inMemlogBaseAddr = io_logAddr;
|
|
o_allocationSize = TPMLOG_DEVTREE_SIZE;
|
|
o_xscomAddr = val->devtreeXscomAddr;
|
|
o_i2cMasterOffset = val->devtreeI2cMasterOffset;
|
|
|
|
// Copy image.
|
|
val->eventLogInMem = (uint8_t*)(mm_block_map(
|
|
(void*)(io_logAddr),
|
|
ALIGN_PAGE(TPMLOG_DEVTREE_SIZE)));
|
|
// Copy log into new location
|
|
memset(val->eventLogInMem, 0, TPMLOG_DEVTREE_SIZE);
|
|
memcpy(val->eventLogInMem, val->eventLog, val->logSize);
|
|
val->newEventPtr = val->eventLogInMem + val->logSize;
|
|
|
|
mutex_unlock( &val->logMutex );
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
"<<getDevtreeInfo() Addr:%lX - %s",
|
|
io_logAddr,
|
|
((TB_SUCCESS == err) ? "No Error" : "With Error") );
|
|
return err;
|
|
}
|
|
|
|
|
|
void TpmLogMgr_setTpmDevtreeInfo(TpmLogMgr* val,
|
|
uint64_t i_xscomAddr,
|
|
uint32_t i_i2cMasterOffset)
|
|
{
|
|
val->devtreeXscomAddr = i_xscomAddr;
|
|
val->devtreeI2cMasterOffset = i_i2cMasterOffset;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
} // end TRUSTEDBOOT
|
|
#endif
|