From dff56a056c7dadf0d970cfe29f0bc9c1fec69e82 Mon Sep 17 00:00:00 2001 From: dnojiri Date: Fri, 3 Apr 2020 10:56:43 -0700 Subject: ec_sync: Run EFS2 in romstage EFS2 allows EC RO to enable PD for special cases. When doing so, it sets NO_BOOT flag to avoid booting the OS. AP needs to get NO_BOOT flag from Cr50 and enforce that. This patch makes verstage get a boot mode and a mirrored hash stored in kernel secdata from Cr50. This patch also makes romstage write an expected EC hash (a.k.a. Hexp) to Cr50 (if there is an update). BUG=b:147298634, chromium:1045217, b:148259137 BRANCH=none TEST=Verify software sync succeeds on Puff. Signed-off-by: dnojiri Change-Id: I1f387b6e920205b9cc4c8536561f2a279c36413d Reviewed-on: https://review.coreboot.org/c/coreboot/+/40389 Tested-by: build bot (Jenkins) Reviewed-by: Julius Werner --- src/security/vboot/antirollback.h | 6 +++ src/security/vboot/ec_sync.c | 2 +- src/security/vboot/secdata_mock.c | 11 ++++++ src/security/vboot/secdata_tpm.c | 25 +++++++++++++ src/security/vboot/vboot_common.h | 1 - src/security/vboot/vboot_logic.c | 79 ++++++++++++++++++++++++++++++++------- 6 files changed, 108 insertions(+), 16 deletions(-) diff --git a/src/security/vboot/antirollback.h b/src/security/vboot/antirollback.h index 5af923600d..6bc020d208 100644 --- a/src/security/vboot/antirollback.h +++ b/src/security/vboot/antirollback.h @@ -71,6 +71,12 @@ uint32_t antirollback_read_space_firmware(struct vb2_context *ctx); */ uint32_t antirollback_write_space_firmware(struct vb2_context *ctx); +/** + * Read and write kernel space in TPM. + */ +uint32_t antirollback_read_space_kernel(struct vb2_context *ctx); +uint32_t antirollback_write_space_kernel(struct vb2_context *ctx); + /** * Lock must be called. */ diff --git a/src/security/vboot/ec_sync.c b/src/security/vboot/ec_sync.c index 3a177b16e8..580e6c6b8d 100644 --- a/src/security/vboot/ec_sync.c +++ b/src/security/vboot/ec_sync.c @@ -50,7 +50,7 @@ void vboot_sync_ec(void) ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED; retval = vb2api_ec_sync(ctx); - vboot_save_nvdata_only(ctx); + vboot_save_data(ctx); switch (retval) { case VB2_SUCCESS: diff --git a/src/security/vboot/secdata_mock.c b/src/security/vboot/secdata_mock.c index a4957f9575..edb6739653 100644 --- a/src/security/vboot/secdata_mock.c +++ b/src/security/vboot/secdata_mock.c @@ -53,6 +53,17 @@ vb2_error_t antirollback_write_space_firmware(struct vb2_context *ctx) return VB2_SUCCESS; } +vb2_error_t antirollback_read_space_kernel(struct vb2_context *ctx) +{ + vb2api_secdata_kernel_create(ctx); + return VB2_SUCCESS; +} + +vb2_error_t antirollback_write_space_kernel(struct vb2_context *ctx) +{ + return VB2_SUCCESS; +} + vb2_error_t antirollback_lock_space_firmware(void) { return VB2_SUCCESS; diff --git a/src/security/vboot/secdata_tpm.c b/src/security/vboot/secdata_tpm.c index 0ae956276c..b60a1bb315 100644 --- a/src/security/vboot/secdata_tpm.c +++ b/src/security/vboot/secdata_tpm.c @@ -80,6 +80,22 @@ static uint32_t read_space_firmware(struct vb2_context *ctx) return TPM_E_CORRUPTED_STATE; } +uint32_t antirollback_read_space_kernel(struct vb2_context *ctx) +{ + uint8_t size = VB2_SECDATA_KERNEL_MIN_SIZE; + + RETURN_ON_FAILURE(tlcl_read(KERNEL_NV_INDEX, ctx->secdata_kernel, + size)); + + if (vb2api_secdata_kernel_check(ctx, &size) + == VB2_ERROR_SECDATA_KERNEL_INCOMPLETE) + /* Re-read. vboot will run the check and handle errors. */ + RETURN_ON_FAILURE(tlcl_read(KERNEL_NV_INDEX, + ctx->secdata_kernel, size)); + + return TPM_SUCCESS; +} + static uint32_t read_space_rec_hash(uint8_t *data) { RETURN_ON_FAILURE(tlcl_read(REC_HASH_NV_INDEX, data, @@ -440,6 +456,15 @@ uint32_t antirollback_write_space_firmware(struct vb2_context *ctx) VB2_SECDATA_FIRMWARE_SIZE); } +uint32_t antirollback_write_space_kernel(struct vb2_context *ctx) +{ + /* Learn the expected size. */ + uint8_t size = VB2_SECDATA_KERNEL_MIN_SIZE; + vb2api_secdata_kernel_check(ctx, &size); + + return write_secdata(KERNEL_NV_INDEX, ctx->secdata_kernel, size); +} + uint32_t antirollback_read_space_rec_hash(uint8_t *data, uint32_t size) { if (size != REC_HASH_NV_SIZE) { diff --git a/src/security/vboot/vboot_common.h b/src/security/vboot/vboot_common.h index 50995e6c04..f25ee46b6f 100644 --- a/src/security/vboot/vboot_common.h +++ b/src/security/vboot/vboot_common.h @@ -61,7 +61,6 @@ static inline void vboot_run_logic(void) {} static inline int vboot_locate_cbfs(struct region_device *rdev) { return -1; } #endif -void vboot_save_nvdata_only(struct vb2_context *ctx); void vboot_save_data(struct vb2_context *ctx); /* diff --git a/src/security/vboot/vboot_logic.c b/src/security/vboot/vboot_logic.c index 9e9e82ac6b..8e82e40bf0 100644 --- a/src/security/vboot/vboot_logic.c +++ b/src/security/vboot/vboot_logic.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -207,10 +208,21 @@ static vb2_error_t hash_body(struct vb2_context *ctx, return VB2_SUCCESS; } -void vboot_save_nvdata_only(struct vb2_context *ctx) +void vboot_save_data(struct vb2_context *ctx) { - assert(!(ctx->flags & (VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED | - VB2_CONTEXT_SECDATA_KERNEL_CHANGED))); + if (ctx->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED && + (CONFIG(VBOOT_MOCK_SECDATA) || tlcl_lib_init() == VB2_SUCCESS)) { + printk(BIOS_INFO, "Saving secdata firmware\n"); + antirollback_write_space_firmware(ctx); + ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED; + } + + if (ctx->flags & VB2_CONTEXT_SECDATA_KERNEL_CHANGED && + (CONFIG(VBOOT_MOCK_SECDATA) || tlcl_lib_init() == VB2_SUCCESS)) { + printk(BIOS_INFO, "Saving secdata kernel\n"); + antirollback_write_space_kernel(ctx); + ctx->flags &= ~VB2_CONTEXT_SECDATA_KERNEL_CHANGED; + } if (ctx->flags & VB2_CONTEXT_NVDATA_CHANGED) { printk(BIOS_INFO, "Saving nvdata\n"); @@ -219,21 +231,55 @@ void vboot_save_nvdata_only(struct vb2_context *ctx) } } -void vboot_save_data(struct vb2_context *ctx) +static uint32_t extend_pcrs(struct vb2_context *ctx) { - if (ctx->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED) { - printk(BIOS_INFO, "Saving secdata\n"); - antirollback_write_space_firmware(ctx); - ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED; - } + return vboot_extend_pcr(ctx, 0, BOOT_MODE_PCR) || + vboot_extend_pcr(ctx, 1, HWID_DIGEST_PCR); +} - vboot_save_nvdata_only(ctx); +#define EC_EFS_BOOT_MODE_NORMAL 0x00 +#define EC_EFS_BOOT_MODE_NO_BOOT 0x01 + +static const char *get_boot_mode_string(uint8_t boot_mode) +{ + if (boot_mode == EC_EFS_BOOT_MODE_NORMAL) + return "NORMAL"; + else if (boot_mode == EC_EFS_BOOT_MODE_NO_BOOT) + return "NO_BOOT"; + else + return "UNDEFINED"; } -static uint32_t extend_pcrs(struct vb2_context *ctx) +static void check_boot_mode(struct vb2_context *ctx) { - return vboot_extend_pcr(ctx, 0, BOOT_MODE_PCR) || - vboot_extend_pcr(ctx, 1, HWID_DIGEST_PCR); + uint8_t boot_mode; + int rv; + + rv = tlcl_cr50_get_boot_mode(&boot_mode); + switch (rv) { + case TPM_E_NO_SUCH_COMMAND: + printk(BIOS_WARNING, "Cr50 does not support GET_BOOT_MODE.\n"); + /* Proceed to legacy boot model. */ + return; + case TPM_SUCCESS: + break; + default: + printk(BIOS_ERR, + "Communication error in getting Cr50 boot mode.\n"); + if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) + /* Continue to boot in recovery mode */ + return; + vb2api_fail(ctx, VB2_RECOVERY_CR50_BOOT_MODE, rv); + vboot_save_data(ctx); + vboot_reboot(); + return; + } + + printk(BIOS_INFO, "Cr50 says boot_mode is %s(0x%02x).\n", + get_boot_mode_string(boot_mode), boot_mode); + + if (boot_mode == EC_EFS_BOOT_MODE_NO_BOOT) + ctx->flags |= VB2_CONTEXT_NO_BOOT; } /** @@ -268,8 +314,10 @@ void verstage_main(void) * check the return value here because vb2api_fw_phase1 will catch * invalid secdata and tell us what to do (=reboot). */ timestamp_add_now(TS_START_TPMINIT); - if (vboot_setup_tpm(ctx) == TPM_SUCCESS) + if (vboot_setup_tpm(ctx) == TPM_SUCCESS) { antirollback_read_space_firmware(ctx); + antirollback_read_space_kernel(ctx); + } timestamp_add_now(TS_END_TPMINIT); if (get_recovery_mode_switch()) { @@ -359,6 +407,9 @@ void verstage_main(void) timestamp_add_now(TS_END_TPMPCR); } + if (CONFIG(TPM_CR50)) + check_boot_mode(ctx); + /* Lock TPM */ timestamp_add_now(TS_START_TPMLOCK); -- cgit v1.2.3