[Skiboot] [RFC PATCH RESEND 09/10] keystore: add opal_secboot_commit runtime service

Eric Richter erichte at linux.ibm.com
Thu Aug 2 09:40:41 AEST 2018


The opal_secboot_commit runtime service serializes an in-memory keystore
bank and writes it out to the appropriate offset in the secboot
partition.

There are three options for the section flag: the two in-memory keystore
banks ACTIVE_BANK and UPDATE_QUEUE, and a third option CLEAR_QUEUE. The
first two flags function almost the same, serialize their respective
list and write the blob to PNOR. CLEAR_QUEUE is a special case for use
after the update queue has been processed by the kernel and no longer
needed, therefore flushing the list and zeroing out the region in the
secboot partition.

This patch also introduces the secboot_serialize_and_write operation,
which takes in a keystore bank list and handles the appropriate
serialization logic. This function may be tweaked in the future to
accomodate platform specific changes. For example, p9 may implement this
function to write variables or other bits of data to the TPM, whereas
platforms with lockable flash may not need to do this.

NOTE: Right now, this is written to allow for a composite flag to allow
for multiple operations to be handled by a single Opal call, however the
call itself does not intelligently handle multiple operations -- that
is, the call will not lump the serialized blobs into a single PNOR
write. This is partially due to the nature of the secboot partition, as
this may not all be one contiguous blob

Signed-off-by: Eric Richter <erichte at linux.ibm.com>
---
 libstb/keystore.c     | 39 +++++++++++++++++++++++++++++++++++
 libstb/secboot_part.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++
 libstb/secboot_part.h |  1 +
 3 files changed, 97 insertions(+)

diff --git a/libstb/keystore.c b/libstb/keystore.c
index 0ddabf5f..1c853380 100644
--- a/libstb/keystore.c
+++ b/libstb/keystore.c
@@ -198,6 +198,45 @@ static int64_t opal_get_next_variable(uint64_t k_varname, uint64_t k_size, uint6
 opal_call(OPAL_GET_NEXT_VARIABLE, opal_get_next_variable, 3);
 
 
+// Cleanup function to empty out a bank list
+static void clear_bank_list(struct list_head *head)
+{
+	struct keystore_variable *node, *next;
+
+	list_for_each_safe(head, node, next, link) {
+		free(node->name);
+		free(node->data);
+		list_del(&node->link);
+		free(node);
+	}
+}
+
+
+static int64_t opal_secboot_commit(uint64_t section)
+{
+	int ret = OPAL_SUCCESS;
+
+	CHECK_KEYSTORE_READY;
+
+	if (section & ACTIVE_BANK) {
+		ret = secboot_part_serialize_and_write(&active_bank_list, ACTIVE_BANK);
+	}
+
+	if (section & UPDATE_QUEUE) {
+		ret = secboot_part_serialize_and_write(&update_queue_list, UPDATE_QUEUE);
+	}
+
+	if (section & CLEAR_QUEUE) {
+		ret = secboot_part_serialize_and_write(NULL, CLEAR_QUEUE);
+		// Do we want to clear the in-memory queue even if the above fails?
+		clear_bank_list(&update_queue_list);
+	}
+
+	return (ret) ? OPAL_RESOURCE : OPAL_SUCCESS;
+}
+opal_call(OPAL_SECBOOT_COMMIT, opal_secboot_commit, 1);
+
+
 int keystore_init(void)
 {
 	int rc;
diff --git a/libstb/secboot_part.c b/libstb/secboot_part.c
index 9a2c8ac0..81b359bf 100644
--- a/libstb/secboot_part.c
+++ b/libstb/secboot_part.c
@@ -231,6 +231,63 @@ int secboot_part_build_keystore(struct list_head *active, struct list_head *uque
 }
 
 
+static int write_variable(char *target, struct keystore_variable *var)
+{
+	char *cur = target;
+
+	prlog(PR_INFO, "Writing variable '%s'\n", var->name);
+
+	*((uint64_t*) cur) = var->name_size; cur += sizeof(uint64_t);
+	*((uint64_t*) cur) = var->data_size; cur += sizeof(uint64_t);
+	memcpy(cur, var->name, var->name_size);
+	cur += var->name_size;
+	memcpy(cur, var->data, var->data_size);
+	cur += var->data_size;
+
+	return cur - target;
+}
+
+
+int secboot_part_serialize_and_write(struct list_head *head, int section)
+{
+	struct keystore_variable *var;
+	char *cur = NULL, *end = NULL;
+
+	switch(section) {
+		case ACTIVE_BANK:
+			cur = (char*) active_bank->item;
+			end = ((char*) active_bank) + SECBOOT_BANK_SIZE;
+			break;
+		case UPDATE_QUEUE:
+			cur = (char*) update_queue->item;
+			end = ((char*) update_queue) + SECBOOT_QUEUE_SIZE;;
+			break;
+
+		case CLEAR_QUEUE:
+			memset(update_queue->item, 0x00, SECBOOT_QUEUE_SIZE - sizeof(struct secboot_section)); // header?
+			goto out; // Skip the serialization of variables
+
+		default: return -1;
+	}
+
+	if (!head) return -1; // head should not be NULL with section != CLEAR_QUEUE
+
+	prlog(PR_INFO, "cur = %p\n", cur);
+	list_for_each(head, var, link) {
+		cur += write_variable(cur, var);
+	}
+	prlog(PR_INFO, "cur = %p\n", cur);
+
+	memset(cur, 0x00, end-cur); // Clear the rest of the bank
+
+out:
+	prlog(PR_INFO,"performing write\n");
+	platform.secboot_write(0, secboot, secboot_size);
+
+	return 0;
+}
+
+
 int secboot_part_init()
 {
 	int rc;
diff --git a/libstb/secboot_part.h b/libstb/secboot_part.h
index 66e71561..a853f8c6 100644
--- a/libstb/secboot_part.h
+++ b/libstb/secboot_part.h
@@ -19,5 +19,6 @@
 
 int secboot_part_init(void);
 int secboot_part_build_keystore(struct list_head* active, struct list_head* uqueue);
+int secboot_part_serialize_and_write(struct list_head *head, int section);
 
 #endif /* __SECBOOT_PART_H */
-- 
2.14.4



More information about the Skiboot mailing list