Julius Werner has submitted this change. ( https://review.coreboot.org/c/coreboot/+/66909 )
(
25 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )Change subject: vboot: Add VBOOT_CBFS_INTEGRATION support ......................................................................
vboot: Add VBOOT_CBFS_INTEGRATION support
This patch introduces support signing and verification of firmware slots using CBFS metadata hash verification method for faster initial verification. To have complete verification, CBFS_VERIFICATION should also be enabled, as metadata hash covers only files metadata, not their contents.
This patch also adapts mainboards and SoCs to new vboot reset requirements.
TEST=Google Volteer/Voxel boots with VBOOT_CBFS_INTEGRATION enabled
Signed-off-by: Jakub Czapiga jacz@semihalf.com Change-Id: I40ae01c477c4e4f7a1c90e4026a8a868ae64b5ca Reviewed-on: https://review.coreboot.org/c/coreboot/+/66909 Reviewed-by: Yu-Ping Wu yupingso@google.com Tested-by: build bot (Jenkins) no-reply@coreboot.org --- M src/include/cbfs_glue.h M src/lib/cbfs.c M src/mainboard/google/asurada/Makefile.inc M src/mainboard/google/cherry/Makefile.inc M src/mainboard/google/corsola/Makefile.inc M src/mainboard/google/geralt/Makefile.inc M src/security/vboot/Kconfig M src/security/vboot/Makefile.inc M src/security/vboot/common.c M src/security/vboot/vboot_common.c M src/security/vboot/vboot_loader.c M src/security/vboot/vboot_logic.c M src/soc/mediatek/mt8173/Makefile.inc 13 files changed, 126 insertions(+), 33 deletions(-)
Approvals: build bot (Jenkins): Verified Yu-Ping Wu: Looks good to me, approved
diff --git a/src/include/cbfs_glue.h b/src/include/cbfs_glue.h index d4fe367..99dc48d 100644 --- a/src/include/cbfs_glue.h +++ b/src/include/cbfs_glue.h @@ -13,11 +13,17 @@ * safety, we only need to verify the metadata hash in the initial stage and can assume it stays * valid in later stages. If TOCTOU safety is required, we may need them in every stage to * reverify metadata that had to be reloaded from flash (e.g. because it didn't fit the mcache). + * Moreover, if VBOOT_CBFS_INTEGRATION and verification are both enabled, then hashing functions + * are required during verification stage. * Note that this only concerns metadata hashing -- file access functions may still link hashing * routines independently for file data hashing. */ #define CBFS_ENABLE_HASHING (CONFIG(CBFS_VERIFICATION) && \ - (CONFIG(TOCTOU_SAFETY) || ENV_INITIAL_STAGE)) + (CONFIG(TOCTOU_SAFETY) || ENV_INITIAL_STAGE || \ + (CONFIG(VBOOT_CBFS_INTEGRATION) && \ + (verification_should_run() || \ + (verstage_should_load() && \ + CONFIG(VBOOT_RETURN_FROM_VERSTAGE)))))) #define CBFS_HASH_HWCRYPTO vboot_hwcrypto_allowed()
#define ERROR(...) printk(BIOS_ERR, "CBFS ERROR: " __VA_ARGS__) diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index 4f2d9ca..d2829d1 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -12,6 +12,7 @@ #include <list.h> #include <metadata_hash.h> #include <security/tpm/tspi/crtm.h> +#include <security/vboot/vboot_common.h> #include <security/vboot/misc.h> #include <stdlib.h> #include <string.h> @@ -57,7 +58,10 @@ RO CBFS would have been caught when building the mcache in cbfs_get boot_device(). (Note that TOCTOU_SAFETY implies !NO_CBFS_MCACHE.) */ assert(cbd == vboot_get_cbfs_boot_device()); - die("TODO: set metadata_hash to RW metadata hash here.\n"); + if (!CONFIG(VBOOT) + || vb2api_get_metadata_hash(vboot_get_context(), &metadata_hash) + != VB2_SUCCESS) + die("Failed to get RW metadata hash"); } err = cbfs_lookup(&cbd->rdev, name, mdata, &data_offset, metadata_hash); } @@ -160,8 +164,14 @@ ERROR("'%s' does not have a file hash!\n", mdata->h.filename); return true; } - if (vb2_hash_verify(vboot_hwcrypto_allowed(), buffer, size, hash)) { + + vb2_error_t rv = vb2_hash_verify(vboot_hwcrypto_allowed(), buffer, size, hash); + if (rv != VB2_SUCCESS) { ERROR("'%s' file hash mismatch!\n", mdata->h.filename); + if (CONFIG(VBOOT_CBFS_INTEGRATION) && !vboot_recovery_mode_enabled() + && vboot_logic_executed()) + vboot_fail_and_reboot(vboot_get_context(), VB2_RECOVERY_FW_BODY, + rv); return true; } } diff --git a/src/mainboard/google/asurada/Makefile.inc b/src/mainboard/google/asurada/Makefile.inc index 601b485..84600b6 100644 --- a/src/mainboard/google/asurada/Makefile.inc +++ b/src/mainboard/google/asurada/Makefile.inc @@ -12,6 +12,7 @@ romstage-y += boardid.c romstage-y += chromeos.c romstage-y += regulator.c +romstage-y += reset.c romstage-y += romstage.c romstage-y += sdram_configs.c
diff --git a/src/mainboard/google/cherry/Makefile.inc b/src/mainboard/google/cherry/Makefile.inc index e1e363c..4edbd38 100644 --- a/src/mainboard/google/cherry/Makefile.inc +++ b/src/mainboard/google/cherry/Makefile.inc @@ -10,6 +10,7 @@ romstage-y += boardid.c romstage-y += chromeos.c romstage-y += regulator.c +romstage-y += reset.c romstage-y += romstage.c romstage-y += sdram_configs.c
diff --git a/src/mainboard/google/corsola/Makefile.inc b/src/mainboard/google/corsola/Makefile.inc index 30ee6c1..d11f6ba 100644 --- a/src/mainboard/google/corsola/Makefile.inc +++ b/src/mainboard/google/corsola/Makefile.inc @@ -10,6 +10,7 @@ romstage-y += boardid.c romstage-y += chromeos.c romstage-y += regulator.c +romstage-y += reset.c romstage-y += romstage.c romstage-y += sdram_configs.c
diff --git a/src/mainboard/google/geralt/Makefile.inc b/src/mainboard/google/geralt/Makefile.inc index 85748dd..006b4f2 100644 --- a/src/mainboard/google/geralt/Makefile.inc +++ b/src/mainboard/google/geralt/Makefile.inc @@ -9,6 +9,7 @@ romstage-y += memlayout.ld romstage-y += chromeos.c romstage-y += regulator.c +romstage-y += reset.c romstage-y += romstage.c romstage-y += sdram_configs.c
diff --git a/src/security/vboot/Kconfig b/src/security/vboot/Kconfig index a36510d..93e1845 100644 --- a/src/security/vboot/Kconfig +++ b/src/security/vboot/Kconfig @@ -35,6 +35,20 @@ help Have two update partitions beside the RO partition.
+config VBOOT_CBFS_INTEGRATION + bool "Enable vboot and CBFS integration" + default n + depends on VBOOT_SLOTS_RW_A + depends on CBFS_VERIFICATION + help + Say yes here to enable cryptographic verification of RW slots CBFS + metadata. This will replace body hash verification. + + This option enables integration of vboot and CBFS. Verification of RW + slots is performed by calculation of their CBFS metadata hash. + It also requires CBFS_VERIFICATION to be enabled, so that CBFS files + contents are correctly verified. + config VBOOT_VBNV_CMOS bool default n diff --git a/src/security/vboot/Makefile.inc b/src/security/vboot/Makefile.inc index bd73871..e4771dd 100644 --- a/src/security/vboot/Makefile.inc +++ b/src/security/vboot/Makefile.inc @@ -61,6 +61,7 @@ verstage-y += vbnv.c romstage-y += vbnv.c ramstage-y += vbnv.c +postcar-y += vbnv.c
romstage-$(CONFIG_VBOOT_EARLY_EC_SYNC) += ec_sync.c
@@ -68,16 +69,19 @@ verstage-$(CONFIG_VBOOT_VBNV_CMOS) += vbnv_cmos.c romstage-$(CONFIG_VBOOT_VBNV_CMOS) += vbnv_cmos.c ramstage-$(CONFIG_VBOOT_VBNV_CMOS) += vbnv_cmos.c +postcar-$(CONFIG_VBOOT_VBNV_CMOS) += vbnv_cmos.c
bootblock-$(CONFIG_VBOOT_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c verstage-$(CONFIG_VBOOT_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c romstage-$(CONFIG_VBOOT_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c ramstage-$(CONFIG_VBOOT_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c +postcar-$(CONFIG_VBOOT_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c
bootblock-$(CONFIG_VBOOT_VBNV_FLASH) += vbnv_flash.c verstage-$(CONFIG_VBOOT_VBNV_FLASH) += vbnv_flash.c romstage-$(CONFIG_VBOOT_VBNV_FLASH) += vbnv_flash.c ramstage-$(CONFIG_VBOOT_VBNV_FLASH) += vbnv_flash.c +postcar-$(CONFIG_VBOOT_VBNV_FLASH) += vbnv_flash.c
bootblock-y += vboot_loader.c romstage-y += vboot_loader.c diff --git a/src/security/vboot/common.c b/src/security/vboot/common.c index 7f1aee1..1703933 100644 --- a/src/security/vboot/common.c +++ b/src/security/vboot/common.c @@ -63,8 +63,16 @@ if (ret) return ret;
- /* Truncate area to the size that was actually signed by vboot. */ - return rdev_chain(fw, fw, 0, vb2api_get_firmware_size(ctx)); + /* + * Truncate area to the size that was actually signed by vboot. + * It is only required for old verification mechanism calculating full body hash. + * New verification mechanism uses signature with zero data size, so truncation + * is not possible. + */ + if (!CONFIG(VBOOT_CBFS_INTEGRATION)) + return rdev_chain(fw, fw, 0, vb2api_get_firmware_size(ctx)); + + return 0; }
static void vboot_setup_cbmem(int unused) diff --git a/src/security/vboot/vboot_common.c b/src/security/vboot/vboot_common.c index 8ecb5d8..dd611d1 100644 --- a/src/security/vboot/vboot_common.c +++ b/src/security/vboot/vboot_common.c @@ -11,6 +11,11 @@
void vboot_save_data(struct vb2_context *ctx) { + if (!verification_should_run() && !(ENV_ROMSTAGE && CONFIG(VBOOT_EARLY_EC_SYNC)) + && (ctx->flags + & (VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED | VB2_CONTEXT_SECDATA_KERNEL_CHANGED))) + die("TPM writeback in " ENV_STRING "?"); + if (ctx->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED && (CONFIG(VBOOT_MOCK_SECDATA) || tlcl_lib_init() == VB2_SUCCESS)) { printk(BIOS_INFO, "Saving secdata firmware\n"); diff --git a/src/security/vboot/vboot_loader.c b/src/security/vboot/vboot_loader.c index 0acb349..7cda690 100644 --- a/src/security/vboot/vboot_loader.c +++ b/src/security/vboot/vboot_loader.c @@ -28,15 +28,32 @@
static void after_verstage(void) { + struct vb2_hash *metadata_hash = NULL; + struct vb2_context *ctx = NULL; + + if (CONFIG(VBOOT_CBFS_INTEGRATION)) { + ctx = vboot_get_context(); + vb2_error_t rv = vb2api_get_metadata_hash(ctx, &metadata_hash); + if (rv) + vboot_fail_and_reboot(ctx, VB2_RECOVERY_FW_PREAMBLE, rv); + } + vboot_executed = 1; /* Mark verstage execution complete. */
const struct cbfs_boot_device *cbd = vboot_get_cbfs_boot_device(); if (!cbd) /* Can't initialize RW CBFS in recovery mode. */ return;
- enum cb_err err = cbfs_init_boot_device(cbd, NULL); /* TODO: RW hash */ - if (err && err != CB_CBFS_CACHE_FULL) /* TODO: -> recovery? */ - die("RW CBFS initialization failure: %d", err); + enum cb_err err = cbfs_init_boot_device(cbd, metadata_hash); + if (err && err != CB_CBFS_CACHE_FULL) { + if (CONFIG(VBOOT_CBFS_INTEGRATION)) { + printk(BIOS_ERR, "RW CBFS initialization failed: %d\n", err); + /* CBFS error code does not fit in subcode. Use only lowest byte. */ + vboot_fail_and_reboot(ctx, VB2_RECOVERY_FW_BODY, err & 0xFF); + } else { + die("RW CBFS initialization failure: %d", err); + } + } }
void vboot_run_logic(void) diff --git a/src/security/vboot/vboot_logic.c b/src/security/vboot/vboot_logic.c index 660b7da..98a044c 100644 --- a/src/security/vboot/vboot_logic.c +++ b/src/security/vboot/vboot_logic.c @@ -54,7 +54,7 @@ return VB2_SUCCESS; }
-static int handle_digest_result(void *slot_hash, size_t slot_hash_sz) +static vb2_error_t handle_digest_result(void *slot_hash, size_t slot_hash_sz) { int is_resume;
@@ -63,14 +63,14 @@ * vboot_retrieve_hash(), if Chrome EC is not enabled then return. */ if (!CONFIG(EC_GOOGLE_CHROMEEC)) - return 0; + return VB2_SUCCESS;
/* * Nothing to do since resuming on the platform doesn't require * vboot verification again. */ if (!CONFIG(RESUME_PATH_SAME_AS_BOOT)) - return 0; + return VB2_SUCCESS;
/* * Assume that if vboot doesn't start in bootblock verified @@ -78,7 +78,7 @@ * lives in RO CBFS. */ if (!CONFIG(VBOOT_STARTS_IN_BOOTBLOCK)) - return 0; + return VB2_SUCCESS;
is_resume = platform_is_resuming();
@@ -92,12 +92,12 @@
if (vboot_retrieve_hash(saved_hash, saved_hash_sz)) { printk(BIOS_ERR, "Couldn't retrieve saved hash.\n"); - return -1; + return VB2_ERROR_UNKNOWN; }
if (memcmp(saved_hash, slot_hash, slot_hash_sz)) { printk(BIOS_ERR, "Hash mismatch on resume.\n"); - return -1; + return VB2_ERROR_UNKNOWN; } } else if (is_resume < 0) printk(BIOS_ERR, "Unable to determine if platform resuming.\n"); @@ -111,10 +111,10 @@ * lead to a reboot loop. The consequence of this is that * we will most likely fail resuming because of EC issues or * the hash digest not matching. */ - return 0; + return VB2_SUCCESS; }
- return 0; + return VB2_SUCCESS; }
static vb2_error_t hash_body(struct vb2_context *ctx, @@ -179,10 +179,7 @@
timestamp_add_now(TS_HASH_BODY_END);
- if (handle_digest_result(hash_digest, hash_digest_sz)) - return VB2_ERROR_UNKNOWN; - - return VB2_SUCCESS; + return handle_digest_result(hash_digest, hash_digest_sz); }
static uint32_t extend_pcrs(struct vb2_context *ctx) @@ -236,16 +233,10 @@ ctx->flags |= VB2_CONTEXT_EC_TRUSTED; }
-/** - * Verify and select the firmware in the RW image - * - * TODO: Avoid loading a stage twice (once in hash_body & again in load_stage). - * when per-stage verification is ready. - */ +/* Verify and select the firmware in the RW image */ void verstage_main(void) { struct vb2_context *ctx; - struct region_device fw_body; vb2_error_t rv;
timestamp_add_now(TS_VBOOT_START); @@ -326,7 +317,6 @@ extend_pcrs(ctx); /* ignore failures */ goto verstage_main_exit; } - vboot_save_and_reboot(ctx, rv); }
@@ -345,12 +335,22 @@ vboot_save_and_reboot(ctx, rv);
printk(BIOS_INFO, "Phase 4\n"); - rv = vboot_locate_firmware(ctx, &fw_body); - if (rv) - die_with_post_code(POST_INVALID_ROM, - "Failed to read FMAP to locate firmware"); + if (CONFIG(VBOOT_CBFS_INTEGRATION)) { + struct vb2_hash *metadata_hash; + rv = vb2api_get_metadata_hash(ctx, &metadata_hash); + if (rv == VB2_SUCCESS) + rv = handle_digest_result(metadata_hash->raw, + vb2_digest_size(metadata_hash->algo)); + } else { + struct region_device fw_body; + rv = vboot_locate_firmware(ctx, &fw_body); + if (rv) + die_with_post_code(POST_INVALID_ROM, + "Failed to read FMAP to locate firmware");
- rv = hash_body(ctx, &fw_body); + rv = hash_body(ctx, &fw_body); + } + if (rv) vboot_save_and_reboot(ctx, rv); vboot_save_data(ctx); diff --git a/src/soc/mediatek/mt8173/Makefile.inc b/src/soc/mediatek/mt8173/Makefile.inc index e824e54..7688ecf 100644 --- a/src/soc/mediatek/mt8173/Makefile.inc +++ b/src/soc/mediatek/mt8173/Makefile.inc @@ -46,6 +46,7 @@ romstage-y += memory.c romstage-y += emi.c dramc_pi_basic_api.c dramc_pi_calibration_api.c romstage-$(CONFIG_MEMORY_TEST) += ../common/memory_test.c +romstage-y += ../common/wdt.c ../common/reset.c romstage-y += ../common/mmu_operations.c mmu_operations.c romstage-y += ../common/rtc.c rtc.c