diff options
Diffstat (limited to 'firmware/2lib/2ec_sync.c')
-rw-r--r-- | firmware/2lib/2ec_sync.c | 103 |
1 files changed, 71 insertions, 32 deletions
diff --git a/firmware/2lib/2ec_sync.c b/firmware/2lib/2ec_sync.c index cba6782e..1871b50c 100644 --- a/firmware/2lib/2ec_sync.c +++ b/firmware/2lib/2ec_sync.c @@ -9,10 +9,12 @@ #include "2common.h" #include "2misc.h" #include "2nvstorage.h" +#include "2secdata.h" #include "2sysincludes.h" #include "vboot_api.h" #include "vboot_display.h" #include "vboot_kernel.h" +#include "vboot_test.h" #define SYNC_FLAG(select) \ ((select) == VB_SELECT_FIRMWARE_READONLY ? \ @@ -61,12 +63,9 @@ static vb2_error_t protect_ec(struct vb2_context *ctx, * @param hash_size Size of the hash in bytes * @param desc Description of what's being hashed */ -static void print_hash(const uint8_t *hash, uint32_t hash_size, - const char *desc) +static void print_hash(const uint8_t *hash, uint32_t hash_size) { int i; - - VB2_DEBUG("%s hash: ", desc); for (i = 0; i < hash_size; i++) VB2_DEBUG_RAW("%02x", hash[i]); VB2_DEBUG_RAW("\n"); @@ -97,36 +96,70 @@ static vb2_error_t check_ec_hash(struct vb2_context *ctx, enum vb2_firmware_selection select) { struct vb2_shared_data *sd = vb2_get_sd(ctx); + const uint8_t *hexp = NULL; + const uint8_t *hmir = NULL; + const uint8_t *heff = NULL; + int hexp_len, heff_len; + const int hmir_len = VB2_SHA256_DIGEST_SIZE; + vb2_error_t rv; - /* Get current EC hash. */ - const uint8_t *ec_hash = NULL; - int ec_hash_size; - vb2_error_t rv = vb2ex_ec_hash_image(select, &ec_hash, &ec_hash_size); + /* + * Get expected EC hash and length. + */ + rv = vb2ex_ec_get_expected_image_hash(select, &hexp, &hexp_len); + if (rv) { + VB2_DEBUG("vb2ex_ec_get_expected_image_hash() returned %#x\n", + rv); + request_recovery(ctx, VB2_RECOVERY_EC_EXPECTED_HASH); + return VB2_ERROR_EC_HASH_EXPECTED; + } + VB2_DEBUG("Hexp %10s: ", image_name_to_string(select)); + print_hash(hexp, hexp_len); + + /* + * Get mirrored EC hash. This returns NULL on old systems. On new + * systems without EFS2, Hmir will be updated but unused. + * + * If it's called from update_ec, Hmir and Hexp are already synced. + */ + hmir = vb2_secdata_kernel_get_ec_hash(ctx); + if (hmir && select == VB_SELECT_FIRMWARE_EC_ACTIVE) { + VB2_DEBUG(" %10s: ", "Hmir"); + print_hash(hmir, hmir_len); + if (hmir_len != hexp_len) { + VB2_DEBUG("Hmir size (%d) != Hexp size (%d)\n", + hmir_len, hexp_len); + request_recovery(ctx, VB2_RECOVERY_EC_HASH_SIZE); + return VB2_ERROR_EC_HASH_SIZE; + } + if (vb2_safe_memcmp(hmir, hexp, hexp_len)) { + VB2_DEBUG("Hmir != Hexp. Update Hmir.\n"); + vb2_secdata_kernel_set_ec_hash(ctx, hexp); + } + } + + /* + * Get effective EC hash and length. + */ + rv = vb2ex_ec_hash_image(select, &heff, &heff_len); if (rv) { VB2_DEBUG("vb2ex_ec_hash_image() returned %#x\n", rv); request_recovery(ctx, VB2_RECOVERY_EC_HASH_FAILED); return VB2_ERROR_EC_HASH_IMAGE; } - print_hash(ec_hash, ec_hash_size, image_name_to_string(select)); + VB2_DEBUG("Heff %10s: ", image_name_to_string(select)); + print_hash(heff, heff_len); - /* Get expected EC hash. */ - const uint8_t *hash = NULL; - int hash_size; - rv = vb2ex_ec_get_expected_image_hash(select, &hash, &hash_size); - if (rv) { - VB2_DEBUG("vb2ex_ec_get_expected_image_hash() returned %#x\n", rv); - request_recovery(ctx, VB2_RECOVERY_EC_EXPECTED_HASH); - return VB2_ERROR_EC_HASH_EXPECTED; - } - if (ec_hash_size != hash_size) { - VB2_DEBUG("EC uses %d-byte hash, but AP-RW contains %d bytes\n", - ec_hash_size, hash_size); + /* Lengths should match. */ + if (heff_len != hexp_len) { + VB2_DEBUG("EC uses %d-byte hash but AP-RW contains %d bytes\n", + heff_len, hexp_len); request_recovery(ctx, VB2_RECOVERY_EC_HASH_SIZE); return VB2_ERROR_EC_HASH_SIZE; } - if (vb2_safe_memcmp(ec_hash, hash, hash_size)) { - print_hash(hash, hash_size, "Expected"); + if (vb2_safe_memcmp(heff, hexp, hexp_len)) { + VB2_DEBUG("Heff != Hexp. Schedule update\n"); sd->flags |= SYNC_FLAG(select); } @@ -177,6 +210,8 @@ static vb2_error_t update_ec(struct vb2_context *ctx, return VBERROR_EC_REBOOT_TO_RO_REQUIRED; } + VB2_DEBUG("Updated %s successfully\n", image_name_to_string(select)); + return VB2_SUCCESS; } @@ -226,21 +261,23 @@ static vb2_error_t sync_ec(struct vb2_context *ctx) const enum vb2_firmware_selection select_rw = EC_EFS ? VB_SELECT_FIRMWARE_EC_UPDATE : VB_SELECT_FIRMWARE_EC_ACTIVE; - VB2_DEBUG("select_rw=%d\n", select_rw); + VB2_DEBUG("select_rw=%s\n", image_name_to_string(select_rw)); /* Update the RW Image */ if (sd->flags & SYNC_FLAG(select_rw)) { if (VB2_SUCCESS != update_ec(ctx, select_rw)) return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - /* Updated successfully. Cold reboot to switch to the new RW. - * TODO: Switch slot and proceed if EC is still in RO. */ - if (EC_EFS) { + /* Updated successfully. Cold reboot to switch to the new RW. */ + if (ctx->flags & VB2_CONTEXT_NO_BOOT) { VB2_DEBUG("Rebooting to jump to new EC-RW\n"); + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } else if (EC_EFS) { + VB2_DEBUG("Rebooting to switch to new EC-RW\n"); return VBERROR_EC_REBOOT_TO_SWITCH_RW; } } - /* Tell EC to jump to its RW image */ + /* Tell EC to jump to RW. It should already be in RW for EFS2. */ if (!(sd->flags & VB2_SD_FLAG_ECSYNC_EC_IN_RW)) { VB2_DEBUG("jumping to EC-RW\n"); rv = vb2ex_ec_jump_to_rw(); @@ -344,9 +381,10 @@ static vb2_error_t ec_sync_phase1(struct vb2_context *ctx) if (check_ec_active(ctx)) return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - /* Check if we need to update RW. Failures trigger recovery mode. */ + /* Check if we need to update RW. Failures trigger recovery mode. */ if (check_ec_hash(ctx, VB_SELECT_FIRMWARE_EC_ACTIVE)) return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + /* See if we need to update EC-RO. */ if (vb2_nv_get(ctx, VB2_NV_TRY_RO_SYNC) && check_ec_hash(ctx, VB_SELECT_FIRMWARE_READONLY)) { @@ -360,7 +398,7 @@ static vb2_error_t ec_sync_phase1(struct vb2_context *ctx) * If EC supports RW-A/B slots, we can proceed but we need * to jump to the new RW version later. */ - if ((sd->flags & VB2_SD_FLAG_ECSYNC_EC_RW) && + if ((sd->flags & SYNC_FLAG(VB_SELECT_FIRMWARE_EC_ACTIVE)) && (sd->flags & VB2_SD_FLAG_ECSYNC_EC_IN_RW) && !EC_EFS) { return VBERROR_EC_REBOOT_TO_RO_REQUIRED; } @@ -382,8 +420,9 @@ static int ec_will_update_slowly(struct vb2_context *ctx) { struct vb2_shared_data *sd = vb2_get_sd(ctx); - return (((sd->flags & VB2_SD_FLAG_ECSYNC_EC_RO) || - (sd->flags & VB2_SD_FLAG_ECSYNC_EC_RW)) && EC_SLOW_UPDATE); + return (((sd->flags & SYNC_FLAG(VB_SELECT_FIRMWARE_READONLY)) || + (sd->flags & SYNC_FLAG(VB_SELECT_FIRMWARE_EC_ACTIVE))) + && EC_SLOW_UPDATE); } /** |