diff options
author | Randall Spangler <rspangler@chromium.org> | 2013-02-04 15:00:09 -0800 |
---|---|---|
committer | ChromeBot <chrome-bot@google.com> | 2013-02-06 17:38:03 -0800 |
commit | 5ca4ea087a3d67c2a639e8b9254f51f076bf85fa (patch) | |
tree | bd5de84d148b867c9cb342815bb2cf858c45557b /firmware | |
parent | 9a8e79cc2642381b24078b5ebb2dff7558f10c62 (diff) | |
download | vboot-5ca4ea087a3d67c2a639e8b9254f51f076bf85fa.tar.gz |
EC software sync uses precomputed hash if available
This removes the need to load the EC code at all when the precomputed
hash matches.
BUG=chrome-os-partner:17606
BRANCH=spring
TEST=wouldn't that be nice
Change-Id: If4438b9db8b1449b8fd4d90ef3acb3bbec5e09a0
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/42567
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/include/vboot_nvstorage.h | 4 | ||||
-rw-r--r-- | firmware/lib/vboot_api_kernel.c | 98 | ||||
-rw-r--r-- | firmware/lib/vboot_display.c | 6 | ||||
-rw-r--r-- | firmware/stub/vboot_api_stub.c | 13 |
4 files changed, 102 insertions, 19 deletions
diff --git a/firmware/include/vboot_nvstorage.h b/firmware/include/vboot_nvstorage.h index 890af4b6..943a5664 100644 --- a/firmware/include/vboot_nvstorage.h +++ b/firmware/include/vboot_nvstorage.h @@ -142,6 +142,10 @@ typedef enum VbNvParam { #define VBNV_RECOVERY_EC_JUMP_RW 0x27 /* EC software sync - unable to protect / unprotect EC-RW */ #define VBNV_RECOVERY_EC_PROTECT 0x28 +/* EC software sync - error obtaining expected EC hash */ +#define VBNV_RECOVERY_EC_EXPECTED_HASH 0x29 +/* EC software sync - expected EC image doesn't match hash */ +#define VBNV_RECOVERY_EC_HASH_MISMATCH 0x2A /* Unspecified/unknown error in read-only firmware */ #define VBNV_RECOVERY_RO_UNSPECIFIED 0x3F /* diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index 3a385d2d..c7213ede 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -555,12 +555,14 @@ VbError_t VbEcSoftwareSync(VbCommonParams *cparams) (VbSharedDataHeader *)cparams->shared_data_blob; int in_rw = 0; int rv; - const uint8_t *ec_hash; + const uint8_t *ec_hash = NULL; int ec_hash_size; - const uint8_t *expected; + const uint8_t *rw_hash = NULL; + int rw_hash_size; + const uint8_t *expected = NULL; int expected_size; uint8_t expected_hash[SHA256_DIGEST_SIZE]; - int need_update; + int need_update = 0; int i; /* Determine whether the EC is in RO or RW */ @@ -660,29 +662,87 @@ VbError_t VbEcSoftwareSync(VbCommonParams *cparams) VBDEBUG(("\n")); /* - * Get expected EC-RW code. Note that we've already checked for + * Get expected EC-RW hash. Note that we've already checked for * RO_NORMAL, so we know that the BIOS must be RW-A or RW-B, and * therefore the EC must match. */ - rv = VbExEcGetExpectedRW(shared->firmware_index ? + rv = VbExEcGetExpectedRWHash(shared->firmware_index ? VB_SELECT_FIRMWARE_B : VB_SELECT_FIRMWARE_A, - &expected, &expected_size); - if (rv) { + &rw_hash, &rw_hash_size); + + if (rv == VBERROR_EC_GET_EXPECTED_HASH_FROM_IMAGE) { + /* + * BIOS has verified EC image but doesn't have a precomputed + * hash for it, so we must compute the hash ourselves. + */ + rw_hash = NULL; + } else if (rv) { VBDEBUG(("VbEcSoftwareSync() - " - "VbExEcGetExpectedRW() returned %d\n", rv)); - VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_IMAGE); + "VbExEcGetExpectedRWHash() returned %d\n", rv)); + VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH); + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } else if (rw_hash_size != SHA256_DIGEST_SIZE) { + VBDEBUG(("VbEcSoftwareSync() - " + "VbExEcGetExpectedRWHash() says size %d, not %d\n", + rw_hash_size, SHA256_DIGEST_SIZE)); + VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH); return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } else { + VBDEBUG(("Expected hash:")); + for (i = 0; i < SHA256_DIGEST_SIZE; i++) + VBDEBUG(("%02x", rw_hash[i])); + VBDEBUG(("\n")); + + need_update = SafeMemcmp(ec_hash, rw_hash, SHA256_DIGEST_SIZE); } - VBDEBUG(("VbEcSoftwareSync() - expected len = %d\n", expected_size)); - /* Hash expected code */ - internal_SHA256(expected, expected_size, expected_hash); - VBDEBUG(("Expected hash:")); - for (i = 0; i < SHA256_DIGEST_SIZE; i++) - VBDEBUG(("%02x", expected_hash[i])); - VBDEBUG(("\n")); + /* + * Get expected EC-RW image if we're sure we need to update (because the + * expected hash didn't match the EC) or we still don't know (because + * there was no expected hash and we need the image to compute one + * ourselves). + */ + if (need_update || !rw_hash) { + /* Get expected EC-RW image */ + rv = VbExEcGetExpectedRW(shared->firmware_index ? + VB_SELECT_FIRMWARE_B : + VB_SELECT_FIRMWARE_A, + &expected, &expected_size); + if (rv) { + VBDEBUG(("VbEcSoftwareSync() - " + "VbExEcGetExpectedRW() returned %d\n", rv)); + VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_IMAGE); + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } + VBDEBUG(("VbEcSoftwareSync() - expected len = %d\n", + expected_size)); + + /* Hash expected image */ + internal_SHA256(expected, expected_size, expected_hash); + VBDEBUG(("Computed hash of expected image:")); + for (i = 0; i < SHA256_DIGEST_SIZE; i++) + VBDEBUG(("%02x", expected_hash[i])); + VBDEBUG(("\n")); + } - need_update = SafeMemcmp(ec_hash, expected_hash, SHA256_DIGEST_SIZE); + if (!rw_hash) { + /* + * BIOS didn't have expected EC hash, so check if we need + * update by comparing EC hash to the one we just computed. + */ + need_update = SafeMemcmp(ec_hash, expected_hash, + SHA256_DIGEST_SIZE); + } else if (need_update && + SafeMemcmp(rw_hash, expected_hash, SHA256_DIGEST_SIZE)) { + /* + * We need to update, but the expected EC image doesn't match + * the expected EC hash we were given. + */ + VBDEBUG(("VbEcSoftwareSync() - " + "VbExEcGetExpectedRW() returned %d\n", rv)); + VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_MISMATCH); + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } /* * TODO: GBB flag to override whether we need update; needed for EC @@ -692,7 +752,7 @@ VbError_t VbEcSoftwareSync(VbCommonParams *cparams) if (in_rw) { if (need_update) { /* - * EC is running the wrong RW code. Reboot the EC to + * EC is running the wrong RW image. Reboot the EC to * RO so we can update it on the next boot. */ VBDEBUG(("VbEcSoftwareSync() - " @@ -747,7 +807,7 @@ VbError_t VbEcSoftwareSync(VbCommonParams *cparams) if (rv != VBERROR_SUCCESS) return rv; - /* Tell EC to jump to its RW code */ + /* Tell EC to jump to its RW image */ VBDEBUG(("VbEcSoftwareSync() jumping to EC-RW\n")); rv = VbExEcJumpToRW(); if (rv != VBERROR_SUCCESS) { diff --git a/firmware/lib/vboot_display.c b/firmware/lib/vboot_display.c index b5488486..bd86d654 100644 --- a/firmware/lib/vboot_display.c +++ b/firmware/lib/vboot_display.c @@ -497,6 +497,12 @@ const char *RecoveryReasonString(uint8_t code) case VBNV_RECOVERY_EC_EXPECTED_IMAGE: return "EC software sync error " "obtaining expected EC image from BIOS"; + case VBNV_RECOVERY_EC_EXPECTED_HASH: + return "EC software sync error " + "obtaining expected EC hash from BIOS"; + case VBNV_RECOVERY_EC_HASH_MISMATCH: + return "EC software sync error " + "comparing expected EC hash and image"; case VBNV_RECOVERY_EC_UPDATE: return "EC software sync error updating EC"; case VBNV_RECOVERY_EC_JUMP_RW: diff --git a/firmware/stub/vboot_api_stub.c b/firmware/stub/vboot_api_stub.c index 8521db0e..dd0d5d4b 100644 --- a/firmware/stub/vboot_api_stub.c +++ b/firmware/stub/vboot_api_stub.c @@ -181,6 +181,19 @@ VbError_t VbExEcGetExpectedRW(enum VbSelectFirmware_t select, return VBERROR_SUCCESS; } +/** + * Read the SHA-256 hash of the expected contents of the EC image associated + * with the main firmware specified by the "select" argument. + */ +VbError_t VbExEcGetExpectedRWHash(enum VbSelectFirmware_t select, + const uint8_t **hash, int *hash_size) { + static const uint8_t fake_hash[32] = {1, 2, 3, 4}; + + *hash = fake_hash; + *hash_size = sizeof(fake_hash); + return VBERROR_SUCCESS; +} + VbError_t VbExEcUpdateRW(const uint8_t *image, int image_size) { return VBERROR_SUCCESS; } |