summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Durbin <adurbin@chromium.org>2016-01-22 15:26:04 -0600
committerPatrick Georgi <pgeorgi@google.com>2016-02-04 17:34:00 +0100
commit87c9faeb4c7a94b2de1b2cf44d8db1383909ccc2 (patch)
treeea1d0ceffe0fa1c4270a389eb1b6f89e61d9209f
parent43e6d6a1247768bbf5c42664c1bdb7d478f05808 (diff)
chromeos/vboot: provide support for x86 memory init verification
For x86 systems which resume through the reset vector one needs to ensure the the RW slot taken at resume time matches the one at boot time. The reason is that any assets pulled out of the boot media need to match how the platform previously booted. To do that one needs obtain the hash digest of the chosen slot, and it needs to be saved in a secure place on the normal boot path. On resume one needs to retrieve the hash digest back to compare it with the chosen slot. If they don't match resuming won't be possible. BUG=chrome-os-partner:46049 BRANCH=glados TEST=Suspended and resumed on chell. Also, tested with an EC build which returns a bad hash to ensure that is properly caught. CQ-DEPEND=CL:323460 Change-Id: I90ce26813b67f46913aa4026b42d9490a564bb6c Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Original-Commit-Id: 01a42c0ecfc6d60d1d2e5e36a86781d91d5c47a9 Original-Change-Id: I6c6bdce7e06712bc06cc620a3d7a6a6250c59c95 Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org> Original-Reviewed-on: https://chromium-review.googlesource.com/323500 Original-Reviewed-by: Patrick Georgi <pgeorgi@chromium.org> Original-Reviewed-by: Duncan Laurie <dlaurie@chromium.org> Reviewed-on: https://review.coreboot.org/13574 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
-rw-r--r--src/Kconfig9
-rw-r--r--src/vendorcode/google/chromeos/vboot2/vboot_logic.c70
-rw-r--r--src/vendorcode/google/chromeos/vboot_common.h18
3 files changed, 96 insertions, 1 deletions
diff --git a/src/Kconfig b/src/Kconfig
index 3f02843f6f..feefc918c5 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -503,6 +503,15 @@ config HAVE_ACPI_RESUME
bool
default n
+config RESUME_PATH_SAME_AS_BOOT
+ bool
+ default y if ARCH_X86
+ depends on HAVE_ACPI_RESUME
+ help
+ This option indicates that when a system resumes it takes the
+ same path as a regular boot. e.g. an x86 system runs from the
+ reset vector at 0xfffffff0 on both resume and warm/cold boot.
+
config HAVE_HARD_RESET
bool
default n
diff --git a/src/vendorcode/google/chromeos/vboot2/vboot_logic.c b/src/vendorcode/google/chromeos/vboot2/vboot_logic.c
index b72de93245..0d08d6adb2 100644
--- a/src/vendorcode/google/chromeos/vboot2/vboot_logic.c
+++ b/src/vendorcode/google/chromeos/vboot2/vboot_logic.c
@@ -26,6 +26,9 @@
#include "../chromeos.h"
#include "misc.h"
+/* The max hash size to expect is for SHA512. */
+#define VBOOT_MAX_HASH_SIZE VB2_SHA512_DIGEST_SIZE
+
#define TODO_BLOCK_SIZE 1024
static int is_slot_a(struct vb2_context *ctx)
@@ -111,15 +114,77 @@ int vb2ex_hwcrypto_digest_finalize(uint8_t *digest, uint32_t digest_size)
return VB2_ERROR_UNKNOWN;
}
+static int handle_digest_result(void *slot_hash, size_t slot_hash_sz)
+{
+ int is_resume;
+
+ /*
+ * Nothing to do since resuming on the platform doesn't require
+ * vboot verification again.
+ */
+ if (!IS_ENABLED(CONFIG_RESUME_PATH_SAME_AS_BOOT))
+ return 0;
+
+ /*
+ * Assume that if vboot doesn't start in bootblock verified
+ * RW memory init code is not employed. i.e. memory init code
+ * lives in RO CBFS.
+ */
+ if (!IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
+ return 0;
+
+ is_resume = vboot_platform_is_resuming();
+
+ if (is_resume > 0) {
+ uint8_t saved_hash[VBOOT_MAX_HASH_SIZE];
+ const size_t saved_hash_sz = sizeof(saved_hash);
+
+ assert(slot_hash_sz == saved_hash_sz);
+
+ printk(BIOS_DEBUG, "Platform is resuming.\n");
+
+ if (vboot_retrieve_hash(saved_hash, saved_hash_sz)) {
+ printk(BIOS_ERR, "Couldn't retrieve saved hash.\n");
+ return -1;
+ }
+
+ if (memcmp(saved_hash, slot_hash, slot_hash_sz)) {
+ printk(BIOS_ERR, "Hash mismatch on resume.\n");
+ return -1;
+ }
+ } else if (is_resume < 0)
+ printk(BIOS_ERR, "Unable to determine if platform resuming.\n");
+
+ printk(BIOS_DEBUG, "Saving vboot hash.\n");
+
+ /* Always save the hash for the current boot. */
+ if (vboot_save_hash(slot_hash, slot_hash_sz)) {
+ printk(BIOS_ERR, "Error saving vboot hash.\n");
+ /* Though this is an error don't report it up since it could
+ * lead to a reboot loop. The consequence of this is that
+ * we will most likely fail resuming because of EC issues or
+ * the hash digest not matching. */
+ return 0;
+ }
+
+ return 0;
+}
+
static int hash_body(struct vb2_context *ctx, struct region_device *fw_main)
{
uint64_t load_ts;
uint32_t expected_size;
uint8_t block[TODO_BLOCK_SIZE];
+ uint8_t hash_digest[VBOOT_MAX_HASH_SIZE];
+ const size_t hash_digest_sz = sizeof(hash_digest);
size_t block_size = sizeof(block);
size_t offset;
int rv;
+ /* Clear the full digest so that any hash digests less than the
+ * max have trailing zeros. */
+ memset(hash_digest, 0, hash_digest_sz);
+
/*
* Since loading the firmware and calculating its hash is intertwined,
* we use this little trick to measure them separately and pretend it
@@ -160,12 +225,15 @@ static int hash_body(struct vb2_context *ctx, struct region_device *fw_main)
timestamp_add_now(TS_DONE_HASHING);
/* Check the result (with RSA signature verification) */
- rv = vb2api_check_hash(ctx);
+ rv = vb2api_check_hash_get_digest(ctx, hash_digest, hash_digest_sz);
if (rv)
return rv;
timestamp_add_now(TS_END_HASH_BODY);
+ if (handle_digest_result(hash_digest, hash_digest_sz))
+ return VB2_ERROR_UNKNOWN;
+
return VB2_SUCCESS;
}
diff --git a/src/vendorcode/google/chromeos/vboot_common.h b/src/vendorcode/google/chromeos/vboot_common.h
index fbffc29d54..a658d62ab4 100644
--- a/src/vendorcode/google/chromeos/vboot_common.h
+++ b/src/vendorcode/google/chromeos/vboot_common.h
@@ -46,6 +46,24 @@ int vboot_recovery_reason(void);
void vboot_reboot(void);
+/*
+ * Save the provided hash digest to a secure location to check against in
+ * the resume path. Returns 0 on success, < 0 on error.
+ */
+int vboot_save_hash(void *digest, size_t digest_size);
+
+/*
+ * Retrieve the previously saved hash digest. Returns 0 on success,
+ * < 0 on error.
+ */
+int vboot_retrieve_hash(void *digest, size_t digest_size);
+
+/*
+ * Determine if the platform is resuming from suspend. Returns 0 when
+ * not resuming, > 0 if resuming, and < 0 on error.
+ */
+int vboot_platform_is_resuming(void);
+
/* Main logic for verified boot. verstage() is the stage entry point
* while the verstage_main() is just the core logic. */
void verstage_main(void);