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 | |
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>
-rw-r--r-- | common/flash_common.c | 9 | ||||
-rw-r--r-- | common/vboot_hash.c | 50 | ||||
-rw-r--r-- | include/vboot_hash.h | 23 |
3 files changed, 74 insertions, 8 deletions
diff --git a/common/flash_common.c b/common/flash_common.c index 6afa4adc6e..11cb8150f3 100644 --- a/common/flash_common.c +++ b/common/flash_common.c @@ -13,6 +13,7 @@ #include "shared_mem.h" #include "system.h" #include "util.h" +#include "vboot_hash.h" int flash_dataptr(int offset, int size_req, int align, char **ptrp) { @@ -48,6 +49,10 @@ int flash_write(int offset, int size, const char *data) if (flash_dataptr(offset, size, CONFIG_FLASH_WRITE_SIZE, NULL) < 0) return EC_ERROR_INVAL; /* Invalid range */ +#ifdef CONFIG_TASK_VBOOTHASH + vboot_hash_invalidate(offset, size); +#endif + return flash_physical_write(offset, size, data); } @@ -56,6 +61,10 @@ int flash_erase(int offset, int size) if (flash_dataptr(offset, size, CONFIG_FLASH_ERASE_SIZE, NULL) < 0) return EC_ERROR_INVAL; /* Invalid range */ +#ifdef CONFIG_TASK_VBOOTHASH + vboot_hash_invalidate(offset, size); +#endif + return flash_physical_erase(offset, size); } 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; diff --git a/include/vboot_hash.h b/include/vboot_hash.h new file mode 100644 index 0000000000..002282b346 --- /dev/null +++ b/include/vboot_hash.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Verified boot hashing memory module for Chrome EC */ + +#ifndef __CROS_EC_VBOOT_HASH_H +#define __CROS_EC_VBOOT_HASH_H + +#include "common.h" + +/** + * Invalidate the hash if the hashed data overlaps the specified region. + * + * @param offset Region start offset in flash + * @param size Size of region in bytes + * + * @return non-zero if the region overlapped the hashed region. + */ +int vboot_hash_invalidate(int offset, int size); + +#endif /* __CROS_EC_VBOOT_HASH_H */ |