summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/antirollback.h9
-rw-r--r--src/vboot/Kconfig8
-rw-r--r--src/vboot/Makefile.inc8
-rw-r--r--src/vboot/secdata_mock.c5
-rw-r--r--src/vboot/secdata_tpm.c97
-rw-r--r--src/vboot/vboot_logic.c13
6 files changed, 140 insertions, 0 deletions
diff --git a/src/include/antirollback.h b/src/include/antirollback.h
index b8ba909385..a48aa20002 100644
--- a/src/include/antirollback.h
+++ b/src/include/antirollback.h
@@ -21,6 +21,8 @@ enum vb2_pcr_digest;
* want to use 0x1009 for something else. */
#define BACKUP_NV_INDEX 0x1009
#define FWMP_NV_INDEX 0x100a
+#define REC_HASH_NV_INDEX 0x100b
+#define REC_HASH_NV_SIZE VB2_SHA256_DIGEST_SIZE
/* Structure definitions for TPM spaces */
@@ -46,6 +48,13 @@ uint32_t antirollback_write_space_firmware(struct vb2_context *ctx);
*/
uint32_t antirollback_lock_space_firmware(void);
+/* Read recovery hash data from TPM. */
+uint32_t antirollback_read_space_rec_hash(uint8_t *data, uint32_t size);
+/* Write new hash data to recovery space in TPM. */
+uint32_t antirollback_write_space_rec_hash(const uint8_t *data, uint32_t size);
+/* Lock down recovery hash space in TPM. */
+uint32_t antirollback_lock_space_rec_hash(void);
+
/****************************************************************************/
/*
diff --git a/src/vboot/Kconfig b/src/vboot/Kconfig
index f3df7c524b..b5c862620f 100644
--- a/src/vboot/Kconfig
+++ b/src/vboot/Kconfig
@@ -134,6 +134,14 @@ config VBOOT_OPROM_MATTERS
it works functionally the same for other platforms that can skip their
native display initialization code instead.
+config VBOOT_HAS_REC_HASH_SPACE
+ bool
+ default n
+ depends on VBOOT
+ help
+ Set this option to indicate to vboot that recovery data hash space
+ is present in TPM.
+
config VBOOT
bool "Verify firmware with vboot."
default n
diff --git a/src/vboot/Makefile.inc b/src/vboot/Makefile.inc
index 05870cab68..33109deb8c 100644
--- a/src/vboot/Makefile.inc
+++ b/src/vboot/Makefile.inc
@@ -107,6 +107,14 @@ $(VB2_LIB): $(obj)/config.h
libverstage-srcs += $(VB2_LIB)
ifeq ($(CONFIG_SEPARATE_VERSTAGE),y)
+
+# This works under the assumption that romstage and verstage use the same
+# architecture and thus CC_verstage is the same as CC_romstage. If this is not
+# true, VB2_LIB needs to ensure that correct CC is being used.
+ifeq ($(CONFIG_VBOOT_HAS_REC_HASH_SPACE),y)
+romstage-srcs += $(VB2_LIB)
+endif
+
cbfs-files-$(CONFIG_SEPARATE_VERSTAGE) += $(CONFIG_CBFS_PREFIX)/verstage
$(CONFIG_CBFS_PREFIX)/verstage-file := $(objcbfs)/verstage.elf
$(CONFIG_CBFS_PREFIX)/verstage-type := stage
diff --git a/src/vboot/secdata_mock.c b/src/vboot/secdata_mock.c
index 03616c1524..9c966d9bbd 100644
--- a/src/vboot/secdata_mock.c
+++ b/src/vboot/secdata_mock.c
@@ -36,3 +36,8 @@ uint32_t antirollback_lock_space_firmware()
{
return TPM_SUCCESS;
}
+
+uint32_t antirollback_lock_space_rec_hash(void)
+{
+ return TPM_SUCCESS;
+}
diff --git a/src/vboot/secdata_tpm.c b/src/vboot/secdata_tpm.c
index b1f3197610..95605f6049 100644
--- a/src/vboot/secdata_tpm.c
+++ b/src/vboot/secdata_tpm.c
@@ -72,6 +72,13 @@ static uint32_t read_space_firmware(struct vb2_context *ctx)
return TPM_E_CORRUPTED_STATE;
}
+static uint32_t read_space_rec_hash(uint8_t *data)
+{
+ RETURN_ON_FAILURE(tlcl_read(REC_HASH_NV_INDEX, data,
+ REC_HASH_NV_SIZE));
+ return TPM_SUCCESS;
+}
+
static uint32_t write_secdata(uint32_t index,
const uint8_t *secdata,
uint32_t len)
@@ -117,6 +124,13 @@ static const uint8_t secdata_kernel[] = {
0xE8,
};
+/*
+ * This is used to initialize the TPM space for recovery hash after defining
+ * it. Since there is no data available to calculate hash at the point where TPM
+ * space is defined, initialize it to all 0s.
+ */
+static const uint8_t rec_hash_data[REC_HASH_NV_SIZE] = { };
+
#if IS_ENABLED(CONFIG_TPM2)
/* Nothing special in the TPM2 path yet. */
@@ -143,11 +157,24 @@ static uint32_t set_kernel_space(const void *kernel_blob)
return TPM_SUCCESS;
}
+static uint32_t set_rec_hash_space(const uint8_t *data)
+{
+ RETURN_ON_FAILURE(tlcl_define_space(REC_HASH_NV_INDEX,
+ REC_HASH_NV_SIZE));
+ RETURN_ON_FAILURE(safe_write(REC_HASH_NV_INDEX, data,
+ REC_HASH_NV_SIZE));
+ return TPM_SUCCESS;
+}
+
static uint32_t _factory_initialize_tpm(struct vb2_context *ctx)
{
RETURN_ON_FAILURE(tlcl_force_clear());
RETURN_ON_FAILURE(set_firmware_space(ctx->secdata));
RETURN_ON_FAILURE(set_kernel_space(secdata_kernel));
+
+ if (IS_ENABLED(CONFIG_VBOOT_HAS_REC_HASH_SPACE))
+ RETURN_ON_FAILURE(set_rec_hash_space(rec_hash_data));
+
return TPM_SUCCESS;
}
@@ -163,6 +190,11 @@ uint32_t antirollback_lock_space_firmware(void)
return tlcl_lock_nv_write(FIRMWARE_NV_INDEX);
}
+uint32_t antirollback_lock_space_rec_hash(void)
+{
+ return tlcl_lock_nv_write(REC_HASH_NV_INDEX);
+}
+
#else
uint32_t tpm_clear_and_reenable(void)
@@ -210,6 +242,18 @@ static uint32_t safe_define_space(uint32_t index, uint32_t perm, uint32_t size)
}
}
+static uint32_t set_rec_hash_space(const uint8_t *data)
+{
+ RETURN_ON_FAILURE(safe_define_space(REC_HASH_NV_INDEX,
+ TPM_NV_PER_GLOBALLOCK |
+ TPM_NV_PER_PPWRITE,
+ REC_HASH_NV_SIZE));
+ RETURN_ON_FAILURE(write_secdata(REC_HASH_NV_INDEX, data,
+ REC_HASH_NV_SIZE));
+
+ return TPM_SUCCESS;
+}
+
static uint32_t _factory_initialize_tpm(struct vb2_context *ctx)
{
TPM_PERMANENT_FLAGS pflags;
@@ -262,6 +306,11 @@ static uint32_t _factory_initialize_tpm(struct vb2_context *ctx)
RETURN_ON_FAILURE(write_secdata(FIRMWARE_NV_INDEX,
ctx->secdata,
VB2_SECDATA_SIZE));
+
+ /* Define and set rec hash space, if available. */
+ if (IS_ENABLED(CONFIG_VBOOT_HAS_REC_HASH_SPACE))
+ RETURN_ON_FAILURE(set_rec_hash_space(rec_hash_data));
+
return TPM_SUCCESS;
}
@@ -269,6 +318,15 @@ uint32_t antirollback_lock_space_firmware(void)
{
return tlcl_set_global_lock();
}
+
+uint32_t antirollback_lock_space_rec_hash(void)
+{
+ /*
+ * Nothing needs to be done here, since global lock is already set while
+ * locking firmware space.
+ */
+ return TPM_SUCCESS;
+}
#endif
uint32_t factory_initialize_tpm(struct vb2_context *ctx)
@@ -430,3 +488,42 @@ uint32_t antirollback_write_space_firmware(struct vb2_context *ctx)
{
return write_secdata(FIRMWARE_NV_INDEX, ctx->secdata, VB2_SECDATA_SIZE);
}
+
+uint32_t antirollback_read_space_rec_hash(uint8_t *data, uint32_t size)
+{
+ if (size != REC_HASH_NV_SIZE) {
+ VBDEBUG("TPM: Incorrect buffer size for rec hash. "
+ "(Expected=0x%x Actual=0x%x).\n", REC_HASH_NV_SIZE,
+ size);
+ return TPM_E_READ_FAILURE;
+ }
+ return read_space_rec_hash(data);
+}
+
+uint32_t antirollback_write_space_rec_hash(const uint8_t *data, uint32_t size)
+{
+ uint8_t spc_data[REC_HASH_NV_SIZE];
+ uint32_t rv;
+
+ if (size != REC_HASH_NV_SIZE) {
+ VBDEBUG("TPM: Incorrect buffer size for rec hash. "
+ "(Expected=0x%x Actual=0x%x).\n", REC_HASH_NV_SIZE,
+ size);
+ return TPM_E_WRITE_FAILURE;
+ }
+
+ rv = read_space_rec_hash(spc_data);
+ if (rv == TPM_E_BADINDEX) {
+ /*
+ * If space is not defined already for recovery hash, define
+ * new space.
+ */
+ VBDEBUG("TPM: Initializing recovery hash space.\n");
+ return set_rec_hash_space(data);
+ }
+
+ if (rv != TPM_SUCCESS)
+ return rv;
+
+ return write_secdata(REC_HASH_NV_INDEX, data, size);
+}
diff --git a/src/vboot/vboot_logic.c b/src/vboot/vboot_logic.c
index 57d83a0f61..bfed7d40e1 100644
--- a/src/vboot/vboot_logic.c
+++ b/src/vboot/vboot_logic.c
@@ -416,6 +416,19 @@ void verstage_main(void)
vboot_reboot();
}
+ /* Lock rec hash space if available. */
+ if (IS_ENABLED(CONFIG_VBOOT_HAS_REC_HASH_SPACE)) {
+ rv = antirollback_lock_space_rec_hash();
+ if (rv) {
+ printk(BIOS_INFO, "Failed to lock rec hash space(%x)\n",
+ rv);
+ vb2api_fail(&ctx, VB2_RECOVERY_RO_TPM_REC_HASH_L_ERROR,
+ 0);
+ save_if_needed(&ctx);
+ vboot_reboot();
+ }
+ }
+
printk(BIOS_INFO, "Slot %c is selected\n", is_slot_a(&ctx) ? 'A' : 'B');
vb2_set_selected_region(region_device_region(&fw_main));
timestamp_add_now(TS_END_VBOOT);