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.c381
1 files changed, 1 insertions, 380 deletions
diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c
index 2431e98f..cf446d98 100644
--- a/firmware/lib/rollback_index.c
+++ b/firmware/lib/rollback_index.c
@@ -69,17 +69,6 @@ uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length)
}
}
-uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
-{
- uint32_t result = TlclDefineSpace(index, perm, size);
- if (result == TPM_E_MAXNVWRITES) {
- RETURN_ON_FAILURE(TPMClearAndReenable());
- return TlclDefineSpace(index, perm, size);
- } else {
- return result;
- }
-}
-
/* Functions to read and write firmware and kernel spaces. */
uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf)
{
@@ -167,7 +156,7 @@ uint32_t SetVirtualDevMode(int val)
rsf.flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
/*
* NOTE: This doesn't update the FLAG_LAST_BOOT_DEVELOPER bit. That
- * will be done by SetupTPM() on the next boot.
+ * will be done on the next boot.
*/
VBDEBUG(("TPM: flags are now 0x%02x\n", rsf.flags));
@@ -247,293 +236,9 @@ uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk)
return TPM_E_CORRUPTED_STATE;
}
-#ifndef TPM2_MODE
-uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf,
- RollbackSpaceKernel *rsk)
-{
- static const RollbackSpaceFirmware rsf_init = {
- .struct_version = ROLLBACK_SPACE_FIRMWARE_VERSION,
- };
- static const RollbackSpaceKernel rsk_init = {
- .struct_version = ROLLBACK_SPACE_KERNEL_VERSION,
- .uid = ROLLBACK_SPACE_KERNEL_UID,
- };
- TPM_PERMANENT_FLAGS pflags;
- uint32_t result;
-
- VBDEBUG(("TPM: One-time initialization\n"));
-
- /*
- * Do a full test. This only happens the first time the device is
- * turned on in the factory, so performance is not an issue. This is
- * almost certainly not necessary, but it gives us more confidence
- * about some code paths below that are difficult to
- * test---specifically the ones that set lifetime flags, and are only
- * executed once per physical TPM.
- */
- result = TlclSelfTestFull();
- if (result != TPM_SUCCESS)
- return result;
-
- result = TlclGetPermanentFlags(&pflags);
- if (result != TPM_SUCCESS)
- return result;
-
- /*
- * TPM may come from the factory without physical presence finalized.
- * Fix if necessary.
- */
- VBDEBUG(("TPM: physicalPresenceLifetimeLock=%d\n",
- pflags.physicalPresenceLifetimeLock));
- if (!pflags.physicalPresenceLifetimeLock) {
- VBDEBUG(("TPM: Finalizing physical presence\n"));
- RETURN_ON_FAILURE(TlclFinalizePhysicalPresence());
- }
-
- /*
- * The TPM will not enforce the NV authorization restrictions until the
- * execution of a TPM_NV_DefineSpace with the handle of
- * TPM_NV_INDEX_LOCK. Here we create that space if it doesn't already
- * exist. */
- VBDEBUG(("TPM: nvLocked=%d\n", pflags.nvLocked));
- if (!pflags.nvLocked) {
- VBDEBUG(("TPM: Enabling NV locking\n"));
- RETURN_ON_FAILURE(TlclSetNvLocked());
- }
-
- /* Clear TPM owner, in case the TPM is already owned for some reason. */
- VBDEBUG(("TPM: Clearing owner\n"));
- RETURN_ON_FAILURE(TPMClearAndReenable());
-
- /* Initializes the firmware and kernel spaces */
- Memcpy(rsf, &rsf_init, sizeof(RollbackSpaceFirmware));
- Memcpy(rsk, &rsk_init, sizeof(RollbackSpaceKernel));
-
- /* Define the backup space. No need to initialize it, though. */
- RETURN_ON_FAILURE(SafeDefineSpace(
- BACKUP_NV_INDEX, TPM_NV_PER_PPWRITE, BACKUP_NV_SIZE));
-
- /* Define and initialize the kernel space */
- RETURN_ON_FAILURE(SafeDefineSpace(KERNEL_NV_INDEX, TPM_NV_PER_PPWRITE,
- sizeof(RollbackSpaceKernel)));
- RETURN_ON_FAILURE(WriteSpaceKernel(rsk));
-
- /* Do the firmware space last, so we retry if we don't get this far. */
- RETURN_ON_FAILURE(SafeDefineSpace(
- FIRMWARE_NV_INDEX,
- TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE,
- sizeof(RollbackSpaceFirmware)));
- RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
-
- return TPM_SUCCESS;
-}
-#endif
-
-/*
- * 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 developer_mode, int disable_dev_request,
- int clear_tpm_owner_request, RollbackSpaceFirmware* rsf)
-{
- uint8_t in_flags;
-#ifndef TPM2_MODE
- uint8_t disable;
- uint8_t deactivated;
-#endif
- uint32_t result;
- uint32_t versions;
-
- RETURN_ON_FAILURE(TlclLibInit());
-
-#ifdef TEGRA_SOFT_REBOOT_WORKAROUND
- result = TlclStartup();
- if (result == TPM_E_INVALID_POSTINIT) {
- /*
- * Some prototype hardware doesn't reset the TPM on a CPU
- * reset. We do a hard reset to get around this.
- */
- VBDEBUG(("TPM: soft reset detected\n", result));
- return TPM_E_MUST_REBOOT;
- } else if (result != TPM_SUCCESS) {
- VBDEBUG(("TPM: TlclStartup returned %08x\n", result));
- return result;
- }
-#else
- RETURN_ON_FAILURE(TlclStartup());
-#endif
-
- /*
- * Some TPMs start the self test automatically at power on. In that case we
- * don't need to call ContinueSelfTest. On some (other) TPMs,
- * ContinueSelfTest may block. In that case, we definitely don't want to
- * call it here. For TPMs in the intersection of these two sets, we're
- * screwed. (In other words: TPMs that require manually starting the
- * self-test AND block will have poor performance until we split
- * TlclSendReceive() into Send() and Receive(), and have a state machine to
- * control setup.)
- *
- * This comment is likely to become obsolete in the near future, so don't
- * trust it. It may have not been updated.
- */
-#ifdef TPM_MANUAL_SELFTEST
-#ifdef TPM_BLOCKING_CONTINUESELFTEST
-#warning "lousy TPM!"
-#endif
- RETURN_ON_FAILURE(TlclContinueSelfTest());
-#endif
-#ifndef TPM2_MODE
- result = TlclAssertPhysicalPresence();
- if (result != TPM_SUCCESS) {
- /*
- * It is possible that the TPM was delivered with the physical
- * presence command disabled. This tries enabling it, then
- * tries asserting PP again.
- */
- RETURN_ON_FAILURE(TlclPhysicalPresenceCMDEnable());
- RETURN_ON_FAILURE(TlclAssertPhysicalPresence());
- }
-
- /* Check that the TPM is enabled and activated. */
- RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated, NULL));
- if (disable || deactivated) {
- VBDEBUG(("TPM: disabled (%d) or deactivated (%d). Fixing...\n",
- disable, deactivated));
- RETURN_ON_FAILURE(TlclSetEnable());
- RETURN_ON_FAILURE(TlclSetDeactivated(0));
- VBDEBUG(("TPM: Must reboot to re-enable\n"));
- return TPM_E_MUST_REBOOT;
- }
-#endif
-
- /* Read the firmware space. */
- result = ReadSpaceFirmware(rsf);
-#ifndef TPM2_MODE
- if (TPM_E_BADINDEX == result) {
- RollbackSpaceKernel rsk;
-
- /*
- * This is the first time we've run, and the TPM has not been
- * initialized. Initialize it.
- */
- VBDEBUG(("TPM: Not initialized yet.\n"));
- RETURN_ON_FAILURE(OneTimeInitializeTPM(rsf, &rsk));
- } else
-#endif
- if (TPM_SUCCESS != result) {
- VBDEBUG(("TPM: Firmware space in a bad state; giving up.\n"));
- return TPM_E_CORRUPTED_STATE;
- }
- Memcpy(&versions, &rsf->fw_versions, sizeof(versions));
- VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n",
- rsf->struct_version, rsf->flags, versions));
- in_flags = rsf->flags;
-
- /* If we've been asked to clear the virtual dev-mode flag, do so now */
- if (disable_dev_request) {
- rsf->flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
- VBDEBUG(("TPM: Clearing virt dev-switch: f%x\n", rsf->flags));
- }
-
- /*
- * The developer_mode value that's passed in is only set by a hardware
- * dev-switch. We should OR it with the virtual switch, whether or not
- * the virtual switch is used. If it's not used, it shouldn't change,
- * so it doesn't matter.
- */
- if (rsf->flags & FLAG_VIRTUAL_DEV_MODE_ON)
- developer_mode = 1;
-
- /*
- * Clear ownership if developer flag has toggled, or if an owner-clear
- * has been requested.
- */
- if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) !=
- (in_flags & FLAG_LAST_BOOT_DEVELOPER)) {
- VBDEBUG(("TPM: Developer flag changed; clearing owner.\n"));
- RETURN_ON_FAILURE(TPMClearAndReenable());
- } else if (clear_tpm_owner_request) {
- VBDEBUG(("TPM: Clearing owner as specifically requested.\n"));
- RETURN_ON_FAILURE(TPMClearAndReenable());
- }
-
- if (developer_mode)
- rsf->flags |= FLAG_LAST_BOOT_DEVELOPER;
- else
- rsf->flags &= ~FLAG_LAST_BOOT_DEVELOPER;
-
-
- /* If firmware space is dirty, flush it back to the TPM */
- if (rsf->flags != in_flags) {
- VBDEBUG(("TPM: Updating firmware space.\n"));
- RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
- }
-
- VBDEBUG(("TPM: SetupTPM() succeeded\n"));
- return TPM_SUCCESS;
-}
-
#ifdef DISABLE_ROLLBACK_TPM
/* Dummy implementations which don't support TPM rollback protection */
-uint32_t RollbackS3Resume(void)
-{
-#ifndef CHROMEOS_ENVIRONMENT
- /*
- * Initialize the TPM, but ignore return codes. In ChromeOS
- * environment, don't even talk to the TPM.
- */
- TlclLibInit();
- TlclResume();
-#endif
- return TPM_SUCCESS;
-}
-
-uint32_t RollbackFirmwareSetup(int is_hw_dev,
- int disable_dev_request,
- int clear_tpm_owner_request,
- int *is_virt_dev, uint32_t *version)
-{
-#ifndef CHROMEOS_ENVIRONMENT
- /*
- * Initialize the TPM, but ignores return codes. In ChromeOS
- * environment, don't even talk to the TPM.
- */
- TlclLibInit();
- TlclStartup();
- TlclContinueSelfTest();
-#endif
- *is_virt_dev = 0;
- *version = 0;
- return TPM_SUCCESS;
-}
-
-uint32_t RollbackFirmwareWrite(uint32_t version)
-{
- return TPM_SUCCESS;
-}
-
-uint32_t RollbackFirmwareLock(void)
-{
- return TPM_SUCCESS;
-}
-
uint32_t RollbackKernelRead(uint32_t* version)
{
*version = 0;
@@ -545,16 +250,6 @@ uint32_t RollbackKernelWrite(uint32_t version)
return TPM_SUCCESS;
}
-uint32_t RollbackBackupRead(uint8_t *raw)
-{
- return TPM_SUCCESS;
-}
-
-uint32_t RollbackBackupWrite(uint8_t *raw)
-{
- return TPM_SUCCESS;
-}
-
uint32_t RollbackKernelLock(int recovery_mode)
{
return TPM_SUCCESS;
@@ -568,57 +263,6 @@ uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp)
#else
-uint32_t RollbackS3Resume(void)
-{
- uint32_t result;
- RETURN_ON_FAILURE(TlclLibInit());
- result = TlclResume();
- if (result == TPM_E_INVALID_POSTINIT) {
- /*
- * We're on a platform where the TPM maintains power in S3, so
- * it's already initialized.
- */
- return TPM_SUCCESS;
- }
- return result;
-}
-
-uint32_t RollbackFirmwareSetup(int is_hw_dev,
- int disable_dev_request,
- int clear_tpm_owner_request,
- int *is_virt_dev, uint32_t *version)
-{
- RollbackSpaceFirmware rsf;
-
- /* Set version to 0 in case we fail */
- *version = 0;
-
- RETURN_ON_FAILURE(SetupTPM(is_hw_dev, disable_dev_request,
- clear_tpm_owner_request, &rsf));
- Memcpy(version, &rsf.fw_versions, sizeof(*version));
- *is_virt_dev = (rsf.flags & FLAG_VIRTUAL_DEV_MODE_ON) ? 1 : 0;
- VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)*version));
- return TPM_SUCCESS;
-}
-
-uint32_t RollbackFirmwareWrite(uint32_t version)
-{
- RollbackSpaceFirmware rsf;
- uint32_t old_version;
-
- RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf));
- Memcpy(&old_version, &rsf.fw_versions, sizeof(old_version));
- VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)old_version,
- (int)version));
- Memcpy(&rsf.fw_versions, &version, sizeof(version));
- return WriteSpaceFirmware(&rsf);
-}
-
-uint32_t RollbackFirmwareLock(void)
-{
- return TlclSetGlobalLock();
-}
-
uint32_t RollbackKernelRead(uint32_t* version)
{
RollbackSpaceKernel rsk;
@@ -664,29 +308,6 @@ uint32_t RollbackKernelWrite(uint32_t version)
return WriteSpaceKernel(&rsk);
}
-/*
- * We don't really care whether the TPM owner has been messing with this or
- * not. We lock it along with the Kernel space just to avoid problems, but it's
- * only useful in dev-mode and only when the battery has been drained
- * completely. There aren't any security issues. It's just in the TPM because
- * we don't have any other place to keep it.
- */
-uint32_t RollbackBackupRead(uint8_t *raw)
-{
- uint32_t r;
- r = TlclRead(BACKUP_NV_INDEX, raw, BACKUP_NV_SIZE);
- VBDEBUG(("TPM: %s returning 0x%x\n", __func__, r));
- return r;
-}
-
-uint32_t RollbackBackupWrite(uint8_t *raw)
-{
- uint32_t r;
- r = TlclWrite(BACKUP_NV_INDEX, raw, BACKUP_NV_SIZE);
- VBDEBUG(("TPM: %s returning 0x%x\n", __func__, r));
- return r;
-}
-
uint32_t RollbackKernelLock(int recovery_mode)
{
static int kernel_locked = 0;