diff options
author | Stephen Cprek <smcprek@us.ibm.com> | 2017-04-20 16:55:27 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2017-04-28 15:42:23 -0400 |
commit | e53a2e5cd5b152d6e565f56867f1f8cd435e7556 (patch) | |
tree | 9586a89a945da5b2f684688a9a421dadb494ee8b /src/usr/pnor | |
parent | f30075299ce2c078705192b1835b70eff4f08fc1 (diff) | |
download | talos-hostboot-e53a2e5cd5b152d6e565f56867f1f8cd435e7556.tar.gz talos-hostboot-e53a2e5cd5b152d6e565f56867f1f8cd435e7556.zip |
Implement Best Effort Secureboot Policy for Hostboot Runtime
Optimized getting the master proc id in rt_pnor
Change-Id: Iab5c194553dddfbb642cfc9dec6398a93ab56d4a
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/39520
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Michael Baiocchi <mbaiocch@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/pnor')
-rw-r--r-- | src/usr/pnor/pnor_common.C | 7 | ||||
-rw-r--r-- | src/usr/pnor/pnor_utils.C | 4 | ||||
-rw-r--r-- | src/usr/pnor/pnor_utils.H | 2 | ||||
-rw-r--r-- | src/usr/pnor/runtime/rt_pnor.C | 199 | ||||
-rw-r--r-- | src/usr/pnor/runtime/rt_pnor.H | 29 |
5 files changed, 181 insertions, 60 deletions
diff --git a/src/usr/pnor/pnor_common.C b/src/usr/pnor/pnor_common.C index e6e7bd2a1..b3bc54c35 100644 --- a/src/usr/pnor/pnor_common.C +++ b/src/usr/pnor/pnor_common.C @@ -388,6 +388,7 @@ bool PNOR::isInhibitedSection(const uint32_t i_section) #endif } +// @TODO RTC:155374 Remove this in the future errlHndl_t PNOR::setSecure(const uint32_t i_secId, PNOR::SectionData_t* io_TOC) { @@ -407,9 +408,9 @@ errlHndl_t PNOR::setSecure(const uint32_t i_secId, // Apply best effort policy by checking if the section appears to have a // secure header size_t l_size = sizeof(ROM_MAGIC_NUMBER); - auto l_buf = new uint8_t[l_size](); + uint8_t l_buf[l_size] = {0}; auto l_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; - // Read first 8 bytes of section data from the PNOR DD + // Read first 4 bytes of section data from the PNOR DD // Note: Do not need to worry about ECC as the 9th byte is the first // ECC byte. l_errhdl = DeviceFW::deviceRead(l_target, l_buf, l_size, @@ -419,7 +420,7 @@ errlHndl_t PNOR::setSecure(const uint32_t i_secId, break; } - // Check if first 8 bytes match the Secureboot Magic Number + // Check if first 4 bytes match the Secureboot Magic Number io_TOC[i_secId].secure &= PNOR::cmpSecurebootMagicNumber(l_buf); } #endif diff --git a/src/usr/pnor/pnor_utils.C b/src/usr/pnor/pnor_utils.C index 979b1cb1f..a5950bc20 100644 --- a/src/usr/pnor/pnor_utils.C +++ b/src/usr/pnor/pnor_utils.C @@ -212,7 +212,7 @@ void PNOR::checkHeader (ffs_hdr* i_ffs_hdr, * @brief Takes in an ffs_entry and returns the enum version of the section * title. */ -void PNOR::getSectionEnum (ffs_entry* i_entry, +void PNOR::getSectionEnum (const ffs_entry* i_entry, uint32_t* o_secId) { *o_secId = PNOR::INVALID_SECTION; @@ -321,7 +321,7 @@ PNOR::parseEntries (ffs_hdr* i_ffs_hdr, #ifdef BOOTLOADER io_TOC[secId].secure = PNOR::isEnforcedSecureSection(secId); -#else +#elif !defined(__HOSTBOOT_RUNTIME) // runtime is handled by rt_pnor code // Check if PNOR section has a secureHeader or not. l_errhdl = PNOR::setSecure(secId, io_TOC); if (l_errhdl) diff --git a/src/usr/pnor/pnor_utils.H b/src/usr/pnor/pnor_utils.H index 6007b3492..700820644 100644 --- a/src/usr/pnor/pnor_utils.H +++ b/src/usr/pnor/pnor_utils.H @@ -183,7 +183,7 @@ void checkHeader (ffs_hdr* i_ffs_hdr, * enums found in include/usr/pnor/pnor_const.H * */ -void getSectionEnum (ffs_entry* i_entry, +void getSectionEnum (const ffs_entry* i_entry, uint32_t* o_secId); /** * @brief Iterate through the entries, each which represent a section in pnor. diff --git a/src/usr/pnor/runtime/rt_pnor.C b/src/usr/pnor/runtime/rt_pnor.C index 484d47e7d..a614ae274 100644 --- a/src/usr/pnor/runtime/rt_pnor.C +++ b/src/usr/pnor/runtime/rt_pnor.C @@ -38,6 +38,8 @@ #include "../ffs.h" #include "../common/ffs_hb.H" #include <util/align.H> +#include <runtime/customize_attrs_for_payload.H> +#include <securerom/ROM.H> // Trace definition extern trace_desc_t* g_trac_pnor; @@ -47,6 +49,8 @@ extern trace_desc_t* g_trac_pnor; */ TASK_ENTRY_MACRO( RtPnor::init ); +// @TODO RTC:155374 Remove this in the future +const size_t BEST_EFFORT_NUM_BYTES = 32; /** * @brief Return the size and address of a given section of PNOR data @@ -103,6 +107,9 @@ void PNOR::getPnorInfo( PnorInfo_t& o_pnorInfo ) } /****************Public Methods***************************/ + +uint64_t RtPnor::iv_masterProcId = RUNTIME::HBRT_HYP_ID_UNKNOWN; + /** * STATIC * @brief Static Initializer @@ -110,7 +117,18 @@ void PNOR::getPnorInfo( PnorInfo_t& o_pnorInfo ) void RtPnor::init(errlHndl_t &io_taskRetErrl) { TRACFCOMP(g_trac_pnor, "RtPnor::init> " ); + do { + io_taskRetErrl = Singleton<RtPnor>::instance().getMasterProcId(); + if (io_taskRetErrl) + { + break; + } io_taskRetErrl = Singleton<RtPnor>::instance().readTOC(); + if (io_taskRetErrl) + { + break; + } + }while (0); TRACFCOMP(g_trac_pnor, "<RtPnor::init" ); } /**************************************************************/ @@ -158,16 +176,6 @@ errlHndl_t RtPnor::getSectionInfo(PNOR::SectionId i_section, i_section, 0,true); break; } - //find proc id - uint64_t l_procId; - TARGETING::Target* l_masterProc = NULL; - TARGETING::targetService().masterProcChipTargetHandle( l_masterProc ); - l_err = RT_TARG::getRtTarget (l_masterProc, l_procId); - if (l_err) - { - TRACFCOMP(g_trac_pnor, "RtPnor::getSectionInfo: getRtTarget failed"); - break; - } //ecc bool l_ecc = (iv_TOC[i_section].integrity&FFS_INTEG_ECC_PROTECT) ? @@ -192,8 +200,8 @@ errlHndl_t RtPnor::getSectionInfo(PNOR::SectionId i_section, l_pClean = malloc(l_sizeBytes); //offset = 0 : read the entire section - l_err = readFromDevice(l_procId, i_section, 0, l_sizeBytes, l_ecc, - l_pWorking); + l_err = readFromDevice(iv_masterProcId, i_section, 0, l_sizeBytes, + l_ecc, l_pWorking); if(l_err) { TRACFCOMP(g_trac_pnor, "RtPnor::getSectionInfo:readFromDevice" @@ -218,6 +226,15 @@ errlHndl_t RtPnor::getSectionInfo(PNOR::SectionId i_section, (iv_TOC[i_section].version & FFS_VERS_SHA512) ? true : false; o_info.sha512perEC = (iv_TOC[i_section].version & FFS_VERS_SHA512_PER_EC) ? true : false; +#ifdef CONFIG_SECUREBOOT + // We don't verify PNOR sections at runtime, but we + // still have to bypass the secure header + if(iv_TOC[i_section].secure) + { + o_info.vaddr += PAGESIZE; + o_info.size -= PAGESIZE; + } +#endif } while (0); TRACFCOMP(g_trac_pnor, EXIT_MRK"RtPnor::getSectionInfo"); @@ -283,16 +300,6 @@ errlHndl_t RtPnor::flush( PNOR::SectionId i_section) //ecc bool l_ecc = (iv_TOC[i_section].integrity&FFS_INTEG_ECC_PROTECT) ? true : false; - //find proc id - uint64_t l_procId; - TARGETING::Target* l_masterProc = NULL; - TARGETING::targetService().masterProcChipTargetHandle( l_masterProc ); - l_err = RT_TARG::getRtTarget (l_masterProc, l_procId); - if (l_err) - { - TRACFCOMP(g_trac_pnor, "RtPnor::flush: getRtTarget failed"); - break; - } //find the diff between each pointer //write back to pnor what doesn't match @@ -303,8 +310,8 @@ errlHndl_t RtPnor::flush( PNOR::SectionId i_section) { TRACFCOMP(g_trac_pnor, "RtPnor::flush: page %d is different," " writing back to pnor", i); - l_err = writeToDevice(l_procId, i_section, i*PAGESIZE,PAGESIZE, - l_ecc,l_pWorking); + l_err = writeToDevice(iv_masterProcId, i_section, + i*PAGESIZE,PAGESIZE, l_ecc, l_pWorking); if (l_err) { TRACFCOMP(g_trac_pnor, "RtPnor::flush: writeToDevice failed"); @@ -331,12 +338,20 @@ errlHndl_t RtPnor::flush( PNOR::SectionId i_section) /*******Protected Methods**************/ RtPnor::RtPnor() { - errlHndl_t l_err = readTOC(); + do { + errlHndl_t l_err = getMasterProcId(); if (l_err) { errlCommit(l_err, PNOR_COMP_ID); + break; } - + l_err = readTOC(); + if (l_err) + { + errlCommit(l_err, PNOR_COMP_ID); + break; + } + } while (0); } /*************************/ @@ -350,7 +365,7 @@ errlHndl_t RtPnor::readFromDevice (uint64_t i_procId, uint64_t i_offset, size_t i_size, bool i_ecc, - void* o_data) + void* o_data) const { TRACFCOMP(g_trac_pnor, ENTER_MRK"RtPnor::readFromDevice: i_offset=0x%X, " "i_procId=%d sec=%d size=0x%X ecc=%d", i_offset, i_procId, i_section, @@ -648,26 +663,16 @@ errlHndl_t RtPnor::writeToDevice( uint64_t i_procId, errlHndl_t RtPnor::readTOC () { TRACFCOMP(g_trac_pnor, ENTER_MRK"RtPnor::readTOC" ); - errlHndl_t l_err = NULL; + errlHndl_t l_err = nullptr; uint8_t* l_toc0Buffer = new uint8_t[PNOR::TOC_SIZE]; do { if (g_hostInterfaces && g_hostInterfaces->pnor_read) { - //find proc id - uint64_t l_procId; - TARGETING::Target* l_masterProc = NULL; - TARGETING::targetService().masterProcChipTargetHandle(l_masterProc); - l_err = RT_TARG::getRtTarget (l_masterProc, l_procId); - if (l_err) - { - TRACFCOMP(g_trac_pnor, "RtPnor::readTOC: getRtTarget failed"); - break; - } // offset = 0 means read the entire PNOR::TOC partition // This offset is offset into the partition, not offset from the // beginning of the flash - l_err = readFromDevice (l_procId, PNOR::TOC, 0, - PNOR::TOC_SIZE, false, l_toc0Buffer); + l_err = readFromDevice (iv_masterProcId, PNOR::TOC, 0, + PNOR::TOC_SIZE, false, l_toc0Buffer); if (l_err) { TRACFCOMP(g_trac_pnor,"RtPnor::readTOC:readFromDevice failed" @@ -684,10 +689,19 @@ errlHndl_t RtPnor::readTOC () TRACFCOMP(g_trac_pnor, "RtPnor::readTOC: parseTOC failed"); break; } + + // Check if PNOR section has a secureHeader or not. + // Cannot do a device read during parseTOC in Runtime, so do after. + l_err = setSecure(l_toc0Buffer, iv_TOC); + if (l_err) + { + TRACFCOMP(g_trac_pnor, "RtPnor::readTOC: setSecure failed"); + break; + } } } while (0); - if(l_toc0Buffer != NULL) + if(l_toc0Buffer != nullptr) { delete[] l_toc0Buffer; } @@ -696,6 +710,73 @@ errlHndl_t RtPnor::readTOC () return l_err; } +// @TODO RTC:155374 Remove this in the future +errlHndl_t RtPnor::setSecure(const uint8_t* i_tocBuffer, + PNOR::SectionData_t* io_TOC) const +{ + errlHndl_t l_errhdl = nullptr; + + assert(i_tocBuffer != nullptr, "RtPnor::setSecure received a NULL tocBuffer to read"); + assert(io_TOC != nullptr, "RtPnor::setSecure received a NULL toc to modify"); + + do { + // Set secure flag for each section after the TOC + // Walk through all the entries in the table and parse the data. + auto const l_ffs_hdr = reinterpret_cast<const ffs_hdr*>(i_tocBuffer); + for(uint32_t i=0; i<l_ffs_hdr->entry_count; ++i) + { + uint32_t l_secId = PNOR::INVALID_SECTION; + + // Get current entry section id + auto cur_entry = &(l_ffs_hdr->entries[i]); + PNOR::getSectionEnum(cur_entry, &l_secId); + if(l_secId == PNOR::INVALID_SECTION) + { + TRACFCOMP(g_trac_pnor, "RtPnor::setSecure Unrecognized Section name(%s), skipping",cur_entry->name); + continue; + } + + // Set secure field based on enforced policy + io_TOC[l_secId].secure = PNOR::isEnforcedSecureSection(l_secId); + +#ifdef CONFIG_SECUREBOOT_BEST_EFFORT + if (io_TOC[l_secId].secure) + { + // Apply best effort policy by checking if the section appears to have a + // secure header + // Need to read first 4 bytes of data to check version header + // Note: For OPAL and PHYP need to read 8 bytes for ECC checking + // In CXX test a pnorDD read is called and requires a + // multiple of 4 bytes. If the section as ECC then it + // needs to be a multiple of 4 bytes after ECC. + // 32 Bytes fulfills both requirements. + size_t l_size = BEST_EFFORT_NUM_BYTES; + uint8_t l_buf[l_size] = {0}; + + bool l_ecc = io_TOC[l_secId].integrity & FFS_INTEG_ECC_PROTECT; + // Read first 8 bytes of section data from PNOR + l_errhdl = readFromDevice(iv_masterProcId, + static_cast<PNOR::SectionId>(l_secId), + 0, l_size, l_ecc, l_buf); + if (l_errhdl) + { + break; + } + + // Check if first 4 bytes match the Secureboot Magic Number + io_TOC[l_secId].secure &= PNOR::cmpSecurebootMagicNumber(l_buf); + } +#endif + } + if (l_errhdl) + { + break; + } + } while(0); + + return l_errhdl; +} + /***********************************************************/ RtPnor& RtPnor::getInstance() { @@ -797,17 +878,6 @@ errlHndl_t RtPnor::clearSection(PNOR::SectionId i_section) l_size = (l_size*9)/8; } - //find proc id - uint64_t l_procId; - TARGETING::Target* l_masterProc = NULL; - TARGETING::targetService().masterProcChipTargetHandle( l_masterProc ); - l_errl = RT_TARG::getRtTarget (l_masterProc, l_procId); - if (l_errl) - { - TRACFCOMP(g_trac_pnor, "RtPnor::clearSection: getRtTarget failed"); - break; - } - // Write clear section page to PNOR for (uint64_t i = 0; i < l_size; i+=PAGESIZE) { @@ -821,7 +891,7 @@ errlHndl_t RtPnor::clearSection(PNOR::SectionId i_section) // Set ecc parameter to false to avoid double writes will only write // 4k at a time, even if the section is ecc protected. - l_errl = writeToDevice( l_procId,i_section, + l_errl = writeToDevice( iv_masterProcId, i_section, (l_address + i), l_chipSelect, false, l_buf); if (l_errl) @@ -847,4 +917,27 @@ errlHndl_t RtPnor::clearSection(PNOR::SectionId i_section) return l_errl; } +errlHndl_t RtPnor::getMasterProcId() +{ + errlHndl_t l_err = nullptr; + + do { + TARGETING::Target* l_masterProc = nullptr; + l_err = TARGETING::targetService().queryMasterProcChipTargetHandle(l_masterProc); + if (l_err) + { + TRACFCOMP(g_trac_pnor, "RtPnor::getMasterProcId: queryMasterProcChipTargetHandle failed"); + break; + } + l_err = RT_TARG::getRtTarget(l_masterProc, iv_masterProcId); + if (l_err) + { + TRACFCOMP(g_trac_pnor, "RtPnor::getMasterProcId: getRtTarget failed for master proc"); + break; + } + } while(0); + + return l_err; +} + diff --git a/src/usr/pnor/runtime/rt_pnor.H b/src/usr/pnor/runtime/rt_pnor.H index 7425adda6..61ec8a02f 100644 --- a/src/usr/pnor/runtime/rt_pnor.H +++ b/src/usr/pnor/runtime/rt_pnor.H @@ -134,7 +134,7 @@ class RtPnor uint64_t i_offset, size_t i_size, bool i_ecc, - void* o_data); + void* o_data) const; /** * @brief Write data back to the PNOR device @@ -164,6 +164,33 @@ class RtPnor */ errlHndl_t readTOC(); + // @TODO RTC:155374 Remove this in the future + /** + * @brief Check if PNOR sections appear to be secure and sets the + * internal TOC of PnorRp accordingly. + * Note: The setting of the flag is based on the Secureboot policy. + * Note: Done separately from pnor common code to prevent PNOR + * deadlock when reading section bytes. + * + * @param[in] io_TOC Pointer to internal array of section data that + * represents the TOC of pnor flash + * Asserts if nullptr + * + * @return errlHndl_t Error log if request was invalid + */ + errlHndl_t setSecure(const uint8_t* i_tocBuffer, + PNOR::SectionData_t* io_TOC) const; + + /** + * @brief Get processor id of master proc and cache in internal variable + * + * @return errlHndl_t - Error from runtime targeting call + */ + errlHndl_t getMasterProcId(); + + // Cached master Proc Id + static uint64_t iv_masterProcId; + //allow testcases to see inside the class friend class PnorRtTest; |