diff options
author | Luigi Semenzato <semenzato@google.com> | 2010-06-28 13:34:31 -0700 |
---|---|---|
committer | Luigi Semenzato <semenzato@google.com> | 2010-06-28 13:34:31 -0700 |
commit | 2b9ddae52ba564dddcfc8bdcbed04dc07a52a7c6 (patch) | |
tree | 13832a568a9bfca1f6851991ed681cba0db5928d /firmware | |
parent | 46186faf4620c9775836bf8ad703fb6c481e68cd (diff) | |
download | vboot-2b9ddae52ba564dddcfc8bdcbed04dc07a52a7c6.tar.gz |
New rollback_index API.
Review URL: http://codereview.chromium.org/2869022
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/lib/include/rollback_index.h | 44 | ||||
-rw-r--r-- | firmware/lib/rollback_index.c | 205 | ||||
-rw-r--r-- | firmware/lib/vboot_firmware.c | 10 | ||||
-rw-r--r-- | firmware/linktest/main.c | 3 | ||||
-rw-r--r-- | firmware/version.c | 2 |
5 files changed, 91 insertions, 173 deletions
diff --git a/firmware/lib/include/rollback_index.h b/firmware/lib/include/rollback_index.h index d60a1701..e3399123 100644 --- a/firmware/lib/include/rollback_index.h +++ b/firmware/lib/include/rollback_index.h @@ -11,13 +11,6 @@ #include "sysincludes.h" -/* TODO: global variables won't work in the boot stub, since it runs - directly out of ROM. */ -extern uint16_t g_firmware_key_version; -extern uint16_t g_firmware_version; -extern uint16_t g_kernel_key_version; -extern uint16_t g_kernel_version; - /* Rollback version types. */ #define FIRMWARE_VERSIONS 0 #define KERNEL_VERSIONS 1 @@ -43,7 +36,6 @@ extern uint16_t g_kernel_version; /* All functions return TPM_SUCCESS (zero) if successful, non-zero if error */ - /* Call from LoadFirmware() @@ -51,7 +43,8 @@ Call from LoadFirmware() Wants firmware versions Must send in developer flag - RollbackFirmwareSetup(IN devmode, OUT firmware versions) + RollbackFirmwareSetup(IN devmode) + (maybe) RollbackFirmwareRead() (maybe) RollbackFirmwareWrite() RollbackFirmwareLock() @@ -73,48 +66,33 @@ Call from LoadKernel() /* These functions are callable from LoadFirmware(). They cannot use * global variables. */ + /* Setup must be called. Pass developer_mode=nonzero if in developer * mode. */ -uint32_t RollbackFirmwareSetup(int developer_mode, - uint16_t* key_version, uint16_t* version); +uint32_t RollbackFirmwareSetup(int developer_mode); +/* Read and Write may be called after Setup. */ +uint32_t RollbackFirmwareRead(uint16_t* key_version, uint16_t* version); /* Write may be called if the versions change */ uint32_t RollbackFirmwareWrite(uint16_t key_version, uint16_t version); + /* Lock must be called */ uint32_t RollbackFirmwareLock(void); /* These functions are callable from LoadKernel(). They may use global * variables. */ + /* Recovery may be called. If it is, this is the first time a * rollback function has been called this boot, so it needs to know if * we're in developer mode. Pass developer_mode=nonzero if in developer * mode. */ uint32_t RollbackKernelRecovery(int developer_mode); + /* Read and write may be called if not in developer mode. If called in - * recovery mode, these are ignored and/or return 0 versions. */ + * recovery mode, the effect is undefined. */ uint32_t RollbackKernelRead(uint16_t* key_version, uint16_t* version); uint32_t RollbackKernelWrite(uint16_t key_version, uint16_t version); + /* Lock must be called. Internally, it's ignored in recovery mode. */ uint32_t RollbackKernelLock(void); - -/* SetupTPM is called on boot and on starting the RW firmware, passing the - * appripriate MODE and DEVELOPER_FLAG parameters. MODE can be one of - * RO_RECOVERY_MODE, RO_NORMAL_MODE, RW_NORMAL_MODE. DEVELOPER_FLAG is 1 when - * the developer switch is ON, 0 otherwise. - * - * If SetupTPM returns TPM_SUCCESS, the caller may proceed. If it returns - * TPM_E_MUST_REBOOT, the caller must reboot in the current mode. For all - * other return values, the caller must reboot in recovery mode. - * - * This function has many side effects on the TPM state. In particular, when - * called with mode = RECOVERY_MODE, it locks the firmware versions before - * returning. In all other cases, the caller is responsible for locking the - * firmware versions once it decides it doesn't need to update them. - */ -uint32_t SetupTPM(int mode, int developer_flag); -uint32_t GetStoredVersions(int type, uint16_t* key_version, uint16_t* version); -uint32_t WriteStoredVersions(int type, uint16_t key_version, uint16_t version); -uint32_t LockFirmwareVersions(void); -uint32_t LockKernelVersionsByLockingPP(void); - #endif /* VBOOT_REFERENCE_ROLLBACK_INDEX_H_ */ diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c index 4fb7ec97..4629e6e4 100644 --- a/firmware/lib/rollback_index.c +++ b/firmware/lib/rollback_index.c @@ -12,10 +12,7 @@ #include "tss_constants.h" #include "utility.h" -uint16_t g_firmware_key_version = 0; -uint16_t g_firmware_version = 0; -uint16_t g_kernel_key_version = 0; -uint16_t g_kernel_version = 0; +static int g_rollback_recovery_mode = 0; /* disable MSVC warning on const logical expression (as in } while(0);) */ __pragma(warning (disable: 4127)) @@ -133,34 +130,6 @@ static uint32_t SetDistrustKernelSpaceAtNextBoot(uint32_t distrust) { return TPM_SUCCESS; } -static uint32_t GetTPMRollbackIndices(int type) { - uint32_t firmware_versions; - uint32_t kernel_versions; - - /* 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. - */ - switch (type) { - case FIRMWARE_VERSIONS: - RETURN_ON_FAILURE(TlclRead(FIRMWARE_VERSIONS_NV_INDEX, - (uint8_t*) &firmware_versions, - sizeof(firmware_versions))); - g_firmware_key_version = (uint16_t) (firmware_versions >> 16); - g_firmware_version = (uint16_t) (firmware_versions & 0xffff); - break; - case KERNEL_VERSIONS: - RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, - (uint8_t*) &kernel_versions, - sizeof(kernel_versions))); - g_kernel_key_version = (uint16_t) (kernel_versions >> 16); - g_kernel_version = (uint16_t) (kernel_versions & 0xffff); - break; - } - - return TPM_SUCCESS; -} - /* Checks if the kernel version space has been mucked with. If it has, * reconstructs it using the backup value. */ @@ -244,9 +213,30 @@ static uint32_t CheckDeveloperModeTransition(uint32_t current_developer) { return TPM_SUCCESS; } -static uint32_t SetupTPM_(int mode, int developer_flag) { +/* SetupTPM starts the TPM and establishes the root of trust for the + * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a + * TPM hardware failure. 3 An unexpected TPM state due to some attack. In + * general we cannot easily distinguish the kind of failure, so our strategy is + * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM + * again, which executes (almost) the same sequence of operations. There is a + * good chance that, if recovery mode was entered because of a TPM failure, the + * failure will repeat itself. (In general this is impossible to guarantee + * because we have no way of creating the exact TPM initial state at the + * previous boot.) In recovery mode, we ignore the failure and continue, thus + * giving the recovery kernel a chance to fix things (that's why we don't set + * bGlobalLock). The choice is between a knowingly insecure device and a + * bricked device. + * + * As a side note, observe that we go through considerable hoops to avoid using + * the STCLEAR permissions for the index spaces. We do this to avoid writing + * to the TPM flashram at every reboot or wake-up, because of concerns about + * the durability of the NVRAM. + */ +static uint32_t SetupTPM(int recovery_mode, + int developer_mode) { uint8_t disable; uint8_t deactivated; + TlclLibInit(); RETURN_ON_FAILURE(TlclStartup()); RETURN_ON_FAILURE(TlclContinueSelfTest()); @@ -272,136 +262,83 @@ static uint32_t SetupTPM_(int mode, int developer_flag) { } } RETURN_ON_FAILURE(BackupKernelSpace()); - RETURN_ON_FAILURE(SetDistrustKernelSpaceAtNextBoot(mode == RO_RECOVERY_MODE)); - RETURN_ON_FAILURE(GetTPMRollbackIndices(FIRMWARE_VERSIONS)); - RETURN_ON_FAILURE(GetTPMRollbackIndices(KERNEL_VERSIONS)); - - RETURN_ON_FAILURE(CheckDeveloperModeTransition(developer_flag)); - - /* As a courtesy (I hope) to the caller, lock the firmware versions if we are - * in recovery mode. The normal mode may need to update the firmware - * versions, so they cannot be locked here. - */ - if (mode == RO_RECOVERY_MODE) { - RETURN_ON_FAILURE(LockFirmwareVersions()); - } - return TPM_SUCCESS; -} - -/* SetupTPM starts the TPM and establishes the root of trust for the - * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a - * TPM hardware failure. 3 An unexpected TPM state due to some attack. In - * general we cannot easily distinguish the kind of failure, so our strategy is - * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM - * again, which executes (almost) the same sequence of operations. There is a - * good chance that, if recovery mode was entered because of a TPM failure, the - * failure will repeat itself. (In general this is impossible to guarantee - * because we have no way of creating the exact TPM initial state at the - * previous boot.) In recovery mode, we ignore the failure and continue, thus - * giving the recovery kernel a chance to fix things (that's why we don't set - * bGlobalLock). The choice is between a knowingly insecure device and a - * bricked device. - * - * As a side note, observe that we go through considerable hoops to avoid using - * the STCLEAR permissions for the index spaces. We do this to avoid writing - * to the TPM flashram at every reboot or wake-up, because of concerns about - * the durability of the NVRAM. - */ -uint32_t SetupTPM(int mode, int developer_flag) { - switch (mode) { - case RO_RECOVERY_MODE: - case RO_NORMAL_MODE: { - uint32_t result = SetupTPM_(mode, developer_flag); - if (mode == RO_NORMAL_MODE) { - return result; - } else { - /* In recovery mode we want to keep going even if there are errors. */ - return TPM_SUCCESS; - } - } - case RW_NORMAL_MODE: - RETURN_ON_FAILURE(GetTPMRollbackIndices(KERNEL_VERSIONS)); - default: - return TPM_E_INTERNAL_INCONSISTENCY; - } -} - -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 get down into kernel verification, the hardware setup persists, but we - * lose the global variables. - */ - switch (type) { - case FIRMWARE_VERSIONS: - *key_version = g_firmware_key_version; - *version = g_firmware_version; - break; - case KERNEL_VERSIONS: - *key_version = g_kernel_key_version; - *version = g_kernel_version; - break; - } - - return TPM_SUCCESS; -} + RETURN_ON_FAILURE(SetDistrustKernelSpaceAtNextBoot(recovery_mode)); + RETURN_ON_FAILURE(CheckDeveloperModeTransition(developer_mode)); -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_ON_FAILURE(SafeWrite(FIRMWARE_VERSIONS_NV_INDEX, - (uint8_t*) &combined_version, - sizeof(uint32_t))); - break; - - case KERNEL_VERSIONS: - RETURN_ON_FAILURE(SafeWrite(KERNEL_VERSIONS_NV_INDEX, - (uint8_t*) &combined_version, - sizeof(uint32_t))); + if (recovery_mode) { + /* In recovery mode global variables are usable. */ + g_rollback_recovery_mode = 1; } return TPM_SUCCESS; } -uint32_t LockFirmwareVersions() { - return TlclSetGlobalLock(); -} - -uint32_t LockKernelVersionsByLockingPP() { - return TlclLockPhysicalPresence(); -} - /* disable MSVC warnings on unused arguments */ __pragma(warning (disable: 4100)) -/* NEW APIS! HELP ME LUIGI, YOU'RE MY ONLY HOPE! */ +uint32_t RollbackFirmwareSetup(int developer_mode) { + return SetupTPM(0, developer_mode); +} -uint32_t RollbackFirmwareSetup(int developer_mode, - uint16_t* key_version, uint16_t* version) { +uint32_t RollbackFirmwareRead(uint16_t* key_version, uint16_t* version) { + uint32_t firmware_versions; + /* Gets firmware versions. */ + RETURN_ON_FAILURE(TlclRead(FIRMWARE_VERSIONS_NV_INDEX, + (uint8_t*) &firmware_versions, + sizeof(firmware_versions))); + *key_version = (uint16_t) (firmware_versions >> 16); + *version = (uint16_t) (firmware_versions & 0xffff); return TPM_SUCCESS; } uint32_t RollbackFirmwareWrite(uint16_t key_version, uint16_t version) { - return TPM_SUCCESS; + uint32_t combined_version = (key_version << 16) & version; + return SafeWrite(FIRMWARE_VERSIONS_NV_INDEX, + (uint8_t*) &combined_version, + sizeof(uint32_t)); } uint32_t RollbackFirmwareLock(void) { - return TPM_SUCCESS; + return TlclSetGlobalLock(); } uint32_t RollbackKernelRecovery(int developer_mode) { + uint32_t result = SetupTPM(1, developer_mode); + if (result == TPM_SUCCESS) { + RETURN_ON_FAILURE(TlclSetGlobalLock()); + } return TPM_SUCCESS; } uint32_t RollbackKernelRead(uint16_t* key_version, uint16_t* version) { + uint32_t kernel_versions; + if (g_rollback_recovery_mode) { + *key_version = 0; + *version = 0; + } else { + /* Reads kernel versions from TPM. */ + RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, + (uint8_t*) &kernel_versions, + sizeof(kernel_versions))); + *key_version = (uint16_t) (kernel_versions >> 16); + *version = (uint16_t) (kernel_versions & 0xffff); + } return TPM_SUCCESS; } uint32_t RollbackKernelWrite(uint16_t key_version, uint16_t version) { + if (!g_rollback_recovery_mode) { + uint32_t combined_version = (key_version << 16) & version; + return SafeWrite(KERNEL_VERSIONS_NV_INDEX, + (uint8_t*) &combined_version, + sizeof(uint32_t)); + } return TPM_SUCCESS; } uint32_t RollbackKernelLock(void) { - return TPM_SUCCESS; + if (!g_rollback_recovery_mode) { + return TlclLockPhysicalPresence(); + } else { + return TPM_SUCCESS; + } } diff --git a/firmware/lib/vboot_firmware.c b/firmware/lib/vboot_firmware.c index 11ea6f77..c445a819 100644 --- a/firmware/lib/vboot_firmware.c +++ b/firmware/lib/vboot_firmware.c @@ -60,10 +60,12 @@ int LoadFirmware(LoadFirmwareParams* params) { } /* Initialize the TPM and read rollback indices. */ - if (0 != RollbackFirmwareSetup( - (params->boot_flags & BOOT_FLAG_DEVELOPER ? 1 : 0), - &tpm_key_version, &tpm_fw_version)) { - VBDEBUG(("Unable to get stored versions.\n")); + if (0 != RollbackFirmwareSetup(params->boot_flags & BOOT_FLAG_DEVELOPER)) { + VBDEBUG(("Unable to setup TPM.\n")); + return LOAD_FIRMWARE_RECOVERY; + } + if (0 != RollbackFirmwareRead(&tpm_key_version, &tpm_fw_version)) { + VBDEBUG(("Unable to read stored versions.\n")); return LOAD_FIRMWARE_RECOVERY; } diff --git a/firmware/linktest/main.c b/firmware/linktest/main.c index f91da995..4696c2e6 100644 --- a/firmware/linktest/main.c +++ b/firmware/linktest/main.c @@ -24,7 +24,8 @@ int main(void) LoadKernel(0); /* rollback_index.h */ - RollbackFirmwareSetup(0, &x, &y); + RollbackFirmwareSetup(0); + RollbackFirmwareRead(&x, &y); RollbackFirmwareWrite(0, 0); RollbackFirmwareLock(); RollbackKernelRecovery(0); diff --git a/firmware/version.c b/firmware/version.c index 85a0ae77..3fa3bed5 100644 --- a/firmware/version.c +++ b/firmware/version.c @@ -1 +1 @@ -char* VbootVersion = "VBOOv=c9cb6a2f"; +char* VbootVersion = "VBOOv=7bb80e3a"; |