summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2012-05-16 10:04:38 -0700
committerGerrit <chrome-bot@google.com>2012-05-17 09:21:50 -0700
commitfeac077c1d96d81f9c1c0b5253d0223b0a2d9448 (patch)
treebbc7c7346a37a9f78fd7d03e852a3df987ca180e /firmware
parentf63ab219c5ee858a89ec0f33ad12536eff813bb2 (diff)
downloadvboot-feac077c1d96d81f9c1c0b5253d0223b0a2d9448.tar.gz
Add checksum to TPM RollbackSpace regions for FW and kernel.
BUG=chrome-os-partner:9707 TEST=manual make make runtests You can also test it by clearing the TPM, then manually looking at the TPM regions. In dev-mode, clear the regions and you'll see something like this: localhost ~ # tpmc read 1007 a 1 0 0 0 0 0 0 0 0 0 localhost ~ # tpmc read 1008 d 1 4c 57 52 47 0 0 0 0 0 0 0 0 localhost ~ # Go back to normal mode and reboot, and you'll see something like this: localhost ~ # tpmc read 1007 a 2 0 1 0 1 0 0 0 0 4f localhost ~ # tpmc read 1008 d 2 4c 57 52 47 1 0 1 0 0 0 0 55 localhost ~ # The important things are that the first number is now 2, instead of 1, and the last number is not zero (it's a checksum, so it'll vary depending on the other numbers, which will themselves vary according to the firmware and kernel versions). Change-Id: Ia4040311c2a4b2819792549b883377c8b6b89d48 Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/22856 Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'firmware')
-rw-r--r--firmware/Makefile1
-rw-r--r--firmware/include/sysincludes.h1
-rw-r--r--firmware/lib/crc8.c28
-rw-r--r--firmware/lib/include/crc8.h13
-rw-r--r--firmware/lib/include/rollback_index.h10
-rw-r--r--firmware/lib/rollback_index.c132
-rw-r--r--firmware/lib/vboot_nvstorage.c21
7 files changed, 170 insertions, 36 deletions
diff --git a/firmware/Makefile b/firmware/Makefile
index 8ea647e2..811c158b 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -62,6 +62,7 @@ LIB_SRCS = \
./lib/cgptlib/cgptlib.c \
./lib/cgptlib/cgptlib_internal.c \
./lib/cgptlib/crc32.c \
+ ./lib/crc8.c \
./lib/cryptolib/padding.c \
./lib/cryptolib/rsa.c \
./lib/cryptolib/rsa_utility.c \
diff --git a/firmware/include/sysincludes.h b/firmware/include/sysincludes.h
index 1560291e..777440e6 100644
--- a/firmware/include/sysincludes.h
+++ b/firmware/include/sysincludes.h
@@ -18,6 +18,7 @@
#ifdef CHROMEOS_ENVIRONMENT
#include <inttypes.h> /* For PRIu64 */
+#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
diff --git a/firmware/lib/crc8.c b/firmware/lib/crc8.c
new file mode 100644
index 00000000..fa770253
--- /dev/null
+++ b/firmware/lib/crc8.c
@@ -0,0 +1,28 @@
+/* Copyright (c) 2011 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.
+ */
+
+#include "crc8.h"
+
+/* Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial. A
+ * table-based algorithm would be faster, but for only a few bytes it isn't
+ * worth the code size. */
+uint8_t Crc8(const void* vptr, int len) {
+ const uint8_t *data = vptr;
+ unsigned crc = 0;
+ int i, j;
+
+ for (j = len; j; j--, data++) {
+ crc ^= (*data << 8);
+ for(i = 8; i; i--) {
+ if (crc & 0x8000)
+ crc ^= (0x1070 << 3);
+ crc <<= 1;
+ }
+ }
+
+ return (uint8_t)(crc >> 8);
+}
+
+
diff --git a/firmware/lib/include/crc8.h b/firmware/lib/include/crc8.h
new file mode 100644
index 00000000..95bc9862
--- /dev/null
+++ b/firmware/lib/include/crc8.h
@@ -0,0 +1,13 @@
+/* Copyright (c) 2011 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.
+ *
+ * Very simple 8-bit CRC function.
+ */
+#ifndef VBOOT_REFERENCE_CRC8_H_
+#define VBOOT_REFERENCE_CRC8_H_
+#include "sysincludes.h"
+
+uint8_t Crc8(const void* data, int len);
+
+#endif /* VBOOT_REFERENCE_CRC8_H_ */
diff --git a/firmware/lib/include/rollback_index.h b/firmware/lib/include/rollback_index.h
index 4d92bb71..4d847626 100644
--- a/firmware/lib/include/rollback_index.h
+++ b/firmware/lib/include/rollback_index.h
@@ -21,14 +21,15 @@
__pragma(pack(push, 1)) /* Support packing for MSVC. */
/* Kernel space - KERNEL_NV_INDEX, locked with physical presence. */
-#define ROLLBACK_SPACE_KERNEL_VERSION 1
+#define ROLLBACK_SPACE_KERNEL_VERSION 2
#define ROLLBACK_SPACE_KERNEL_UID 0x4752574C /* 'GRWL' */
typedef struct RollbackSpaceKernel {
uint8_t struct_version; /* Struct version, for backwards
* compatibility */
uint32_t uid; /* Unique ID to detect space redefinition */
uint32_t kernel_versions; /* Kernel versions */
- uint32_t reserved; /* Reserved for future expansion */
+ uint8_t reserved[3]; /* Reserved for future expansion */
+ uint8_t crc8; /* Checksum (v2 and later only) */
} __attribute__((packed)) RollbackSpaceKernel;
@@ -41,13 +42,14 @@ typedef struct RollbackSpaceKernel {
* from the backup copy. */
#define FLAG_KERNEL_SPACE_USE_BACKUP 0x02
-#define ROLLBACK_SPACE_FIRMWARE_VERSION 1
+#define ROLLBACK_SPACE_FIRMWARE_VERSION 2
/* Firmware space - FIRMWARE_NV_INDEX, locked with global lock. */
typedef struct RollbackSpaceFirmware {
uint8_t struct_version; /* Struct version, for backwards compatibility */
uint8_t flags; /* Flags (see FLAG_* above) */
uint32_t fw_versions; /* Firmware versions */
- uint32_t reserved; /* Reserved for future expansion */
+ uint8_t reserved[3]; /* Reserved for future expansion */
+ uint8_t crc8; /* Checksum (v2 and later only) */
} __attribute__((packed)) RollbackSpaceFirmware;
__pragma(pack(pop)) /* Support packing for MSVC. */
diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c
index 1d0f1d0f..3b4e4665 100644
--- a/firmware/lib/rollback_index.c
+++ b/firmware/lib/rollback_index.c
@@ -6,12 +6,17 @@
* stored in the TPM NVRAM.
*/
+#include "crc8.h"
#include "rollback_index.h"
#include "tlcl.h"
#include "tss_constants.h"
#include "utility.h"
#include "vboot_api.h"
+#ifndef offsetof
+#define offsetof(A,B) __builtin_offsetof(A,B)
+#endif
+
#ifdef ROLLBACK_UNITTEST
/* Compiling for unit test, so we need the real implementations of
* rollback functions. The unit test mocks the underlying tlcl
@@ -67,31 +72,134 @@ uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size) {
/* Functions to read and write firmware and kernel spaces. */
-static uint32_t ReadSpaceFirmware(RollbackSpaceFirmware* rsf) {
- return TlclRead(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware));
+uint32_t ReadSpaceFirmware(RollbackSpaceFirmware* rsf) {
+ uint32_t r;
+ int attempts = 3;
+
+ while (attempts--) {
+ r = TlclRead(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware));
+ if (r != TPM_SUCCESS)
+ return r;
+
+ /* No CRC in this version, so we'll create one when we write it. Note that
+ * we're marking this as version 2, not ROLLBACK_SPACE_FIRMWARE_VERSION,
+ * because version 2 just added the CRC. Later versions will need to
+ * set default values for any extra fields explicitly (probably here). */
+ if (rsf->struct_version < 2) {
+ rsf->struct_version = 2; /* Danger Will Robinson! Danger! */
+ return TPM_SUCCESS;
+ }
+
+ /* If the CRC is good, we're done. If it's bad, try a couple more times to
+ * see if it gets better before we give up. It could just be noise. */
+ if (rsf->crc8 == Crc8(rsf, offsetof(RollbackSpaceFirmware, crc8)))
+ return TPM_SUCCESS;
+
+ VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
+ }
+
+ VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
+ return TPM_E_CORRUPTED_STATE;
}
-static uint32_t WriteSpaceFirmware(const RollbackSpaceFirmware* rsf) {
- return SafeWrite(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware));
+uint32_t WriteSpaceFirmware(RollbackSpaceFirmware* rsf) {
+ RollbackSpaceFirmware rsf2;
+ uint32_t r;
+ int attempts = 3;
+
+ /* All writes should use struct_version 2 or greater. */
+ if (rsf->struct_version < 2)
+ rsf->struct_version = 2;
+ rsf->crc8 = Crc8(rsf, offsetof(RollbackSpaceFirmware, crc8));
+
+ while (attempts--) {
+ r = SafeWrite(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware));
+ /* Can't write, not gonna try again */
+ if (r != TPM_SUCCESS)
+ return r;
+
+ /* Read it back to be sure it got the right values. */
+ r = ReadSpaceFirmware(&rsf2); /* This checks the CRC */
+ if (r == TPM_SUCCESS)
+ return r;
+
+ VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
+ /* Try writing it again. Maybe it was garbled on the way out. */
+ }
+
+ VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
+ return TPM_E_CORRUPTED_STATE;
}
-#ifndef DISABLE_ROLLBACK_TPM
-static uint32_t ReadSpaceKernel(RollbackSpaceKernel* rsk) {
- return TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel));
+uint32_t ReadSpaceKernel(RollbackSpaceKernel* rsk) {
+ uint32_t r;
+ int attempts = 3;
+
+ while (attempts--) {
+ r = TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel));
+ if (r != TPM_SUCCESS)
+ return r;
+
+ /* No CRC in this version, so we'll create one when we write it. Note that
+ * we're marking this as version 2, not ROLLBACK_SPACE_KERNEL_VERSION,
+ * because version 2 just added the CRC. Later versions will need to
+ * set default values for any extra fields explicitly (probably here). */
+ if (rsk->struct_version < 2) {
+ rsk->struct_version = 2; /* Danger Will Robinson! Danger! */
+ return TPM_SUCCESS;
+ }
+
+ /* If the CRC is good, we're done. If it's bad, try a couple more times to
+ * see if it gets better before we give up. It could just be noise. */
+ if (rsk->crc8 == Crc8(rsk, offsetof(RollbackSpaceKernel, crc8)))
+ return TPM_SUCCESS;
+
+ VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
+ }
+
+ VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
+ return TPM_E_CORRUPTED_STATE;
}
-#endif
-static uint32_t WriteSpaceKernel(const RollbackSpaceKernel* rsk) {
- return SafeWrite(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel));
+uint32_t WriteSpaceKernel(RollbackSpaceKernel* rsk) {
+ RollbackSpaceKernel rsk2;
+ uint32_t r;
+ int attempts = 3;
+
+ /* All writes should use struct_version 2 or greater. */
+ if (rsk->struct_version < 2)
+ rsk->struct_version = 2;
+ rsk->crc8 = Crc8(rsk, offsetof(RollbackSpaceKernel, crc8));
+
+ while (attempts--) {
+ r = SafeWrite(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel));
+ /* Can't write, not gonna try again */
+ if (r != TPM_SUCCESS)
+ return r;
+
+ /* Read it back to be sure it got the right values. */
+ r = ReadSpaceKernel(&rsk2); /* This checks the CRC */
+ if (r == TPM_SUCCESS)
+ return r;
+
+ VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
+ /* Try writing it again. Maybe it was garbled on the way out. */
+ }
+
+ VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
+ return TPM_E_CORRUPTED_STATE;
}
uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware* rsf,
RollbackSpaceKernel* rsk) {
static const RollbackSpaceFirmware rsf_init = {
- ROLLBACK_SPACE_FIRMWARE_VERSION, 0, 0, 0};
+ .struct_version = ROLLBACK_SPACE_FIRMWARE_VERSION,
+ };
static const RollbackSpaceKernel rsk_init = {
- ROLLBACK_SPACE_KERNEL_VERSION, ROLLBACK_SPACE_KERNEL_UID, 0, 0};
+ .struct_version = ROLLBACK_SPACE_KERNEL_VERSION,
+ .uid = ROLLBACK_SPACE_KERNEL_UID,
+ };
TPM_PERMANENT_FLAGS pflags;
uint32_t result;
diff --git a/firmware/lib/vboot_nvstorage.c b/firmware/lib/vboot_nvstorage.c
index e96a17fe..7361817b 100644
--- a/firmware/lib/vboot_nvstorage.c
+++ b/firmware/lib/vboot_nvstorage.c
@@ -6,6 +6,7 @@
/* Non-volatile storage routines.
*/
+#include "crc8.h"
#include "utility.h"
#include "vboot_common.h"
#include "vboot_nvstorage.h"
@@ -39,26 +40,6 @@
#define CRC_OFFSET 15
-/* Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial. A
- * table-based algorithm would be faster, but for only 15 bytes isn't
- * worth the code size. */
-static uint8_t Crc8(const uint8_t* data, int len) {
- unsigned crc = 0;
- int i, j;
-
- for (j = len; j; j--, data++) {
- crc ^= (*data << 8);
- for(i = 8; i; i--) {
- if (crc & 0x8000)
- crc ^= (0x1070 << 3);
- crc <<= 1;
- }
- }
-
- return (uint8_t)(crc >> 8);
-}
-
-
int VbNvSetup(VbNvContext* context) {
uint8_t* raw = context->raw;