summaryrefslogtreecommitdiff
path: root/firmware/lib/rollback_index.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/lib/rollback_index.c')
-rw-r--r--firmware/lib/rollback_index.c132
1 files changed, 120 insertions, 12 deletions
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;