From ad2adc4022c24ea8f883ab2ae61b0a6989743d56 Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Mon, 10 Dec 2012 09:43:49 -0800 Subject: Invalidate hash if flash operation changes the hashed region This prevents the EC from returning a stale hash. BUG=chrome-os-partner:16668 BRANCH=link,snow TEST=manual, with WP disabled From EC console - Boot system and wait a second - hash --> prints valid hash - flasherase 0x20000 0x1000 - hash --> invalid - hash rw - hash --> prints valid hash - flashwrite 0x20000 0x1000 - hash --> invalid - hash rw - flasherase 0x38000 0x1000 - flashwrite 0x38000 0x1000 - hash --> still valid (since 0x38000 is outside the rw section) From root shell - ectool hash --> prints valid hash - ectool flasherase 0x20000 0x1000 - ectool hash --> invalid - ectool hash recalc RW - ectool hash --> prints valid hash - echo 'Making a hash of this' > /tmp/hashofthis - ectool flashwrite 0x20000 /tmp/hashofthis - ectool hash --> invalid - ectool hash recalc RW - ectool flasherase 0x38000 0x1000 - ectool flashwrite 0x38000 /tmp/hashofthis - ectool hash --> still valid (since 0x38000 is outside the rw section) Change-Id: Id915a504a7bc70b8b8c339b5ce55dc5bad5838fe Signed-off-by: Randall Spangler Reviewed-on: https://gerrit.chromium.org/gerrit/39484 Reviewed-by: Bill Richardson --- common/vboot_hash.c | 50 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) (limited to 'common/vboot_hash.c') diff --git a/common/vboot_hash.c b/common/vboot_hash.c index 8174455fa5..68b9876522 100644 --- a/common/vboot_hash.c +++ b/common/vboot_hash.c @@ -80,11 +80,17 @@ static int vboot_hash_start(uint32_t offset, uint32_t size, return EC_SUCCESS; } -/* Abort hash currently in progress, if any. */ +/* Abort hash currently in progress, and invalidate any completed hash. */ static void vboot_hash_abort(void) { - if (in_progress) + if (in_progress) { want_abort = 1; + } else { + CPRINTF("[%T hash abort]\n"); + want_abort = 0; + data_size = 0; + hash = NULL; + } } static void vboot_hash_init(void) @@ -112,6 +118,26 @@ static void vboot_hash_init(void) } } +int vboot_hash_invalidate(int offset, int size) +{ + /* Don't invalidate if passed an invalid region */ + if (offset < 0 || size <= 0 || offset + size < 0) + return 0; + + /* Don't invalidate if hash is already invalid */ + if (!hash) + return 0; + + /* No overlap if passed region is off either end of hashed region */ + if (offset + size <= data_offset || offset >= data_offset + data_size) + return 0; + + /* Invalidate the hash */ + CPRINTF("[%T hash invalidated 0x%08x 0x%08x]\n", offset, size); + vboot_hash_abort(); + return 1; +} + void vboot_hash_task(void) { vboot_hash_init(); @@ -122,10 +148,8 @@ void vboot_hash_task(void) task_wait_event(-1); } else if (want_abort) { /* Abort hash computation currently in progress */ - CPRINTF("[%T hash abort]\n"); - data_size = 0; - want_abort = 0; in_progress = 0; + vboot_hash_abort(); } else { /* Compute the next chunk of hash */ int size = MIN(CHUNK_SIZE, data_size - curr_pos); @@ -136,10 +160,16 @@ void vboot_hash_task(void) size); curr_pos += size; if (curr_pos >= data_size) { + /* Store the final hash */ hash = SHA256_final(&ctx); CPRINTF("[%T hash done %.*h]\n", SHA256_DIGEST_SIZE, hash); + in_progress = 0; + + /* Handle receiving abort during finalize */ + if (want_abort) + vboot_hash_abort(); } /* @@ -189,10 +219,14 @@ static int command_hash(int argc, char **argv) ccprintf("Offset: 0x%08x\n", data_offset); ccprintf("Size: 0x%08x (%d)\n", data_size, data_size); ccprintf("Digest: "); - if (in_progress) + if (want_abort) + ccprintf("(aborting)\n"); + else if (in_progress) ccprintf("(in progress)\n"); - else + else if (hash) ccprintf("%.*h\n", SHA256_DIGEST_SIZE, hash); + else + ccprintf("(invalid)\n"); return EC_SUCCESS; } @@ -248,7 +282,7 @@ static void fill_response(struct ec_response_vboot_hash *r) { if (in_progress) r->status = EC_VBOOT_HASH_STATUS_BUSY; - else if (hash) { + else if (hash && !want_abort) { r->status = EC_VBOOT_HASH_STATUS_DONE; r->hash_type = EC_VBOOT_HASH_TYPE_SHA256; r->digest_size = SHA256_DIGEST_SIZE; -- cgit v1.2.1