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; }