summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuigi Semenzato <semenzato@chromium.org>2011-05-23 23:34:17 -0700
committerNick Sanders <nsanders@chromium.org>2011-05-25 17:21:13 -0700
commit7b90cf3f009de938d3412709fda382f77eae8784 (patch)
tree02c1899c482ee40d2c30249fcd3d4f906e4723e3
parenta78123412ded7c6ba62f6564193c45de36a22046 (diff)
downloadvboot-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.h5
-rw-r--r--firmware/lib/rollback_index.c60
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
}
}