[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