[Skiboot] [PATCH v6 14/20] secvar/storage/fakenv: add fake tpm operations for testing

Eric Richter erichte at linux.ibm.com
Thu Sep 17 02:21:25 AEST 2020


The secboot_tpm storage driver heavily relies on the TPM to ensure data
integrity, which makes it difficult to test in userspace or on hardware
without a TPM.

This patch adds a bunch of functions that implement the tssskiboot
interface, and simulates the expected TPM behavior utilizing PNOR space
instead.

THIS IS NOT INTENDED FOR PRODUCTION USE.

Signed-off-by: Eric Richter <erichte at linux.ibm.com>
---
 libstb/secvar/storage/Makefile.inc |   3 +
 libstb/secvar/storage/fakenv_ops.c | 175 +++++++++++++++++++++++++++++
 2 files changed, 178 insertions(+)
 create mode 100644 libstb/secvar/storage/fakenv_ops.c

diff --git a/libstb/secvar/storage/Makefile.inc b/libstb/secvar/storage/Makefile.inc
index 35fba723..99f7b073 100644
--- a/libstb/secvar/storage/Makefile.inc
+++ b/libstb/secvar/storage/Makefile.inc
@@ -5,8 +5,11 @@ SECVAR_STORAGE_DIR = $(SRC)/libstb/secvar/storage
 
 SUBDIRS += $(SECVAR_STORAGE_DIR)
 
+# Swap the comment on these two lines to use the fake TPM NV
+# implementation hardware without a TPM
 SECVAR_STORAGE_SRCS = secboot_tpm.c tpmnv_ops.c
 #SECVAR_STORAGE_SRCS = secboot_tpm.c fakenv_ops.c
+
 SECVAR_STORAGE_OBJS = $(SECVAR_STORAGE_SRCS:%.c=%.o)
 SECVAR_STORAGE = $(SECVAR_STORAGE_DIR)/built-in.a
 
diff --git a/libstb/secvar/storage/fakenv_ops.c b/libstb/secvar/storage/fakenv_ops.c
new file mode 100644
index 00000000..64d5d51e
--- /dev/null
+++ b/libstb/secvar/storage/fakenv_ops.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2020 IBM Corp. */
+#include <skiboot.h>
+#include "secboot_tpm.h"
+
+/* Offset into the SECBOOT PNOR partition to write "TPMNV" data */
+static size_t fakenv_offset = sizeof(struct secboot);
+
+struct fake_tpmnv {
+	struct {
+		struct secboot_header header;
+		char vars[1024]; // Hardcode the size to 1024 for now
+	} vars;
+	struct tpmnv_control control;
+	int defined[2];
+} __attribute__((packed));
+
+static struct fake_tpmnv fakenv = {0};
+static int tpm_ready = 0;
+
+
+static inline void *nv_index_address(int index)
+{
+	switch (index) {
+	case SECBOOT_TPMNV_VARS_INDEX:
+		return &fakenv.vars;
+	case SECBOOT_TPMNV_CONTROL_INDEX:
+		return &fakenv.control;
+	default:
+		return 0;
+	}
+}
+
+
+static int tpm_init(void)
+{
+	int rc;
+
+	if (tpm_ready)
+		return 0;
+
+	rc = flash_secboot_read(&fakenv, fakenv_offset, sizeof(struct fake_tpmnv));
+	if (rc)
+		return rc;
+
+	tpm_ready = 1;
+
+	return 0;
+}
+
+static int fakenv_read(TPMI_RH_NV_INDEX nvIndex, void *buf,
+		       size_t bufsize,  uint16_t off)
+{
+	if (tpm_init())
+		return OPAL_INTERNAL_ERROR;
+
+	memcpy(buf, nv_index_address(nvIndex) + off, bufsize);
+
+	return 0;
+}
+
+static int fakenv_write(TPMI_RH_NV_INDEX nvIndex, void *buf,
+			size_t bufsize, uint16_t off)
+{
+	if (tpm_init())
+		return OPAL_INTERNAL_ERROR;
+
+	memcpy(nv_index_address(nvIndex) + off, buf, bufsize);
+
+	/* Just write the whole NV struct for now */
+	return flash_secboot_write(fakenv_offset, &fakenv, sizeof(struct fake_tpmnv));
+}
+
+static int fakenv_definespace(TPMI_RH_NV_INDEX nvIndex, uint16_t dataSize)
+{
+	if (tpm_init())
+		return OPAL_INTERNAL_ERROR;
+
+	(void) dataSize;
+
+	switch (nvIndex) {
+	case SECBOOT_TPMNV_VARS_INDEX:
+		fakenv.defined[0] = 1;
+		return 0;
+	case SECBOOT_TPMNV_CONTROL_INDEX:
+		fakenv.defined[1] = 1;
+		return 0;
+	}
+
+	return OPAL_INTERNAL_ERROR;
+}
+
+static int fakenv_writelock(TPMI_RH_NV_INDEX nvIndex)
+{
+	if (tpm_init())
+		return OPAL_INTERNAL_ERROR;
+
+	(void) nvIndex;
+
+	return 0;
+}
+
+static int fakenv_get_defined_indices(TPMI_RH_NV_INDEX **indices, size_t *count)
+{
+	if (tpm_init())
+		return OPAL_INTERNAL_ERROR;
+
+	*indices = zalloc(sizeof(fakenv.defined));
+	if (*indices == NULL)
+		return OPAL_NO_MEM;
+
+	*count = 0;
+
+	if (fakenv.defined[0]) {
+		*indices[0] = SECBOOT_TPMNV_VARS_INDEX;
+		(*count)++;
+	}
+	if (fakenv.defined[1]) {
+		*indices[1] = SECBOOT_TPMNV_CONTROL_INDEX;
+		(*count)++;
+	}
+
+	return 0;
+}
+
+static int fakenv_undefinespace(TPMI_RH_NV_INDEX index)
+{
+	if (tpm_init())
+		return OPAL_INTERNAL_ERROR;
+
+	switch (index) {
+	case SECBOOT_TPMNV_VARS_INDEX:
+		fakenv.defined[0] = 0;
+		memset(&fakenv.vars, 0, sizeof(fakenv.vars));
+		return 0;
+	case SECBOOT_TPMNV_CONTROL_INDEX:
+		fakenv.defined[1] = 0;
+		memset(&fakenv.control, 0, sizeof(fakenv.control));
+		return 0;
+	}
+
+	return -1;
+}
+
+static int fakenv_readpublic(TPMI_RH_NV_INDEX index, TPMS_NV_PUBLIC *nv_public,
+			     TPM2B_NAME *nv_name)
+{
+	if (tpm_init())
+		return OPAL_INTERNAL_ERROR;
+
+	(void) nv_public;
+
+	switch (index) {
+	case SECBOOT_TPMNV_VARS_INDEX:
+		memcpy(&nv_name->t.name, tpmnv_vars_name, sizeof(TPM2B_NAME));
+		break;
+	case SECBOOT_TPMNV_CONTROL_INDEX:
+		memcpy(&nv_name->t.name, tpmnv_control_name, sizeof(TPM2B_NAME));
+		break;
+	default:
+		return OPAL_INTERNAL_ERROR;
+	}
+
+	return 0;
+}
+
+struct tpmnv_ops_s tpmnv_ops = {
+	.read = fakenv_read,
+	.write = fakenv_write,
+	.writelock = fakenv_writelock,
+	.definespace = fakenv_definespace,
+	.getindices = fakenv_get_defined_indices,
+	.undefinespace = fakenv_undefinespace,
+	.readpublic = fakenv_readpublic,
+};
-- 
2.21.1



More information about the Skiboot mailing list