diff options
Diffstat (limited to 'firmware/lib/rollback_index.c')
-rw-r--r-- | firmware/lib/rollback_index.c | 132 |
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; |