diff options
-rw-r--r-- | src/include/antirollback.h | 9 | ||||
-rw-r--r-- | src/vboot/Kconfig | 8 | ||||
-rw-r--r-- | src/vboot/Makefile.inc | 8 | ||||
-rw-r--r-- | src/vboot/secdata_mock.c | 5 | ||||
-rw-r--r-- | src/vboot/secdata_tpm.c | 97 | ||||
-rw-r--r-- | src/vboot/vboot_logic.c | 13 |
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); |