[PATCH 2/8] drivers: rollback: Add TPM2 implementation of rollback devices

seanedmond at linux.microsoft.com seanedmond at linux.microsoft.com
Tue Sep 12 11:47:25 CEST 2023


From: Stephen Carlson <stcarlso at linux.microsoft.com>

This implementation of the rollback uclass driver allows existing TPM2
devices declared in the device tree to be referenced for storing the OS
anti-rollback counter, using the TPM2 non-volatile storage API.  The
rollback device must be a child of the TPM device.  For example:

	tpm2 {
		compatible = "sandbox,tpm2";

		rollback at 1 {
			compatible = "tpm,rollback";
			rollback-nv-index = <0x1001007>;
		};
	};

Signed-off-by: Stephen Carlson <stcarlso at linux.microsoft.com>
Signed-off-by: Sean Edmond <seanedmond at microsoft.com>
---
 MAINTAINERS                     |   1 +
 drivers/rollback/Makefile       |   1 +
 drivers/rollback/rollback-tpm.c | 117 ++++++++++++++++++++++++++++++++
 include/tpm-v2.h                |  17 +++++
 lib/tpm-v2.c                    |  48 +++++++++++++
 5 files changed, 184 insertions(+)
 create mode 100644 drivers/rollback/rollback-tpm.c

diff --git a/MAINTAINERS b/MAINTAINERS
index de14724c27..e5ac889db4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1446,6 +1446,7 @@ F:	drivers/rollback/Kconfig
 F:	drivers/rollback/Makefile
 F:	drivers/rollback/rollback-sandbox.c
 F:	drivers/rollback/rollback-uclass.c
+F:	drivers/security/rollback-tpm.c
 
 SEMIHOSTING
 R:	Sean Anderson <sean.anderson at seco.com>
diff --git a/drivers/rollback/Makefile b/drivers/rollback/Makefile
index 4e7fa46041..63c08863ca 100644
--- a/drivers/rollback/Makefile
+++ b/drivers/rollback/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_DM_ROLLBACK) += rollback-uclass.o
 obj-$(CONFIG_ROLLBACK_SANDBOX) += rollback-sandbox.o
+obj-$(CONFIG_ROLLBACK_TPM) += rollback-tpm.o
\ No newline at end of file
diff --git a/drivers/rollback/rollback-tpm.c b/drivers/rollback/rollback-tpm.c
new file mode 100644
index 0000000000..3bb6214042
--- /dev/null
+++ b/drivers/rollback/rollback-tpm.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Microsoft, Inc
+ * Written by Stephen Carlson <stcarlso at microsoft.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <rollback.h>
+#include <tpm_api.h>
+
+struct rollback_state {
+	u32 nv_index;
+	struct udevice *tpm_dev;
+};
+
+static int tpm_rollback_idx_get(struct udevice *dev, u64 *rollback_idx)
+{
+	struct rollback_state *priv = dev_get_priv(dev);
+	int ret;
+
+	if (!rollback_idx)
+		return -EINVAL;
+
+	ret = tpm2_nv_read_value(priv->tpm_dev, priv->nv_index, rollback_idx, sizeof(u64));
+	if (ret) {
+		log(UCLASS_ROLLBACK, LOGL_ERR,
+		    "Unable to read rollback number from TPM (ret=%d)\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int tpm_rollback_idx_set(struct udevice *dev, u64 rollback_idx)
+{
+	int ret;
+	struct rollback_state *priv = dev_get_priv(dev);
+
+	ret = tpm2_nv_write_value(priv->tpm_dev, priv->nv_index, &rollback_idx, sizeof(u64));
+	if (ret) {
+		log(UCLASS_ROLLBACK, LOGL_ERR,
+		    "Unable to write anti-rollback version to TPM (ret=%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct rollback_ops tpm_rollback_ops = {
+	.rollback_idx_get		= tpm_rollback_idx_get,
+	.rollback_idx_set		= tpm_rollback_idx_set,
+};
+
+static int tpm_rollback_probe(struct udevice *dev)
+{
+	struct rollback_state *priv = dev_get_priv(dev);
+	int ret;
+
+	/* initialize the TPM rollback counter NV index
+	 * and initial to 0.  Note, this driver provides
+	 * a NULL policy.
+	 */
+	ret = tpm_rollback_counter_init(priv->tpm_dev, priv->nv_index,
+					NULL, 0);
+	if (ret) {
+		log(UCLASS_ROLLBACK, LOGL_ERR,
+		    "TPM rollback init failed (ret=%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tpm_rollback_remove(struct udevice *dev)
+{
+	struct rollback_state *priv = dev_get_priv(dev);
+
+	return tpm_close(priv->tpm_dev);
+}
+
+static int tpm_rollback_ofdata_to_platdata(struct udevice *dev)
+{
+	struct udevice *parent_dev;
+	struct rollback_state *priv = dev_get_priv(dev);
+
+	priv->nv_index = (u32)dev_read_u32_default(dev, "rollback-nv-index", 0);
+
+	parent_dev = dev_get_parent(dev);
+
+	if (parent_dev->driver->id == UCLASS_TPM) {
+		priv->tpm_dev = parent_dev;
+	} else {
+		log(UCLASS_ROLLBACK, LOGL_ERR,
+		    "TPM rollback must be a child node of a TPM\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id tpm_rollback_ids[] = {
+	{ .compatible = "tpm,rollback" },
+	{ }
+};
+
+U_BOOT_DRIVER(rollback_tpm) = {
+	.name	= "rollback_tpm",
+	.id	= UCLASS_ROLLBACK,
+	.priv_auto = sizeof(struct rollback_state),
+	.of_match = tpm_rollback_ids,
+	.of_to_plat = tpm_rollback_ofdata_to_platdata,
+	.probe	= tpm_rollback_probe,
+	.remove	= tpm_rollback_remove,
+	.ops	= &tpm_rollback_ops,
+};
diff --git a/include/tpm-v2.h b/include/tpm-v2.h
index 2b6980e441..8c441066a0 100644
--- a/include/tpm-v2.h
+++ b/include/tpm-v2.h
@@ -321,6 +321,7 @@ enum tpm2_return_codes {
 	TPM2_RC_COMMAND_CODE	= TPM2_RC_VER1 + 0x0043,
 	TPM2_RC_AUTHSIZE	= TPM2_RC_VER1 + 0x0044,
 	TPM2_RC_AUTH_CONTEXT	= TPM2_RC_VER1 + 0x0045,
+	TPM2_RC_NV_UNINITIALIZED	= TPM2_RC_VER1 + 0x04a,
 	TPM2_RC_NV_DEFINED	= TPM2_RC_VER1 + 0x004c,
 	TPM2_RC_NEEDS_TEST	= TPM2_RC_VER1 + 0x0053,
 	TPM2_RC_WARN		= 0x0900,
@@ -706,4 +707,20 @@ u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
  */
 u32 tpm2_auto_start(struct udevice *dev);
 
+/**
+ * tpm_rollback_counter_init() - Initialize a TPM rollback counter
+ *                               (used by the TPM-backed rollback device)
+ *
+ * Will define the non-volitile index and initialize to 0 if it hasn't
+ * been created previously.
+ *
+ * @dev:	     TPM device
+ * @nv_index:	     NV index to initialize
+ * @nv_policy:       NV index policy (pass NULL for no policy)
+ * @nv_policy_size:  NV index policy size (pass 0 for no policy)
+ * Return: result of the operation
+ */
+int tpm_rollback_counter_init(struct udevice *dev, u32 nv_index,
+			      const u8 *nv_policy, size_t nv_policy_size);
+
 #endif /* __TPM_V2_H */
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 9ab5b46df1..c3c469eb35 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -742,3 +742,51 @@ u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
 
 	return 0;
 }
+
+int tpm_rollback_counter_init(struct udevice *dev, u32 nv_index,
+			      const u8 *nv_policy, size_t nv_policy_size)
+{
+	int ret;
+	u64 data;
+	u64 data0 = 0;
+
+	ret = tpm_open(dev);
+	if (ret == -EBUSY) {
+		log(UCLASS_ROLLBACK, LOGL_DEBUG,
+		    "Existing TPM session found, reusing\n");
+	} else {
+		if (ret) {
+			log(UCLASS_ROLLBACK, LOGL_ERR,
+			    "TPM initialization failed (ret=%d)\n", ret);
+			return ret;
+		}
+
+		ret = tpm2_auto_start(dev);
+		if (ret) {
+			log(UCLASS_ROLLBACK, LOGL_ERR,
+			    "TPM startup failed (ret=%d)\n", ret);
+			return ret;
+		}
+	}
+
+	if (ret) {
+		log_err("TPM startup failed\n");
+		return ret;
+	}
+
+	/* test reading NV index from TPM */
+	ret = tpm2_nv_read_value(dev, nv_index, &data, sizeof(u64));
+
+	if (ret) {
+		/*read failed.  Assume the NV index hasn't been defined yet */
+		ret = tpm2_nv_define_space(dev, nv_index, sizeof(u64), TPMA_NV_PPREAD |
+					   TPMA_NV_PPWRITE | TPMA_NV_PLATFORMCREATE,
+					   nv_policy, nv_policy_size);
+
+		/* initialize the rollback counter to 0 */
+		if (ret == TPM2_RC_NV_DEFINED || !ret)
+			ret = tpm2_nv_write_value(dev, nv_index, &data0, sizeof(u64));
+	}
+
+	return ret;
+}
-- 
2.40.0



More information about the U-Boot mailing list