diff options
Diffstat (limited to 'src/vendorcode')
-rw-r--r-- | src/vendorcode/google/chromeos/vboot2/vboot_logic.c | 70 | ||||
-rw-r--r-- | src/vendorcode/google/chromeos/vboot_common.h | 18 |
2 files changed, 87 insertions, 1 deletions
diff --git a/src/vendorcode/google/chromeos/vboot2/vboot_logic.c b/src/vendorcode/google/chromeos/vboot2/vboot_logic.c index b72de93245..0d08d6adb2 100644 --- a/src/vendorcode/google/chromeos/vboot2/vboot_logic.c +++ b/src/vendorcode/google/chromeos/vboot2/vboot_logic.c @@ -26,6 +26,9 @@ #include "../chromeos.h" #include "misc.h" +/* The max hash size to expect is for SHA512. */ +#define VBOOT_MAX_HASH_SIZE VB2_SHA512_DIGEST_SIZE + #define TODO_BLOCK_SIZE 1024 static int is_slot_a(struct vb2_context *ctx) @@ -111,15 +114,77 @@ int vb2ex_hwcrypto_digest_finalize(uint8_t *digest, uint32_t digest_size) return VB2_ERROR_UNKNOWN; } +static int handle_digest_result(void *slot_hash, size_t slot_hash_sz) +{ + int is_resume; + + /* + * Nothing to do since resuming on the platform doesn't require + * vboot verification again. + */ + if (!IS_ENABLED(CONFIG_RESUME_PATH_SAME_AS_BOOT)) + return 0; + + /* + * Assume that if vboot doesn't start in bootblock verified + * RW memory init code is not employed. i.e. memory init code + * lives in RO CBFS. + */ + if (!IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK)) + return 0; + + is_resume = vboot_platform_is_resuming(); + + if (is_resume > 0) { + uint8_t saved_hash[VBOOT_MAX_HASH_SIZE]; + const size_t saved_hash_sz = sizeof(saved_hash); + + assert(slot_hash_sz == saved_hash_sz); + + printk(BIOS_DEBUG, "Platform is resuming.\n"); + + if (vboot_retrieve_hash(saved_hash, saved_hash_sz)) { + printk(BIOS_ERR, "Couldn't retrieve saved hash.\n"); + return -1; + } + + if (memcmp(saved_hash, slot_hash, slot_hash_sz)) { + printk(BIOS_ERR, "Hash mismatch on resume.\n"); + return -1; + } + } else if (is_resume < 0) + printk(BIOS_ERR, "Unable to determine if platform resuming.\n"); + + printk(BIOS_DEBUG, "Saving vboot hash.\n"); + + /* Always save the hash for the current boot. */ + if (vboot_save_hash(slot_hash, slot_hash_sz)) { + printk(BIOS_ERR, "Error saving vboot hash.\n"); + /* Though this is an error don't report it up since it could + * 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 0; +} + static int hash_body(struct vb2_context *ctx, struct region_device *fw_main) { uint64_t load_ts; uint32_t expected_size; uint8_t block[TODO_BLOCK_SIZE]; + uint8_t hash_digest[VBOOT_MAX_HASH_SIZE]; + const size_t hash_digest_sz = sizeof(hash_digest); size_t block_size = sizeof(block); size_t offset; int rv; + /* Clear the full digest so that any hash digests less than the + * max have trailing zeros. */ + memset(hash_digest, 0, hash_digest_sz); + /* * Since loading the firmware and calculating its hash is intertwined, * we use this little trick to measure them separately and pretend it @@ -160,12 +225,15 @@ static int hash_body(struct vb2_context *ctx, struct region_device *fw_main) timestamp_add_now(TS_DONE_HASHING); /* Check the result (with RSA signature verification) */ - rv = vb2api_check_hash(ctx); + rv = vb2api_check_hash_get_digest(ctx, hash_digest, hash_digest_sz); if (rv) return rv; timestamp_add_now(TS_END_HASH_BODY); + if (handle_digest_result(hash_digest, hash_digest_sz)) + return VB2_ERROR_UNKNOWN; + return VB2_SUCCESS; } diff --git a/src/vendorcode/google/chromeos/vboot_common.h b/src/vendorcode/google/chromeos/vboot_common.h index fbffc29d54..a658d62ab4 100644 --- a/src/vendorcode/google/chromeos/vboot_common.h +++ b/src/vendorcode/google/chromeos/vboot_common.h @@ -46,6 +46,24 @@ int vboot_recovery_reason(void); void vboot_reboot(void); +/* + * Save the provided hash digest to a secure location to check against in + * the resume path. Returns 0 on success, < 0 on error. + */ +int vboot_save_hash(void *digest, size_t digest_size); + +/* + * Retrieve the previously saved hash digest. Returns 0 on success, + * < 0 on error. + */ +int vboot_retrieve_hash(void *digest, size_t digest_size); + +/* + * Determine if the platform is resuming from suspend. Returns 0 when + * not resuming, > 0 if resuming, and < 0 on error. + */ +int vboot_platform_is_resuming(void); + /* Main logic for verified boot. verstage() is the stage entry point * while the verstage_main() is just the core logic. */ void verstage_main(void); |