summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-12-10 09:43:49 -0800
committerGerrit <chrome-bot@google.com>2012-12-10 15:14:38 -0800
commitad2adc4022c24ea8f883ab2ae61b0a6989743d56 (patch)
treec701ea92f8d7ea9f1cbf1d18630885e41c4baf8a
parentc26a242e947a110ea3cf0c43d8274eebb9aaeb5a (diff)
downloadchrome-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.c9
-rw-r--r--common/vboot_hash.c50
-rw-r--r--include/vboot_hash.h23
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 */