[PATCH 8/9] sandbox: tpm: Support storing device state in tpm2

Simon Glass sjg at chromium.org
Mon Jul 5 17:48:48 CEST 2021


At present the tpm2 emulator does not support storing the device state.
Add this so we can handle the normal vboot flow through the sandbox
executables (VPL->SPL etc.) with the TPM contents staying in place.

Note: sandbox has not yet been converted to use livetree for the state
information, since livetree does not yet support writing to the tree.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

 drivers/tpm/tpm2_tis_sandbox.c | 139 +++++++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)

diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c
index 1d38a79a867..ed9c9a0bc9f 100644
--- a/drivers/tpm/tpm2_tis_sandbox.c
+++ b/drivers/tpm/tpm2_tis_sandbox.c
@@ -79,6 +79,145 @@ struct sandbox_tpm2 {
 
 static struct sandbox_tpm2 s_state, *g_state;
 
+/**
+ * sandbox_tpm2_read_state() - read the sandbox EC state from the state file
+ *
+ * If data is available, then blob and node will provide access to it. If
+ * not this function sets up an empty TPM.
+ *
+ * @blob: Pointer to device tree blob, or NULL if no data to read
+ * @node: Node offset to read from
+ */
+static int sandbox_tpm2_read_state(const void *blob, int node)
+{
+	struct sandbox_tpm2 *state = &s_state;
+	char prop_name[20];
+	const char *prop;
+	int len;
+	int i;
+
+	if (!blob)
+		return 0;
+	state->tests_done = fdtdec_get_int(blob, node, "tests-done", 0);
+
+	for (i = 0; i < TPM2_HIERARCHY_NB; i++) {
+		snprintf(prop_name, sizeof(prop_name), "pw%d", i);
+
+		prop = fdt_getprop(blob, node, prop_name, &len);
+		if (len > TPM2_DIGEST_LEN)
+			return log_msg_ret("pw", -E2BIG);
+		if (prop) {
+			memcpy(state->pw[i], prop, len);
+			state->pw_sz[i] = len;
+		}
+	}
+
+	for (i = 0; i < TPM2_PROPERTY_NB; i++) {
+		snprintf(prop_name, sizeof(prop_name), "properties%d", i);
+		state->properties[i] = fdtdec_get_uint(blob, node, prop_name,
+						       0);
+	}
+
+	for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) {
+		int subnode;
+
+		snprintf(prop_name, sizeof(prop_name), "pcr%d", i);
+		subnode = fdt_subnode_offset(blob, node, prop_name);
+		if (subnode < 0)
+			continue;
+		prop = fdt_getprop(blob, subnode, "value", &len);
+		if (len != TPM2_DIGEST_LEN)
+			return log_msg_ret("pcr", -E2BIG);
+		memcpy(state->pcr[i], prop, TPM2_DIGEST_LEN);
+		state->pcr_extensions[i] = fdtdec_get_uint(blob, subnode,
+							   "extensions", 0);
+	}
+
+	for (i = 0; i < NV_SEQ_COUNT; i++) {
+		struct nvdata_state *nvd = &state->nvdata[i];
+
+		sprintf(prop_name, "nvdata%d", i);
+		prop = fdt_getprop(blob, node, prop_name, &len);
+		if (len > NV_DATA_SIZE)
+			return log_msg_ret("nvd", -E2BIG);
+		if (prop) {
+			memcpy(nvd->data, prop, len);
+			nvd->length = len;
+			nvd->present = true;
+		}
+	}
+	s_state.valid = true;
+
+	return 0;
+}
+
+/**
+ * sandbox_tpm2_write_state() - Write out our state to the state file
+ *
+ * The caller will ensure that there is a node ready for the state. The node
+ * may already contain the old state, in which case it is overridden.
+ *
+ * @blob: Device tree blob holding state
+ * @node: Node to write our state into
+ */
+static int sandbox_tpm2_write_state(void *blob, int node)
+{
+	const struct sandbox_tpm2 *state = g_state;
+	char prop_name[20];
+	int i;
+
+	if (!state)
+		return 0;
+
+	/*
+	 * We are guaranteed enough space to write basic properties. This is
+	 * SANDBOX_STATE_MIN_SPACE.
+	 *
+	 * We could use fdt_add_subnode() to put each set of data in its
+	 * own node - perhaps useful if we add access information to each.
+	 */
+	fdt_setprop_u32(blob, node, "tests-done", state->tests_done);
+
+	for (i = 0; i < TPM2_HIERARCHY_NB; i++) {
+		if (state->pw_sz[i]) {
+			snprintf(prop_name, sizeof(prop_name), "pw%d", i);
+			fdt_setprop(blob, node, prop_name, state->pw[i],
+				    state->pw_sz[i]);
+		}
+	}
+
+	for (i = 0; i < TPM2_PROPERTY_NB; i++) {
+		snprintf(prop_name, sizeof(prop_name), "properties%d", i);
+		fdt_setprop_u32(blob, node, prop_name, state->properties[i]);
+	}
+
+	for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) {
+		int subnode;
+
+		snprintf(prop_name, sizeof(prop_name), "pcr%d", i);
+		subnode = fdt_add_subnode(blob, node, prop_name);
+		fdt_setprop(blob, subnode, "value", state->pcr[i],
+			    TPM2_DIGEST_LEN);
+		fdt_setprop_u32(blob, subnode, "extensions",
+				state->pcr_extensions[i]);
+	}
+
+	for (i = 0; i < NV_SEQ_COUNT; i++) {
+		const struct nvdata_state *nvd = &state->nvdata[i];
+
+		if (nvd->present) {
+			snprintf(prop_name, sizeof(prop_name), "nvdata%d", i);
+			fdt_setprop(blob, node, prop_name, nvd->data,
+				    nvd->length);
+		}
+	}
+
+	return 0;
+}
+
+SANDBOX_STATE_IO(sandbox_tpm2, "sandbox,tpm2", sandbox_tpm2_read_state,
+		 sandbox_tpm2_write_state);
+
 /*
  * Check the tag validity depending on the command (authentication required or
  * not). If authentication is required, check it is valid. Update the auth
-- 
2.32.0.93.g670b81a890-goog



More information about the U-Boot mailing list