New anti-rollback strategy (no TPM NVRAM write cycles for locking).
Review URL: http://codereview.chromium.org/2225005
diff --git a/vboot_firmware/include/rollback_index.h b/vboot_firmware/include/rollback_index.h
index d4e47ac..2633ab7 100644
--- a/vboot_firmware/include/rollback_index.h
+++ b/vboot_firmware/include/rollback_index.h
@@ -31,6 +31,7 @@
void SetupTPM(void);
uint16_t GetStoredVersion(int type);
int WriteStoredVersion(int type, uint16_t version);
-void LockStoredVersion(int type);
+void LockFirmwareVersions();
+void LockKernelVersionsByLockingPP();
#endif /* VBOOT_REFERENCE_ROLLBACK_INDEX_H_ */
diff --git a/vboot_firmware/include/tlcl.h b/vboot_firmware/include/tlcl.h
index 362b61e..655b877 100644
--- a/vboot_firmware/include/tlcl.h
+++ b/vboot_firmware/include/tlcl.h
@@ -66,6 +66,10 @@
*/
void TlclAssertPhysicalPresence(void);
+/* Turns off physical presence and locks it off until next reboot.
+ */
+uint32_t TlclLockPhysicalPresence(void);
+
/* Sets the nvLocked bit.
*/
void TlclSetNvLocked(void);
@@ -78,16 +82,20 @@
*/
void TlclForceClear(void);
-/* Issues a PhysicalEnable.
+/* Issues a SetEnable.
*/
-void TlclPhysicalEnable(void);
+void TlclSetEnable(void);
-/* Issues a PhysicalSetDeactivated. Pass 0 to activate. Returns result code.
+/* Issues a SetDeactivated. Pass 0 to activate. Returns result code.
*/
-int TlclPhysicalSetDeactivated(uint8_t flag);
+int TlclSetDeactivated(uint8_t flag);
/* Gets some permanent flags of interest. (Add more here as needed.)
*/
int TlclGetFlags(uint8_t* disable, uint8_t* deactivated);
+/* Sets the bGlobalLock flag, which only a reboot can clear.
+ */
+uint32_t TlclSetGlobalLock(void);
+
#endif /* TPM_LITE_TLCL_H_ */
diff --git a/vboot_firmware/lib/firmware_image_fw.c b/vboot_firmware/lib/firmware_image_fw.c
index 85b4d35..a8cb646 100644
--- a/vboot_firmware/lib/firmware_image_fw.c
+++ b/vboot_firmware/lib/firmware_image_fw.c
@@ -289,14 +289,11 @@
}
}
}
- /* Lock Firmware TPM rollback indices from further writes. */
- /* TODO(gauravsh): Figure out if these can be combined into one
- * 32-bit location since we seem to always use them together. This can help
- * us minimize the number of NVRAM writes/locks (which are limited over flash
- * memory lifetimes.
+ /* Lock Firmware TPM rollback indices from further writes. In this design,
+ * this is done by setting the globalLock bit, which is cleared only by
+ * TPM_Init at reboot.
*/
- LockStoredVersion(FIRMWARE_KEY_VERSION);
- LockStoredVersion(FIRMWARE_VERSION);
+ LockFirmwareVersions();
/* Determine which firmware (if any) to jump to.
*
diff --git a/vboot_firmware/lib/kernel_image_fw.c b/vboot_firmware/lib/kernel_image_fw.c
index 5a6afcf..6cfb197 100644
--- a/vboot_firmware/lib/kernel_image_fw.c
+++ b/vboot_firmware/lib/kernel_image_fw.c
@@ -447,13 +447,12 @@
try_kernel[i]->boot_priority = 0;
} /* for loop. */
- /* Lock Kernel TPM rollback indices from further writes.
- * TODO(gauravsh): Figure out if these can be combined into one
- * 32-bit location since we seem to always use them together. This can help
- * us minimize the number of NVRAM writes/locks (which are limited over flash
- * memory lifetimes.
+ /* Lock Kernel TPM rollback indices from further writes. In this design,
+ * this is tied to locking physical presence---so (software) physical
+ * presence cannot be asserted after this point. This is a big side effect,
+ * so we want to make it clear in the function name.
+ * TODO(gauravsh): figure out better abstractions.
*/
- LockStoredVersion(KERNEL_KEY_VERSION);
- LockStoredVersion(KERNEL_VERSION);
+ LockKernelVersionsByLockingPP();
return kernel_to_boot;
}
diff --git a/vboot_firmware/lib/rollback_index.c b/vboot_firmware/lib/rollback_index.c
index 2d7fd8e..89e97a3 100644
--- a/vboot_firmware/lib/rollback_index.c
+++ b/vboot_firmware/lib/rollback_index.c
@@ -21,21 +21,23 @@
static void InitializeSpaces(void) {
uint16_t zero = 0;
- uint32_t perm = TPM_NV_PER_WRITE_STCLEAR | TPM_NV_PER_PPWRITE;
+ uint32_t firmware_perm = TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE;
+ uint32_t kernel_perm = TPM_NV_PER_PPWRITE;
debug("Initializing spaces\n");
TlclSetNvLocked(); /* useful only the first time */
- TlclDefineSpace(FIRMWARE_KEY_VERSION_NV_INDEX, perm, sizeof(uint16_t));
+ TlclDefineSpace(FIRMWARE_KEY_VERSION_NV_INDEX,
+ firmware_perm, sizeof(uint16_t));
TlclWrite(FIRMWARE_KEY_VERSION_NV_INDEX, (uint8_t*) &zero, sizeof(uint16_t));
- TlclDefineSpace(FIRMWARE_VERSION_NV_INDEX, perm, sizeof(uint16_t));
+ TlclDefineSpace(FIRMWARE_VERSION_NV_INDEX, firmware_perm, sizeof(uint16_t));
TlclWrite(FIRMWARE_VERSION_NV_INDEX, (uint8_t*) &zero, sizeof(uint16_t));
- TlclDefineSpace(KERNEL_KEY_VERSION_NV_INDEX, perm, sizeof(uint16_t));
+ TlclDefineSpace(KERNEL_KEY_VERSION_NV_INDEX, kernel_perm, sizeof(uint16_t));
TlclWrite(KERNEL_KEY_VERSION_NV_INDEX, (uint8_t*) &zero, sizeof(uint16_t));
- TlclDefineSpace(KERNEL_VERSION_NV_INDEX, perm, sizeof(uint16_t));
+ TlclDefineSpace(KERNEL_VERSION_NV_INDEX, kernel_perm, sizeof(uint16_t));
TlclWrite(KERNEL_VERSION_NV_INDEX, (uint8_t*) &zero, sizeof(uint16_t));
}
@@ -55,8 +57,8 @@
(uint8_t*) &g_firmware_key_version,
sizeof(g_firmware_key_version)) ||
TPM_SUCCESS != TlclRead(FIRMWARE_KEY_VERSION_NV_INDEX,
- (uint8_t*) &g_firmware_key_version,
- sizeof(g_firmware_key_version)) ||
+ (uint8_t*) &g_firmware_key_version,
+ sizeof(g_firmware_key_version)) ||
TPM_SUCCESS != TlclRead(FIRMWARE_KEY_VERSION_NV_INDEX,
(uint8_t*) &g_firmware_key_version,
sizeof(g_firmware_key_version)))
@@ -66,6 +68,8 @@
void SetupTPM(void) {
+ uint8_t disable;
+ uint8_t deactivated;
TlclLibinit();
TlclStartup();
/* TODO(gauravsh): The call to self test should probably be deferred.
@@ -77,8 +81,20 @@
* before the selftest completes. */
TlclSelftestfull();
TlclAssertPhysicalPresence();
+ /* Check that the TPM is enabled and activated. */
+ if(TlclGetFlags(&disable, &deactivated) != TPM_SUCCESS) {
+ debug("failed to get TPM flags");
+ EnterRecovery();
+ }
+ if (disable || deactivated) {
+ TlclSetEnable();
+ if (TlclSetDeactivated(0) != TPM_SUCCESS) {
+ debug("failed to activate TPM");
+ EnterRecovery();
+ }
+ }
if (!GetTPMRollbackIndices()) {
- debug("Ho Ho Ho! We must jump to recovery.");
+ debug("failed to get rollback indices");
EnterRecovery();
}
}
@@ -128,22 +144,16 @@
return 0;
}
-void LockStoredVersion(int type) {
- /* TODO(gauravsh): Add error checking here to make sure TlclWriteLock
- * did not fail. We must jump to recovery in that case.
- */
- switch (type) {
- case FIRMWARE_KEY_VERSION:
- TlclWriteLock(FIRMWARE_KEY_VERSION_NV_INDEX);
- break;
- case FIRMWARE_VERSION:
- TlclWriteLock(FIRMWARE_VERSION_NV_INDEX);
- break;
- case KERNEL_KEY_VERSION:
- TlclWriteLock(KERNEL_KEY_VERSION_NV_INDEX);
- break;
- case KERNEL_VERSION:
- TlclWriteLock(KERNEL_VERSION_NV_INDEX);
- break;
+void LockFirmwareVersions() {
+ if (TlclSetGlobalLock() != TPM_SUCCESS) {
+ debug("failed to set global lock");
+ EnterRecovery();
+ }
+}
+
+void LockKernelVersionsByLockingPP() {
+ if (TlclLockPhysicalPresence() != TPM_SUCCESS) {
+ debug("failed to turn off PP");
+ EnterRecovery();
}
}
diff --git a/vboot_firmware/lib/tlcl.c b/vboot_firmware/lib/tlcl.c
index ff59e23..1b55189 100644
--- a/vboot_firmware/lib/tlcl.c
+++ b/vboot_firmware/lib/tlcl.c
@@ -20,9 +20,11 @@
void TlclWriteLock(uint32_t index) { return; }
void TlclReadLock(uint32_t index) { return; }
void TlclAssertPhysicalPresence(void) { return; }
+uint32_t TlclLockPhysicalPresence(void) { return TPM_SUCCESS; }
void TlclSetNvLocked(void) { return; }
int TlclIsOwned(void) { return 0; }
void TlclForceClear(void) { return; }
-void TlclPhysicalEnable(void) { return; }
-int TlclPhysicalSetDeactivated(uint8_t flag) { return TPM_SUCCESS; }
+uint32_t TlclSetEnable(void) { return TPM_SUCCESS; }
+uint32_t TlclSetDeactivated(int deactivated) { return TPM_SUCCESS; }
+uint32_t TlclSetGlobalLock(void) { return TPM_SUCCESS; }
int TlclGetFlags(uint8_t* disable, uint8_t* deactivated) { return TPM_SUCCESS; }