summaryrefslogtreecommitdiff
path: root/src/security
diff options
context:
space:
mode:
authorJakub Czapiga <jacz@semihalf.com>2022-08-19 12:25:27 +0200
committerJulius Werner <jwerner@chromium.org>2022-11-08 23:03:49 +0000
commit967a76bd811088b2a8bd7f008b2436e31ab4e5b3 (patch)
tree1568d12f1aee56c85d2190559115f86547ad45b1 /src/security
parentfe17a7d4d420763ef387e84256eaed0373c25725 (diff)
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>
Diffstat (limited to 'src/security')
-rw-r--r--src/security/vboot/Kconfig14
-rw-r--r--src/security/vboot/Makefile.inc4
-rw-r--r--src/security/vboot/common.c12
-rw-r--r--src/security/vboot/vboot_common.c5
-rw-r--r--src/security/vboot/vboot_loader.c23
-rw-r--r--src/security/vboot/vboot_logic.c50
6 files changed, 78 insertions, 30 deletions
diff --git a/src/security/vboot/Kconfig b/src/security/vboot/Kconfig
index a36510dee7..93e18457f7 100644
--- a/src/security/vboot/Kconfig
+++ b/src/security/vboot/Kconfig
@@ -35,6 +35,20 @@ config VBOOT_SLOTS_RW_AB
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 bd738711c3..e4771dd415 100644
--- a/src/security/vboot/Makefile.inc
+++ b/src/security/vboot/Makefile.inc
@@ -61,6 +61,7 @@ bootblock-y += vbnv.c
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 @@ bootblock-$(CONFIG_VBOOT_VBNV_CMOS) += vbnv_cmos.c
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 7f1aee1820..17039330a6 100644
--- a/src/security/vboot/common.c
+++ b/src/security/vboot/common.c
@@ -63,8 +63,16 @@ int vboot_locate_firmware(struct vb2_context *ctx, struct region_device *fw)
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 8ecb5d81eb..dd611d1145 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 0acb349941..7cda690216 100644
--- a/src/security/vboot/vboot_loader.c
+++ b/src/security/vboot/vboot_loader.c
@@ -28,15 +28,32 @@ int vboot_executed;
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 660b7da1be..98a044c7e1 100644
--- a/src/security/vboot/vboot_logic.c
+++ b/src/security/vboot/vboot_logic.c
@@ -54,7 +54,7 @@ vb2_error_t vb2ex_read_resource(struct vb2_context *ctx,
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 @@ static int handle_digest_result(void *slot_hash, size_t slot_hash_sz)
* 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 @@ static int handle_digest_result(void *slot_hash, size_t slot_hash_sz)
* lives in RO CBFS.
*/
if (!CONFIG(VBOOT_STARTS_IN_BOOTBLOCK))
- return 0;
+ return VB2_SUCCESS;
is_resume = platform_is_resuming();
@@ -92,12 +92,12 @@ static int handle_digest_result(void *slot_hash, size_t slot_hash_sz)
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 @@ static int handle_digest_result(void *slot_hash, size_t slot_hash_sz)
* 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 @@ static vb2_error_t hash_body(struct vb2_context *ctx,
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 @@ static void check_boot_mode(struct vb2_context *ctx)
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 @@ void verstage_main(void)
extend_pcrs(ctx); /* ignore failures */
goto verstage_main_exit;
}
-
vboot_save_and_reboot(ctx, rv);
}
@@ -345,12 +335,22 @@ void verstage_main(void)
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);