summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/usr/runtime/runtime.H13
-rw-r--r--src/include/usr/runtime/runtime_reasoncodes.H3
-rw-r--r--src/include/usr/targeting/attrrp.H16
-rw-r--r--src/include/usr/targeting/common/target.H11
-rw-r--r--src/usr/isteps/istep21/call_host_runtime_setup.C8
-rw-r--r--src/usr/runtime/populate_hbruntime.C91
-rwxr-xr-xsrc/usr/targeting/attrrp.C111
-rwxr-xr-xsrc/usr/targeting/common/xmltohb/xmltohb.pl26
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
OpenPOWER on IntegriCloud