diff options
author | Randall Spangler <rspangler@chromium.org> | 2012-12-10 09:43:49 -0800 |
---|---|---|
committer | Gerrit <chrome-bot@google.com> | 2012-12-10 15:14:38 -0800 |
commit | ad2adc4022c24ea8f883ab2ae61b0a6989743d56 (patch) | |
tree | c701ea92f8d7ea9f1cbf1d18630885e41c4baf8a /common/vboot_hash.c | |
parent | c26a242e947a110ea3cf0c43d8274eebb9aaeb5a (diff) | |
download | chrome-ec-ad2adc4022c24ea8f883ab2ae61b0a6989743d56.tar.gz |
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 <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/39484
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Diffstat (limited to 'common/vboot_hash.c')
-rw-r--r-- | common/vboot_hash.c | 50 |
1 files changed, 42 insertions, 8 deletions
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; |