| Index: vboot_firmware/lib/rollback_index.c
|
| diff --git a/vboot_firmware/lib/rollback_index.c b/vboot_firmware/lib/rollback_index.c
|
| index fe0caffbf8c97a3ebbac8bb2b9a1df96cc6a0ba9..7b30c4d79a485ddee32ef50e59b141a960499468 100644
|
| --- a/vboot_firmware/lib/rollback_index.c
|
| +++ b/vboot_firmware/lib/rollback_index.c
|
| @@ -19,7 +19,14 @@ uint16_t g_firmware_version = 0;
|
| uint16_t g_kernel_key_version = 0;
|
| uint16_t g_kernel_version = 0;
|
|
|
| -static int InitializeSpaces(void) {
|
| +#define RETURN_ON_FAILURE(tpm_command) do { \
|
| + uint32_t result; \
|
| + if ((result = tpm_command) != TPM_SUCCESS) {\
|
| + return result; \
|
| + } \
|
| + } while (0)
|
| +
|
| +static uint32_t InitializeSpaces(void) {
|
| uint32_t zero = 0;
|
| uint32_t space_holder;
|
| uint32_t firmware_perm = TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE;
|
| @@ -33,35 +40,40 @@ static int InitializeSpaces(void) {
|
| return 0;
|
| }
|
|
|
| - TlclSetNvLocked();
|
| + RETURN_ON_FAILURE(TlclSetNvLocked());
|
|
|
| - TlclDefineSpace(FIRMWARE_VERSIONS_NV_INDEX, firmware_perm, sizeof(uint32_t));
|
| - TlclWrite(FIRMWARE_VERSIONS_NV_INDEX, (uint8_t*) &zero, sizeof(uint32_t));
|
| + RETURN_ON_FAILURE(TlclDefineSpace(FIRMWARE_VERSIONS_NV_INDEX,
|
| + firmware_perm, sizeof(uint32_t)));
|
| + RETURN_ON_FAILURE(TlclWrite(FIRMWARE_VERSIONS_NV_INDEX,
|
| + (uint8_t*) &zero, sizeof(uint32_t)));
|
|
|
| - TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX, kernel_perm, sizeof(uint32_t));
|
| - TlclWrite(KERNEL_VERSIONS_NV_INDEX, (uint8_t*) &zero, sizeof(uint32_t));
|
| + RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX,
|
| + kernel_perm, sizeof(uint32_t)));
|
| + RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, (uint8_t*) &zero,
|
| + sizeof(uint32_t)));
|
|
|
| /* The space KERNEL_VERSIONS_BACKUP_NV_INDEX is used to protect the kernel
|
| * versions when entering recovery mode. The content of space
|
| * KERNEL_BACKUP_IS_VALID determines whether the backup value (1) or the
|
| * regular value (0) should be trusted.
|
| */
|
| - TlclDefineSpace(KERNEL_VERSIONS_BACKUP_NV_INDEX,
|
| - firmware_perm, sizeof(uint32_t));
|
| - TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX,
|
| - (uint8_t*) &zero, sizeof(uint32_t));
|
| - TlclDefineSpace(KERNEL_BACKUP_IS_VALID_NV_INDEX,
|
| - firmware_perm, sizeof(uint32_t));
|
| - TlclWrite(KERNEL_BACKUP_IS_VALID_NV_INDEX,
|
| - (uint8_t*) &zero, sizeof(uint32_t));
|
| + RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_BACKUP_NV_INDEX,
|
| + firmware_perm, sizeof(uint32_t)));
|
| + RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX,
|
| + (uint8_t*) &zero, sizeof(uint32_t)));
|
| + RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_BACKUP_IS_VALID_NV_INDEX,
|
| + firmware_perm, sizeof(uint32_t)));
|
| + RETURN_ON_FAILURE(TlclWrite(KERNEL_BACKUP_IS_VALID_NV_INDEX,
|
| + (uint8_t*) &zero, sizeof(uint32_t)));
|
|
|
| /* The space TPM_IS_INITIALIZED_NV_INDEX is used to indicate that the TPM
|
| * initialization has completed. Without it we cannot be sure that the last
|
| * space to be created was also initialized (power could have been lost right
|
| * after its creation).
|
| */
|
| - TlclDefineSpace(TPM_IS_INITIALIZED_NV_INDEX, firmware_perm, sizeof(uint32_t));
|
| - return 1;
|
| + RETURN_ON_FAILURE(TlclDefineSpace(TPM_IS_INITIALIZED_NV_INDEX,
|
| + firmware_perm, sizeof(uint32_t)));
|
| + return TPM_SUCCESS;
|
| }
|
|
|
| /* Enters the recovery mode. If |unlocked| is true, there is some problem with
|
| @@ -104,7 +116,7 @@ static void EnterRecovery(int unlocked) {
|
| /* TODO(nelson): code for entering recovery mode. */
|
| }
|
|
|
| -static int GetTPMRollbackIndices(void) {
|
| +static uint32_t GetTPMRollbackIndices(void) {
|
| uint32_t backup_is_valid;
|
| uint32_t firmware_versions;
|
| uint32_t kernel_versions;
|
| @@ -133,86 +145,83 @@ static int GetTPMRollbackIndices(void) {
|
| * incompetent. Foo to them. Politeness and lack of an adequate
|
| * character set prevent me from expressing my true feelings.
|
| */
|
| - TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX, TPM_NV_PER_PPWRITE,
|
| - sizeof(uint32_t));
|
| + RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX,
|
| + TPM_NV_PER_PPWRITE,
|
| + sizeof(uint32_t)));
|
| } else if (result != TPM_SUCCESS) {
|
| EnterRecovery(1);
|
| }
|
| if (result == TPM_E_BADINDEX ||
|
| protected_combined_versions != unsafe_combined_versions) {
|
| - TlclWrite(KERNEL_VERSIONS_NV_INDEX,
|
| - (uint8_t*) &protected_combined_versions, sizeof(uint32_t));
|
| + RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX,
|
| + (uint8_t*) &protected_combined_versions,
|
| + sizeof(uint32_t)));
|
| }
|
| /* We recovered the backed-up versions and now we can reset the
|
| * BACKUP_IS_VALID flag.
|
| */
|
| - TlclWrite(KERNEL_BACKUP_IS_VALID_NV_INDEX, (uint8_t*) &zero, 0);
|
| + RETURN_ON_FAILURE(TlclWrite(KERNEL_BACKUP_IS_VALID_NV_INDEX,
|
| + (uint8_t*) &zero, 0));
|
|
|
| - /* TODO(nelson): ForceClear and reboot if unowned. */
|
| + if (!TlclIsOwned()) {
|
| + /* Must ForceClear and reboot to prevent from running into the 64-write
|
| + * limit.
|
| + */
|
| + RETURN_ON_FAILURE(TlclForceClear());
|
| + /* Reboot! No return */
|
| + return 9999;
|
| + }
|
| }
|
|
|
| /* We perform the reads, making sure they succeed. A failure means that the
|
| * rollback index locations are missing or somehow messed up. We let the
|
| * caller deal with that.
|
| */
|
| - if (TPM_SUCCESS != TlclRead(FIRMWARE_VERSIONS_NV_INDEX,
|
| - (uint8_t*) &firmware_versions,
|
| - sizeof(firmware_versions)) ||
|
| - TPM_SUCCESS != TlclRead(KERNEL_VERSIONS_NV_INDEX,
|
| - (uint8_t*) &kernel_versions,
|
| - sizeof(kernel_versions)))
|
| - return 0;
|
| + RETURN_ON_FAILURE(TlclRead(FIRMWARE_VERSIONS_NV_INDEX,
|
| + (uint8_t*) &firmware_versions,
|
| + sizeof(firmware_versions)));
|
| + RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX,
|
| + (uint8_t*) &kernel_versions,
|
| + sizeof(kernel_versions)));
|
|
|
| g_firmware_key_version = firmware_versions >> 16;
|
| g_firmware_version = firmware_versions && 0xffff;
|
| g_kernel_key_version = kernel_versions >> 16;
|
| g_kernel_version = kernel_versions && 0xffff;
|
|
|
| - return 1;
|
| + return TPM_SUCCESS;
|
| }
|
|
|
|
|
| -int SetupTPM(void) {
|
| +uint32_t SetupTPM(void) {
|
| uint8_t disable;
|
| uint8_t deactivated;
|
| - TlclLibinit();
|
| - TlclStartup();
|
| - /* TODO(gauravsh): The call to self test should probably be deferred.
|
| - * As per semenzato@chromium.org -
|
| - * TlclStartup should be called before the firmware initializes the memory
|
| - * controller, so the selftest can run in parallel with that. Here we should
|
| - * just call TlclSelftestFull to make sure the self test has
|
| - * completed---unless we want to rely on the NVRAM operations being available
|
| - * before the selftest completes. */
|
| - TlclSelftestfull();
|
| - TlclAssertPhysicalPresence();
|
| + TlclLibInit();
|
| + RETURN_ON_FAILURE(TlclStartup());
|
| + RETURN_ON_FAILURE(TlclContinueSelfTest());
|
| + RETURN_ON_FAILURE(TlclAssertPhysicalPresence());
|
| /* Check that the TPM is enabled and activated. */
|
| - if(TlclGetFlags(&disable, &deactivated) != TPM_SUCCESS) {
|
| - debug("failed to get TPM flags");
|
| - return 1;
|
| - }
|
| + RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated));
|
| if (disable || deactivated) {
|
| - TlclSetEnable();
|
| - if (TlclSetDeactivated(0) != TPM_SUCCESS) {
|
| - debug("failed to activate TPM");
|
| - return 1;
|
| - }
|
| + RETURN_ON_FAILURE(TlclSetEnable());
|
| + RETURN_ON_FAILURE(TlclSetDeactivated(0));
|
| + /* TODO: Reboot now */
|
| + return 9999;
|
| }
|
| /* We expect this to fail the first time we run on a device, indicating that
|
| * the TPM has not been initialized yet. */
|
| - if (!GetTPMRollbackIndices()) {
|
| - debug("failed to get rollback indices");
|
| - if (!InitializeSpaces()) {
|
| - /* If InitializeSpaces() fails (possibly because it had been executed
|
| - * already), something is wrong. */
|
| - return 1;
|
| - }
|
| + if (GetTPMRollbackIndices() != TPM_SUCCESS) {
|
| + /* If InitializeSpaces() fails (possibly because it had been executed
|
| + * already), something is wrong. */
|
| + RETURN_ON_FAILURE(InitializeSpaces());
|
| + /* Try again. */
|
| + RETURN_ON_FAILURE(GetTPMRollbackIndices());
|
| }
|
|
|
| - return 0;
|
| + return TPM_SUCCESS;
|
| }
|
|
|
| -int GetStoredVersions(int type, uint16_t* key_version, uint16_t* version) {
|
| +uint32_t GetStoredVersions(int type, uint16_t* key_version, uint16_t* version) {
|
|
|
| /* TODO: should verify that SetupTPM() has been called. Note that
|
| * SetupTPM() does hardware setup AND sets global variables. When we
|
| @@ -232,39 +241,36 @@ int GetStoredVersions(int type, uint16_t* key_version, uint16_t* version) {
|
| break;
|
| }
|
|
|
| - return 0;
|
| + return TPM_SUCCESS;
|
| }
|
|
|
| -int WriteStoredVersions(int type, uint16_t key_version, uint16_t version) {
|
| +uint32_t WriteStoredVersions(int type, uint16_t key_version, uint16_t version) {
|
| uint32_t combined_version = (key_version << 16) & version;
|
| switch (type) {
|
| case FIRMWARE_VERSIONS:
|
| - return (TPM_SUCCESS != TlclWrite(FIRMWARE_VERSIONS_NV_INDEX,
|
| - (uint8_t*) &combined_version,
|
| - sizeof(uint32_t)));
|
| + RETURN_ON_FAILURE(TlclWrite(FIRMWARE_VERSIONS_NV_INDEX,
|
| + (uint8_t*) &combined_version,
|
| + sizeof(uint32_t)));
|
| + break;
|
|
|
| case KERNEL_VERSIONS:
|
| - return (TPM_SUCCESS != TlclWrite(KERNEL_VERSIONS_NV_INDEX,
|
| - (uint8_t*) &combined_version,
|
| - sizeof(uint32_t)));
|
| + RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX,
|
| + (uint8_t*) &combined_version,
|
| + sizeof(uint32_t)));
|
| + break;
|
| }
|
| - /* TODO(nelson): ForceClear and reboot if unowned. */
|
| -
|
| - return 1;
|
| + if (!TlclIsOwned()) {
|
| + RETURN_ON_FAILURE(TlclForceClear());
|
| + /* TODO: Reboot here. No return. */
|
| + return 9999;
|
| + }
|
| + return TPM_SUCCESS;
|
| }
|
|
|
| -int LockFirmwareVersions() {
|
| - if (TlclSetGlobalLock() != TPM_SUCCESS) {
|
| - debug("failed to set global lock");
|
| - return 1;
|
| - }
|
| - return 0;
|
| +uint32_t LockFirmwareVersions() {
|
| + return TlclSetGlobalLock();
|
| }
|
|
|
| -int LockKernelVersionsByLockingPP() {
|
| - if (TlclLockPhysicalPresence() != TPM_SUCCESS) {
|
| - debug("failed to turn off PP");
|
| - return 1;
|
| - }
|
| - return 0;
|
| +uint32_t LockKernelVersionsByLockingPP() {
|
| + return TlclLockPhysicalPresence();
|
| }
|
|
|