diff options
author | Luigi Semenzato <semenzato@chromium.org> | 2011-05-23 23:34:17 -0700 |
---|---|---|
committer | Nick Sanders <nsanders@chromium.org> | 2011-05-25 17:21:13 -0700 |
commit | 7b90cf3f009de938d3412709fda382f77eae8784 (patch) | |
tree | 02c1899c482ee40d2c30249fcd3d4f906e4723e3 | |
parent | a78123412ded7c6ba62f6564193c45de36a22046 (diff) | |
download | vboot-0.13.587.B.tar.gz |
Tolerate lack of TPM reset in common cases.0.13.587.B
This is a temporary workaround for Tegra boards that don't reset the TPM
when the CPU is reset. It makes the firmware more lenient when execution
starts with an already locked TPM.
BUG=chromeos-partner:3574
TEST=none (yet)
Change-Id: If6a060595c1eb41e95e0935f8467de8bb6256b12
Reviewed-on: http://gerrit.chromium.org/gerrit/1429
Reviewed-by: Gaurav Shah <gauravsh@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Tested-by: Nick Sanders <nsanders@chromium.org>
-rw-r--r-- | firmware/arch/arm/include/biosincludes.h | 5 | ||||
-rw-r--r-- | firmware/lib/rollback_index.c | 60 |
2 files changed, 64 insertions, 1 deletions
diff --git a/firmware/arch/arm/include/biosincludes.h b/firmware/arch/arm/include/biosincludes.h index 84778e3a..b2793d5f 100644 --- a/firmware/arch/arm/include/biosincludes.h +++ b/firmware/arch/arm/include/biosincludes.h @@ -43,4 +43,9 @@ extern void debug(const char *format, ...); #define UINT64_MAX (UINT64_C(0xffffffffffffffffULL)) #endif +/* This workaround applies to Kaen prototypes and is not expected to be needed + * in the final products. See crosbug.com/15759. + */ +#define TEGRA_SOFT_REBOOT_WORKAROUND + #endif /*__ARCH_ARM_BIOSINCLUDES_H__ */ diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c index 697bd0e7..27b61650 100644 --- a/firmware/lib/rollback_index.c +++ b/firmware/lib/rollback_index.c @@ -15,6 +15,10 @@ static int g_rollback_recovery_mode = 0; +#ifdef TEGRA_SOFT_REBOOT_WORKAROUND +static int soft_reset = 0; +#endif + /* disable MSVC warning on const logical expression (as in } while(0);) */ __pragma(warning (disable: 4127)) @@ -47,6 +51,21 @@ static uint32_t SafeWrite(uint32_t index, const void* data, uint32_t length) { if (result == TPM_E_MAXNVWRITES) { RETURN_ON_FAILURE(TPMClearAndReenable()); return TlclWrite(index, data, length); +#ifdef TEGRA_SOFT_REBOOT_WORKAROUND + } else if ((result == TPM_E_BAD_PRESENCE || + result == TPM_E_AREA_LOCKED) && + soft_reset == 1) { + /* Ignore writes that failed because the TPM wasn't unlocked. + * + * This may have security implications. 1. It may delay updating the + * version number, therefore widening the window for a rollback attack. + * 2. It may prevent noticing transitions between developer mode and normal + * mode, in which case the TPM owner will not be cleared when + * transitioning. See crosbug.com/15759. Note that this code path is not + * taken on systems where a CPU reset implies a TPM reset. + */ + return TPM_SUCCESS; +#endif } else { return result; } @@ -190,7 +209,22 @@ uint32_t SetupTPM(int recovery_mode, int developer_mode, 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 try to + * tolerate this failure, which is possible in most cases. + */ + VBDEBUG(("TPM: soft reset detected\n", result)); + soft_reset = 1; + } 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 @@ -210,7 +244,20 @@ uint32_t SetupTPM(int recovery_mode, int developer_mode, RETURN_ON_FAILURE(TlclContinueSelfTest()); #endif result = TlclAssertPhysicalPresence(); - if (result != 0) { +#ifdef TEGRA_SOFT_REBOOT_WORKAROUND + /* + * If soft_reset is true, the failure to assert PP is expected because the + * TPM is locked from a previous boot. In this case we will never execute + * the PhysicalPresenceCMDEnable below, but that's OK because this is a + * warm boot and at some point in the past we must have cold-booted with + * this firmware (one would hope), so that situation (TPM delivered with PP + * disabled) has already been resolved. + */ + if (soft_reset) { + result = TPM_SUCCESS; + } +#endif + 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. @@ -437,7 +484,18 @@ uint32_t RollbackKernelLock(void) { if (g_rollback_recovery_mode) { return TPM_SUCCESS; } else { +#ifdef TEGRA_SOFT_REBOOT_WORKAROUND + TPM_STCLEAR_FLAGS flags; + uint32_t result = TlclLockPhysicalPresence(); + if (result == TPM_SUCCESS) { + return result; + } + RETURN_ON_FAILURE(TlclGetSTClearFlags(&flags)); + /* Ignore PP locking failure if PP is already locked. */ + return flags.physicalPresenceLock == 1 ? TPM_SUCCESS : result; +#else return TlclLockPhysicalPresence(); +#endif } } |