diff options
-rw-r--r-- | src/include/usr/runtime/runtime.H | 13 | ||||
-rw-r--r-- | src/include/usr/runtime/runtime_reasoncodes.H | 3 | ||||
-rw-r--r-- | src/include/usr/targeting/attrrp.H | 16 | ||||
-rw-r--r-- | src/include/usr/targeting/common/target.H | 11 | ||||
-rw-r--r-- | src/usr/isteps/istep21/call_host_runtime_setup.C | 8 | ||||
-rw-r--r-- | src/usr/runtime/populate_hbruntime.C | 91 | ||||
-rwxr-xr-x | src/usr/targeting/attrrp.C | 111 | ||||
-rwxr-xr-x | src/usr/targeting/common/xmltohb/xmltohb.pl | 26 |
8 files changed, 250 insertions, 29 deletions
diff --git a/src/include/usr/runtime/runtime.H b/src/include/usr/runtime/runtime.H index df22c23e5..7a51984c8 100644 --- a/src/include/usr/runtime/runtime.H +++ b/src/include/usr/runtime/runtime.H @@ -71,6 +71,19 @@ errlHndl_t load_host_data( void ); errlHndl_t populate_hbRuntimeData( void ); /** + * @brief persistent read/write Attribute validity runtime check + * + * @description In order to ensure validity of persistent read/write + * attributes, perform a check of enum values and integer ranges + * to ensure validity, while pinning attribute memory to ensure + * that PNOR cannot change the attributes prior to the copy to + * reserve memory. + * + * @return errlHndl_t nullptr on Success else pointer to error log + */ +errlHndl_t persistent_rwAttrRuntimeCheck( void ); + +/** * @brief Populate HB secureboot data in mainstore * * @description Populates the System Parameters section of HDAT with diff --git a/src/include/usr/runtime/runtime_reasoncodes.H b/src/include/usr/runtime/runtime_reasoncodes.H index d5af4f2a6..c36b9415d 100644 --- a/src/include/usr/runtime/runtime_reasoncodes.H +++ b/src/include/usr/runtime/runtime_reasoncodes.H @@ -56,6 +56,7 @@ namespace RUNTIME MOD_UNMAP_VIRT_ADDR = 0x18, /**< populate_hbruntime.C */ MOD_POPULATE_TPMINFOBYNODE = 0x19, /**< populate_hbruntime.C */ MOD_FILL_RSVMEM_HBDATA = 0x20, /**< populate_hbruntime.C */ + MOD_ATTR_RUNTIME_CHECK_PREP_FAIL = 0x21, /**< populate_hbruntime.C */ }; enum RuntimeReasonCode @@ -100,6 +101,8 @@ namespace RUNTIME RC_EXTRA_I2C_DEVICE_IN_MRW = RUNTIME_COMP_ID | 0x25, RC_GETTUPLE_UNSUPPORTED = RUNTIME_COMP_ID | 0x26, RC_EXCEEDED_MEMORY = RUNTIME_COMP_ID | 0x27, + RC_UNABLE_TO_PIN_ATTR_MEM = RUNTIME_COMP_ID | 0x28, + RC_UNABLE_TO_UNPIN_ATTR_MEM = RUNTIME_COMP_ID | 0x29, }; enum UserDetailsTypes diff --git a/src/include/usr/targeting/attrrp.H b/src/include/usr/targeting/attrrp.H index 7e0006bd2..1453d0273 100644 --- a/src/include/usr/targeting/attrrp.H +++ b/src/include/usr/targeting/attrrp.H @@ -394,6 +394,22 @@ class AttrRP */ TARG_DECLARE_SINGLETON(TARGETING::AttrRP,theAttrRP); +extern const char* ATTRRP_MSG_Q; + +// user-defined message subtype for MSG_MM_RP_RUNTIME_PREP +/** @enum msg_mm_rp_runtime_prep_t + * @brief Message type and subtypes for the MSG_MM_RP_RUNTIME_PREP message + */ +enum msg_mm_rp_runtime_prep_t +{ + MSG_MM_RP_RUNTIME_PREP = 0x2, // prepare runtime for secure transition + // of attrs + // data[0] = MSG_MM_RP_RUNTIME_PREP_BEGIN or + // data[0] = MSG_MM_RP_RUNTIME_PREP_END + MSG_MM_RP_RUNTIME_PREP_BEGIN, + MSG_MM_RP_RUNTIME_PREP_END, +}; + } // End namespace TARGETING #endif // __TARGETING_ATTRRP_H diff --git a/src/include/usr/targeting/common/target.H b/src/include/usr/targeting/common/target.H index 0681da27f..f9ba6c346 100644 --- a/src/include/usr/targeting/common/target.H +++ b/src/include/usr/targeting/common/target.H @@ -787,6 +787,17 @@ void handleRangeCheckFailure(const Target* i_pTarget, const ATTRIBUTE_ID i_attr, const uint64_t i_outOfRangeValue); +// Function to handle validation of all persistent r/w attributes for runtime +/** + * @brief Attempts to get all persistent r/w attributes for a given target. + * Those that are non-present for that target are skipped. All others + * are checked for valid enum values and ranges. + * + * @param[in] i_pTarget The target for which all attributes will be checked. + * Cannot be nullptr. + */ +void validateAllRwNvAttr(const Target* i_pTarget); + // The following #include ensures that persistent read/write attributes are // value-checked for validity upon calling getAttr. This is done via diff --git a/src/usr/isteps/istep21/call_host_runtime_setup.C b/src/usr/isteps/istep21/call_host_runtime_setup.C index 774d1ac3f..dcad3c89b 100644 --- a/src/usr/isteps/istep21/call_host_runtime_setup.C +++ b/src/usr/isteps/istep21/call_host_runtime_setup.C @@ -189,6 +189,14 @@ void* call_host_runtime_setup (void *io_pArgs) } } + l_err = RUNTIME::persistent_rwAttrRuntimeCheck(); + if ( l_err ) + { + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, + "Failed persistent_rwAttrRuntimeCheck()" ); + break; + } + // Fill in Hostboot runtime data for all nodes // (adjunct partition) // Write the HB runtime data into mainstore diff --git a/src/usr/runtime/populate_hbruntime.C b/src/usr/runtime/populate_hbruntime.C index f5310d1a1..bc2915ddd 100644 --- a/src/usr/runtime/populate_hbruntime.C +++ b/src/usr/runtime/populate_hbruntime.C @@ -1838,5 +1838,96 @@ errlHndl_t populate_hbRuntimeData( void ) } // end populate_hbRuntimeData +errlHndl_t persistent_rwAttrRuntimeCheck( void ) +{ + errlHndl_t l_err = nullptr; + // For security purposes make R/W attribute memory pages non-ejectable + // and of these, verify the persistent attributes. If all goes well, + // we can hand these over to runtime with added confidence of their + // validity, otherwise we stop the IPL. + msg_q_t l_msgQ = msg_q_resolve(TARGETING::ATTRRP_MSG_Q); + + assert(l_msgQ != nullptr, "Bug! Message queue did not resolve properly!"); + + msg_t* l_msg = msg_allocate(); + + assert(l_msg != nullptr, "Bug! Message allocation failed!"); + + l_msg->type = TARGETING::MSG_MM_RP_RUNTIME_PREP; + + l_msg->data[0] = TARGETING::MSG_MM_RP_RUNTIME_PREP_BEGIN; + + int rc = msg_sendrecv(l_msgQ, l_msg); + + if (rc != 0 || l_msg->data[1]) + { + uint64_t l_rc = l_msg->data[1]; + + TRACFCOMP( g_trac_runtime, + "persistent_rwAttrRuntimeCheck: failed to pin attribute memory. " + "Message rc: %llX msg_sendrecv rc:%i", l_rc, rc); + + /*@ + * @errortype + * @reasoncode RUNTIME::RC_UNABLE_TO_PIN_ATTR_MEM + * @moduleid RUNTIME::MOD_ATTR_RUNTIME_CHECK_PREP_FAIL + * @userdata1 Message return code from message handler + * @userdata2 Return code from msg_sendrecv function + * @devdesc Unable to pin read/write attribute memory + * @custdesc Internal system error occured + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, + RUNTIME::MOD_ATTR_RUNTIME_CHECK_PREP_FAIL, + RUNTIME::RC_UNABLE_TO_PIN_ATTR_MEM, + l_rc, + rc, + true /* Add HB Software Callout */); + } + else + { + TARGETING::TargetRangeFilter targets( + TARGETING::targetService().begin(), + TARGETING::targetService().end()); + for ( ; targets; ++targets) + { + validateAllRwNvAttr( *targets ); + } + + l_msg->type = TARGETING::MSG_MM_RP_RUNTIME_PREP; + l_msg->data[0] = TARGETING::MSG_MM_RP_RUNTIME_PREP_END; + + int rc = msg_sendrecv(l_msgQ, l_msg); + + if (rc != 0 || l_msg->data[1]) + { + uint64_t l_rc = l_msg->data[1]; + + TRACFCOMP( g_trac_runtime, "persistent_rwAttrRuntimeCheck:" + " failed to unpin attribute memory. " + "Message rc: %llX msg_sendrecv rc:%i", l_rc, rc); + + /*@ + * @errortype + * @reasoncode RUNTIME::RC_UNABLE_TO_UNPIN_ATTR_MEM + * @moduleid RUNTIME::MOD_ATTR_RUNTIME_CHECK_PREP_FAIL + * @userdata1 Message return code from message handler + * @userdata2 Return code from msg_sendrecv function + * @devdesc Unable to unpin read/write attribute memory + * @custdesc Internal system error occured + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, + RUNTIME::MOD_ATTR_RUNTIME_CHECK_PREP_FAIL, + RUNTIME::RC_UNABLE_TO_UNPIN_ATTR_MEM, + l_rc, + rc, + true /* Add HB Software Callout */); + } + } + + return l_err; +} // end persistent_rwAttrRuntimeCheck + } //namespace RUNTIME diff --git a/src/usr/targeting/attrrp.C b/src/usr/targeting/attrrp.C index 1ab96e6ea..66be9a33f 100755 --- a/src/usr/targeting/attrrp.C +++ b/src/usr/targeting/attrrp.C @@ -60,6 +60,9 @@ using namespace ERRORLOG; namespace TARGETING { + + const char* ATTRRP_MSG_Q = "attrrpq"; + void* AttrRP::getBaseAddress(const NODE_ID i_nodeIdUnused) { return reinterpret_cast<void*>(VMM_VADDR_ATTR_RP); @@ -130,39 +133,52 @@ namespace TARGETING if (!msg) continue; // Parse message data members. - uint64_t vAddr = msg->data[0]; - void* pAddr = reinterpret_cast<void*>(msg->data[1]); + uint64_t vAddr = 0; + void* pAddr = nullptr; + ssize_t section = -1; + uint64_t offset = 0; + uint64_t size = 0; TRACFCOMP(g_trac_targeting, INFO_MRK "AttrRP: Message recv'd: " - "0x%x, 0x%lx 0x%p", msg->type, vAddr, pAddr); + "0x%x"); - // Locate corresponding attribute section for message. - ssize_t section = -1; - for (size_t i = 0; i < iv_sectionCount; ++i) - { - if ((vAddr >= iv_sections[i].vmmAddress) && - (vAddr < iv_sections[i].vmmAddress + iv_sections[i].size)) + do { + + if (msg->type != MSG_MM_RP_RUNTIME_PREP) { - section = i; - break; - } - } + vAddr = msg->data[0]; + pAddr = reinterpret_cast<void*>(msg->data[1]); - // Return EINVAL if no section was found. Kernel bug? - if (section == -1) - { - rc = -EINVAL; - TRACFCOMP(g_trac_targeting, - ERR_MRK "AttrRP: Address given outside section " - "ranges: %p", - vAddr); - } - else // Process request. - { + TRACFCOMP(g_trac_targeting, + INFO_MRK "AttrRP: vAddr=0x%lx pAddr=0x%p", + msg->type, vAddr, pAddr); + + // Locate corresponding attribute section for message. + for (size_t i = 0; i < iv_sectionCount; ++i) + { + if ((vAddr >= iv_sections[i].vmmAddress) && + (vAddr < iv_sections[i].vmmAddress + + iv_sections[i].size)) + { + section = i; + break; + } + } + + // Return EINVAL if no section was found. Kernel bug? + if (section == -1) + { + rc = -EINVAL; + TRACFCOMP(g_trac_targeting, + ERR_MRK "AttrRP: Address given outside section " + "ranges: %p", + vAddr); + break; // go to error handler + } - // Determine PNOR offset and page size. - uint64_t offset = vAddr - iv_sections[section].vmmAddress; - uint64_t size = std::min(PAGE_SIZE, + // Determine PNOR offset and page size. + offset = vAddr - iv_sections[section].vmmAddress; + size = std::min(PAGE_SIZE, iv_sections[section].vmmAddress + iv_sections[section].size - vAddr); @@ -174,6 +190,10 @@ namespace TARGETING // we should only operate on 2k of content. + } + + // Process request. + // Read / Write message behavior. switch(msg->type) { @@ -229,7 +249,33 @@ namespace TARGETING pAddr, size); break; + case MSG_MM_RP_RUNTIME_PREP: + { + // used for security purposes to pin all the attribute + // memory just prior to copying to reserve memory + uint64_t l_access = + msg->data[0] == MSG_MM_RP_RUNTIME_PREP_BEGIN? + WRITABLE: + msg->data[0] == MSG_MM_RP_RUNTIME_PREP_END? + WRITE_TRACKED: 0; + if (!l_access) + { + rc = -EINVAL; + break; + } + for (size_t i = 0; i < iv_sectionCount; ++i) + { + if ( iv_sections[i].type == SECTION_TYPE_PNOR_RW) + { + rc = mm_set_permission(reinterpret_cast<void*>( + iv_sections[i].vmmAddress), + iv_sections[i].size, + l_access); + } + } + break; + } default: TRACFCOMP(g_trac_targeting, ERR_MRK "AttrRP: Unhandled command type %d.", @@ -237,7 +283,8 @@ namespace TARGETING rc = -EINVAL; break; } - } + + } while (0); // Log an error log if the AttrRP was unable to handle a message // for any reason. @@ -272,7 +319,7 @@ namespace TARGETING errlCommit(l_errl,TARG_COMP_ID); } - // Respond to kernel request. + // Respond to request. msg->data[1] = rc; rc = msg_respond(iv_msgQ, msg); if (rc) @@ -566,6 +613,12 @@ namespace TARGETING // Allocate message queue for VMM requests. iv_msgQ = msg_q_create(); + // register it so it can be discovered by istep 21 and thus allow + // secure runtime preparation of persistent r/w attributes + int rc = msg_q_register(iv_msgQ, ATTRRP_MSG_Q); + + assert(rc == 0, "Bug! Unable to register message queue"); + // Create VMM block for each section, assign permissions. for (size_t i = 0; i < iv_sectionCount; ++i) { diff --git a/src/usr/targeting/common/xmltohb/xmltohb.pl b/src/usr/targeting/common/xmltohb/xmltohb.pl index ef60f0b69..de26c5338 100755 --- a/src/usr/targeting/common/xmltohb/xmltohb.pl +++ b/src/usr/targeting/common/xmltohb/xmltohb.pl @@ -770,6 +770,32 @@ foreach my $attr (@rwPersistAttrs) } } print $rwAttrCFile <<VERBATIM; +void validateAllRwNvAttr(const Target* i_pTarget) +{ +VERBATIM +foreach my $attr (@rwPersistAttrs) +{ + if (exists $attr->{simpleType} && + exists $attr->{simpleType}->{enumeration}) + { + my $lowerCaseValue = lc "o_$attr->{id}_value"; + print $rwAttrCFile "" + . " AttributeTraits<ATTR_$attr->{id}>::Type $lowerCaseValue;\n" + . " i_pTarget->tryGetAttr<ATTR_$attr->{id}>($lowerCaseValue);\n\n"; + } +} +foreach my $attr (@rwPersistAttrs) +{ + if (exists $attr->{range}) + { + my $lowerCaseValue = lc "o_$attr->{id}_value"; + print $rwAttrCFile "" + . " AttributeTraits<ATTR_$attr->{id}>::Type $lowerCaseValue;\n" + . " i_pTarget->tryGetAttr<ATTR_$attr->{id}>($lowerCaseValue);\n\n"; + } +} +print $rwAttrCFile <<VERBATIM; +} #endif // !__HOSTBOOT_RUNTIME &&__HOSTBOOT_MODULE } // namespace TARGETING |