| OLD | NEW |
| 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 * Use of this source code is governed by a BSD-style license that can be | 2 * Use of this source code is governed by a BSD-style license that can be |
| 3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
| 4 * | 4 * |
| 5 * Functions for querying, manipulating and locking rollback indices | 5 * Functions for querying, manipulating and locking rollback indices |
| 6 * stored in the TPM NVRAM. | 6 * stored in the TPM NVRAM. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #include "rollback_index.h" | 9 #include "rollback_index.h" |
| 10 | 10 |
| 11 #include <stdint.h> | 11 #include <stdint.h> |
| 12 | 12 |
| 13 #include "utility.h" | 13 #include "utility.h" |
| 14 #include "tlcl.h" | 14 #include "tlcl.h" |
| 15 #include "tss_constants.h" | 15 #include "tss_constants.h" |
| 16 | 16 |
| 17 uint16_t g_firmware_key_version = 0; | 17 uint16_t g_firmware_key_version = 0; |
| 18 uint16_t g_firmware_version = 0; | 18 uint16_t g_firmware_version = 0; |
| 19 uint16_t g_kernel_key_version = 0; | 19 uint16_t g_kernel_key_version = 0; |
| 20 uint16_t g_kernel_version = 0; | 20 uint16_t g_kernel_version = 0; |
| 21 | 21 |
| 22 #define RETURN_ON_FAILURE(tpm_command) do { \ | 22 #define RETURN_ON_FAILURE(tpm_command) do { \ |
| 23 uint32_t result; \ | 23 uint32_t result; \ |
| 24 if ((result = tpm_command) != TPM_SUCCESS) {\ | 24 if ((result = (tpm_command)) != TPM_SUCCESS) { \ |
| 25 return result; \ | 25 return result; \ |
| 26 } \ | 26 } \ |
| 27 } while (0) | 27 } while (0) |
| 28 | 28 |
| 29 static uint32_t InitializeKernelVersionsSpaces(void) { |
| 30 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX, |
| 31 TPM_NV_PER_PPWRITE, KERNEL_SPACE_SIZE)); |
| 32 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, KERNEL_SPACE_INIT_DATA, |
| 33 KERNEL_SPACE_SIZE)); |
| 34 return TPM_SUCCESS; |
| 35 } |
| 36 |
| 37 static uint32_t GetSpacesInitialized(int* initialized) { |
| 38 uint32_t space_holder; |
| 39 uint32_t result; |
| 40 result = TlclRead(TPM_IS_INITIALIZED_NV_INDEX, |
| 41 (uint8_t*) &space_holder, sizeof(space_holder)); |
| 42 switch (result) { |
| 43 case TPM_SUCCESS: |
| 44 *initialized = 1; |
| 45 break; |
| 46 case TPM_E_BADINDEX: |
| 47 *initialized = 0; |
| 48 result = TPM_SUCCESS; |
| 49 break; |
| 50 } |
| 51 return result; |
| 52 } |
| 53 |
| 29 static uint32_t InitializeSpaces(void) { | 54 static uint32_t InitializeSpaces(void) { |
| 30 uint32_t zero = 0; | 55 uint32_t zero = 0; |
| 31 uint32_t space_holder; | |
| 32 uint32_t firmware_perm = TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE; | 56 uint32_t firmware_perm = TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE; |
| 33 uint32_t kernel_perm = TPM_NV_PER_PPWRITE; | |
| 34 | 57 |
| 35 debug("Initializing spaces\n"); | 58 debug("Initializing spaces\n"); |
| 36 | 59 |
| 37 if (TlclRead(TPM_IS_INITIALIZED_NV_INDEX, | |
| 38 (uint8_t*) &space_holder, sizeof(space_holder)) == TPM_SUCCESS) { | |
| 39 /* Spaces are already initialized, so this is an error */ | |
| 40 return 0; | |
| 41 } | |
| 42 | |
| 43 RETURN_ON_FAILURE(TlclSetNvLocked()); | 60 RETURN_ON_FAILURE(TlclSetNvLocked()); |
| 44 | 61 |
| 45 RETURN_ON_FAILURE(TlclDefineSpace(FIRMWARE_VERSIONS_NV_INDEX, | 62 RETURN_ON_FAILURE(TlclDefineSpace(FIRMWARE_VERSIONS_NV_INDEX, |
| 46 firmware_perm, sizeof(uint32_t))); | 63 firmware_perm, sizeof(uint32_t))); |
| 47 RETURN_ON_FAILURE(TlclWrite(FIRMWARE_VERSIONS_NV_INDEX, | 64 RETURN_ON_FAILURE(TlclWrite(FIRMWARE_VERSIONS_NV_INDEX, |
| 48 (uint8_t*) &zero, sizeof(uint32_t))); | 65 (uint8_t*) &zero, sizeof(uint32_t))); |
| 49 | 66 |
| 50 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX, | 67 RETURN_ON_FAILURE(InitializeKernelVersionsSpaces()); |
| 51 kernel_perm, sizeof(uint32_t))); | |
| 52 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, (uint8_t*) &zero, | |
| 53 sizeof(uint32_t))); | |
| 54 | 68 |
| 55 /* The space KERNEL_VERSIONS_BACKUP_NV_INDEX is used to protect the kernel | 69 /* The space KERNEL_VERSIONS_BACKUP_NV_INDEX is used to protect the kernel |
| 56 * versions when entering recovery mode. The content of space | 70 * versions when entering recovery mode. The content of space |
| 57 * KERNEL_BACKUP_IS_VALID determines whether the backup value (1) or the | 71 * KERNEL_MUST_USE_BACKUP determines whether the backup value (1) or the |
| 58 * regular value (0) should be trusted. | 72 * regular value (0) should be trusted. |
| 59 */ | 73 */ |
| 60 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_BACKUP_NV_INDEX, | 74 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
| 61 firmware_perm, sizeof(uint32_t))); | 75 firmware_perm, sizeof(uint32_t))); |
| 62 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, | 76 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
| 63 (uint8_t*) &zero, sizeof(uint32_t))); | 77 (uint8_t*) &zero, sizeof(uint32_t))); |
| 64 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_BACKUP_IS_VALID_NV_INDEX, | 78 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_MUST_USE_BACKUP_NV_INDEX, |
| 65 firmware_perm, sizeof(uint32_t))); | 79 firmware_perm, sizeof(uint32_t))); |
| 66 RETURN_ON_FAILURE(TlclWrite(KERNEL_BACKUP_IS_VALID_NV_INDEX, | 80 RETURN_ON_FAILURE(TlclWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, |
| 67 (uint8_t*) &zero, sizeof(uint32_t))); | 81 (uint8_t*) &zero, sizeof(uint32_t))); |
| 68 | 82 |
| 69 /* The space TPM_IS_INITIALIZED_NV_INDEX is used to indicate that the TPM | 83 /* The space TPM_IS_INITIALIZED_NV_INDEX is used to indicate that the TPM |
| 70 * initialization has completed. Without it we cannot be sure that the last | 84 * initialization has completed. Without it we cannot be sure that the last |
| 71 * space to be created was also initialized (power could have been lost right | 85 * space to be created was also initialized (power could have been lost right |
| 72 * after its creation). | 86 * after its creation). |
| 73 */ | 87 */ |
| 74 RETURN_ON_FAILURE(TlclDefineSpace(TPM_IS_INITIALIZED_NV_INDEX, | 88 RETURN_ON_FAILURE(TlclDefineSpace(TPM_IS_INITIALIZED_NV_INDEX, |
| 75 firmware_perm, sizeof(uint32_t))); | 89 firmware_perm, sizeof(uint32_t))); |
| 76 return TPM_SUCCESS; | 90 return TPM_SUCCESS; |
| 77 } | 91 } |
| 78 | 92 |
| 79 /* Enters the recovery mode. If |unlocked| is true, there is some problem with | 93 /* Enters the recovery mode. If |unlocked| is true, there is some problem with |
| 80 * the TPM, so do not attempt to do any more TPM operations, and particularly | 94 * the TPM, so do not attempt to do any more TPM operations, and particularly |
| 81 * do not set bGlobalLock. | 95 * do not set bGlobalLock. |
| 82 */ | 96 */ |
| 83 static void EnterRecovery(int unlocked) { | 97 void EnterRecovery(int unlocked) { |
| 84 uint32_t combined_versions; | 98 uint32_t combined_versions; |
| 85 uint32_t backup_versions; | 99 uint32_t backup_versions; |
| 86 uint32_t backup_is_valid; | 100 uint32_t must_use_backup; |
| 101 uint32_t result; |
| 87 | 102 |
| 88 if (!unlocked) { | 103 if (!unlocked) { |
| 89 /* Saves the kernel versions and indicates that we should trust the saved | 104 /* Saves the kernel versions and indicates that we should trust the saved |
| 90 * ones. | 105 * ones. |
| 91 */ | 106 */ |
| 92 TlclRead(KERNEL_VERSIONS_NV_INDEX, | 107 if (TlclRead(KERNEL_VERSIONS_NV_INDEX, (uint8_t*) &combined_versions, |
| 93 (uint8_t*) &combined_versions, sizeof(uint32_t)); | 108 sizeof(uint32_t)) != TPM_SUCCESS) |
| 94 TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, | 109 goto recovery_mode; |
| 95 (uint8_t*) &backup_versions, sizeof(uint32_t)); | 110 if (TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, (uint8_t*) &backup_versions, |
| 96 /* We could unconditional writes of both KERNEL_VERSIONS_BACKUP and | 111 sizeof(uint32_t)) != TPM_SUCCESS) |
| 97 * KERNEL_BACKUP_IS_VALID, but this is more robust. | 112 goto recovery_mode; |
| 98 */ | 113 /* Avoids idempotent writes. */ |
| 99 if (combined_versions != backup_versions) { | 114 if (combined_versions != backup_versions) { |
| 100 TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, | 115 result = TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
| 101 (uint8_t*) &combined_versions, sizeof(uint32_t)); | 116 (uint8_t*) &combined_versions, sizeof(uint32_t)); |
| 117 if (result == TPM_E_MAXNVWRITES) { |
| 118 goto forceclear_and_reboot; |
| 119 } else if (result != TPM_SUCCESS) { |
| 120 goto recovery_mode; |
| 121 } |
| 102 } | 122 } |
| 103 | 123 |
| 104 TlclRead(KERNEL_BACKUP_IS_VALID_NV_INDEX, | 124 if (TlclRead(KERNEL_MUST_USE_BACKUP_NV_INDEX, (uint8_t*) &must_use_backup, |
| 105 (uint8_t*) &backup_is_valid, sizeof(uint32_t)); | 125 sizeof(uint32_t)) != TPM_SUCCESS) |
| 106 if (backup_is_valid != 1) { | 126 goto recovery_mode; |
| 107 backup_is_valid = 1; | 127 if (must_use_backup != 1) { |
| 108 TlclWrite(KERNEL_BACKUP_IS_VALID_NV_INDEX, (uint8_t*) &backup_is_valid, | 128 must_use_backup = 1; |
| 109 sizeof(uint32_t)); | 129 result = TlclWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, |
| 130 (uint8_t*) &must_use_backup, sizeof(uint32_t)); |
| 131 if (result == TPM_E_MAXNVWRITES) { |
| 132 goto forceclear_and_reboot; |
| 133 } else if (result != TPM_SUCCESS) { |
| 134 goto recovery_mode; |
| 135 } |
| 110 } | 136 } |
| 111 /* Protects the firmware and backup kernel versions. */ | 137 /* Protects the firmware and backup kernel versions. */ |
| 112 LockFirmwareVersions(); | 138 if (LockFirmwareVersions() != TPM_SUCCESS) |
| 139 goto recovery_mode; |
| 113 } | 140 } |
| 141 |
| 142 recovery_mode: |
| 114 debug("entering recovery mode"); | 143 debug("entering recovery mode"); |
| 115 | 144 |
| 116 /* TODO(nelson): code for entering recovery mode. */ | 145 /* TODO(nelson): code for entering recovery mode. */ |
| 146 |
| 147 forceclear_and_reboot: |
| 148 if (TlclForceClear() != TPM_SUCCESS) { |
| 149 goto recovery_mode; |
| 150 } |
| 151 /* TODO: reboot */ |
| 117 } | 152 } |
| 118 | 153 |
| 119 static uint32_t GetTPMRollbackIndices(void) { | 154 static uint32_t GetTPMRollbackIndices(void) { |
| 120 uint32_t backup_is_valid; | |
| 121 uint32_t firmware_versions; | 155 uint32_t firmware_versions; |
| 122 uint32_t kernel_versions; | 156 uint32_t kernel_versions; |
| 123 | 157 |
| 124 if (TlclRead(KERNEL_BACKUP_IS_VALID_NV_INDEX, (uint8_t*) &backup_is_valid, | |
| 125 sizeof(uint32_t)) != TPM_SUCCESS) { | |
| 126 EnterRecovery(1); | |
| 127 } | |
| 128 if (backup_is_valid) { | |
| 129 /* We reach this path if the previous boot went into recovery mode and we | |
| 130 * made a copy of the kernel versions to protect them. | |
| 131 */ | |
| 132 uint32_t protected_combined_versions; | |
| 133 uint32_t unsafe_combined_versions; | |
| 134 uint32_t result; | |
| 135 uint32_t zero = 0; | |
| 136 if (TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, | |
| 137 (uint8_t*) &protected_combined_versions, | |
| 138 sizeof(uint32_t)) != TPM_SUCCESS) { | |
| 139 EnterRecovery(1); | |
| 140 } | |
| 141 result = TlclRead(KERNEL_VERSIONS_NV_INDEX, | |
| 142 (uint8_t*) &unsafe_combined_versions, sizeof(uint32_t)); | |
| 143 if (result == TPM_E_BADINDEX) { | |
| 144 /* Jeez, someone removed the space. This is either hostile or extremely | |
| 145 * incompetent. Foo to them. Politeness and lack of an adequate | |
| 146 * character set prevent me from expressing my true feelings. | |
| 147 */ | |
| 148 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX, | |
| 149 TPM_NV_PER_PPWRITE, | |
| 150 sizeof(uint32_t))); | |
| 151 } else if (result != TPM_SUCCESS) { | |
| 152 EnterRecovery(1); | |
| 153 } | |
| 154 if (result == TPM_E_BADINDEX || | |
| 155 protected_combined_versions != unsafe_combined_versions) { | |
| 156 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, | |
| 157 (uint8_t*) &protected_combined_versions, | |
| 158 sizeof(uint32_t))); | |
| 159 } | |
| 160 /* We recovered the backed-up versions and now we can reset the | |
| 161 * BACKUP_IS_VALID flag. | |
| 162 */ | |
| 163 RETURN_ON_FAILURE(TlclWrite(KERNEL_BACKUP_IS_VALID_NV_INDEX, | |
| 164 (uint8_t*) &zero, 0)); | |
| 165 | |
| 166 if (!TlclIsOwned()) { | |
| 167 /* Must ForceClear and reboot to prevent from running into the 64-write | |
| 168 * limit. | |
| 169 */ | |
| 170 RETURN_ON_FAILURE(TlclForceClear()); | |
| 171 /* Reboot! No return */ | |
| 172 return 9999; | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 /* We perform the reads, making sure they succeed. A failure means that the | 158 /* We perform the reads, making sure they succeed. A failure means that the |
| 177 * rollback index locations are missing or somehow messed up. We let the | 159 * rollback index locations are missing or somehow messed up. We let the |
| 178 * caller deal with that. | 160 * caller deal with that. |
| 179 */ | 161 */ |
| 180 RETURN_ON_FAILURE(TlclRead(FIRMWARE_VERSIONS_NV_INDEX, | 162 RETURN_ON_FAILURE(TlclRead(FIRMWARE_VERSIONS_NV_INDEX, |
| 181 (uint8_t*) &firmware_versions, | 163 (uint8_t*) &firmware_versions, |
| 182 sizeof(firmware_versions))); | 164 sizeof(firmware_versions))); |
| 183 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, | 165 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, |
| 184 (uint8_t*) &kernel_versions, | 166 (uint8_t*) &kernel_versions, |
| 185 sizeof(kernel_versions))); | 167 sizeof(kernel_versions))); |
| 186 | 168 |
| 187 g_firmware_key_version = firmware_versions >> 16; | 169 g_firmware_key_version = firmware_versions >> 16; |
| 188 g_firmware_version = firmware_versions && 0xffff; | 170 g_firmware_version = firmware_versions && 0xffff; |
| 189 g_kernel_key_version = kernel_versions >> 16; | 171 g_kernel_key_version = kernel_versions >> 16; |
| 190 g_kernel_version = kernel_versions && 0xffff; | 172 g_kernel_version = kernel_versions && 0xffff; |
| 191 | 173 |
| 192 return TPM_SUCCESS; | 174 return TPM_SUCCESS; |
| 193 } | 175 } |
| 194 | 176 |
| 177 /* Checks if the kernel version space has been mucked with. If it has, |
| 178 * reconstructs it using the backup value. |
| 179 */ |
| 180 uint32_t RecoverKernelSpace(void) { |
| 181 uint32_t perms = 0; |
| 182 uint8_t buffer[KERNEL_SPACE_SIZE]; |
| 183 int read_OK = 0; |
| 184 int perms_OK = 0; |
| 185 uint32_t backup_combined_versions; |
| 186 uint32_t must_use_backup; |
| 195 | 187 |
| 196 uint32_t SetupTPM(void) { | 188 RETURN_ON_FAILURE(TlclRead(KERNEL_MUST_USE_BACKUP_NV_INDEX, |
| 189 (uint8_t*) &must_use_backup, sizeof(uint32_t))); |
| 190 /* must_use_backup is true if the previous boot entered recovery mode. */ |
| 191 |
| 192 read_OK = TlclRead(KERNEL_VERSIONS_NV_INDEX, (uint8_t*) &buffer, |
| 193 KERNEL_SPACE_SIZE) == TPM_SUCCESS; |
| 194 if (read_OK) { |
| 195 RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_VERSIONS_NV_INDEX, &perms)); |
| 196 perms_OK = perms == TPM_NV_PER_PPWRITE; |
| 197 } |
| 198 if (!must_use_backup && read_OK && perms_OK && |
| 199 !Memcmp(buffer + sizeof(uint32_t), KERNEL_SPACE_UID, |
| 200 KERNEL_SPACE_UID_SIZE)) { |
| 201 /* Everything is fine. This is the normal, frequent path. */ |
| 202 return TPM_SUCCESS; |
| 203 } |
| 204 |
| 205 /* Either we detected that something went wrong, or we cannot trust the |
| 206 * PP-protected kernel space. Attempts to fix. It is not always necessary |
| 207 * to redefine the space, but we might as well, since this path should be |
| 208 * taken quite seldom (after recovery mode and after an attack). |
| 209 */ |
| 210 RETURN_ON_FAILURE(InitializeKernelVersionsSpaces()); |
| 211 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
| 212 (uint8_t*) &backup_combined_versions, |
| 213 sizeof(uint32_t))); |
| 214 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, |
| 215 (uint8_t*) &backup_combined_versions, |
| 216 sizeof(uint32_t))); |
| 217 if (must_use_backup) { |
| 218 uint32_t zero = 0; |
| 219 RETURN_ON_FAILURE(TlclWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, |
| 220 (uint8_t*) &zero, 0)); |
| 221 |
| 222 } |
| 223 return TPM_SUCCESS; |
| 224 } |
| 225 |
| 226 static uint32_t BackupKernelSpace(void) { |
| 227 uint32_t kernel_versions; |
| 228 uint32_t backup_versions; |
| 229 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, |
| 230 (uint8_t*) &kernel_versions, sizeof(uint32_t))); |
| 231 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
| 232 (uint8_t*) &backup_versions, sizeof(uint32_t))); |
| 233 if (kernel_versions == backup_versions) { |
| 234 return TPM_SUCCESS; |
| 235 } else if (kernel_versions < backup_versions) { |
| 236 /* This cannot happen. We're screwed. */ |
| 237 return TPM_E_INTERNAL_INCONSISTENCY; |
| 238 } |
| 239 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
| 240 (uint8_t*) &kernel_versions, sizeof(uint32_t))); |
| 241 return TPM_SUCCESS; |
| 242 } |
| 243 |
| 244 static uint32_t SetupTPM_(void) { |
| 197 uint8_t disable; | 245 uint8_t disable; |
| 198 uint8_t deactivated; | 246 uint8_t deactivated; |
| 199 TlclLibInit(); | 247 TlclLibInit(); |
| 200 RETURN_ON_FAILURE(TlclStartup()); | 248 RETURN_ON_FAILURE(TlclStartup()); |
| 201 RETURN_ON_FAILURE(TlclContinueSelfTest()); | 249 RETURN_ON_FAILURE(TlclContinueSelfTest()); |
| 202 RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); | 250 RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); |
| 203 /* Check that the TPM is enabled and activated. */ | 251 /* Checks that the TPM is enabled and activated. */ |
| 204 RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated)); | 252 RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated)); |
| 205 if (disable || deactivated) { | 253 if (disable || deactivated) { |
| 206 RETURN_ON_FAILURE(TlclSetEnable()); | 254 RETURN_ON_FAILURE(TlclSetEnable()); |
| 207 RETURN_ON_FAILURE(TlclSetDeactivated(0)); | 255 RETURN_ON_FAILURE(TlclSetDeactivated(0)); |
| 208 /* TODO: Reboot now */ | 256 /* TODO: Reboot */ |
| 209 return 9999; | 257 return 9999; |
| 210 } | 258 } |
| 211 /* We expect this to fail the first time we run on a device, indicating that | 259 /* We expect this to fail the first time we run on a device, indicating that |
| 212 * the TPM has not been initialized yet. */ | 260 * the TPM has not been initialized yet. */ |
| 213 if (GetTPMRollbackIndices() != TPM_SUCCESS) { | 261 if (RecoverKernelSpace() != TPM_SUCCESS) { |
| 214 /* If InitializeSpaces() fails (possibly because it had been executed | 262 int initialized = 0; |
| 215 * already), something is wrong. */ | 263 RETURN_ON_FAILURE(GetSpacesInitialized(&initialized)); |
| 216 RETURN_ON_FAILURE(InitializeSpaces()); | 264 if (initialized) { |
| 217 /* Try again. */ | 265 return TPM_E_ALREADY_INITIALIZED; |
| 218 RETURN_ON_FAILURE(GetTPMRollbackIndices()); | 266 } else { |
| 267 RETURN_ON_FAILURE(InitializeSpaces()); |
| 268 RETURN_ON_FAILURE(RecoverKernelSpace()); |
| 269 } |
| 219 } | 270 } |
| 271 RETURN_ON_FAILURE(BackupKernelSpace()); |
| 272 RETURN_ON_FAILURE(GetTPMRollbackIndices()); |
| 220 | 273 |
| 221 return TPM_SUCCESS; | 274 return TPM_SUCCESS; |
| 222 } | 275 } |
| 223 | 276 |
| 277 uint32_t SetupTPM(void) { |
| 278 uint32_t result = SetupTPM_(); |
| 279 if (result == TPM_E_MAXNVWRITES) { |
| 280 /* ForceClears and reboots */ |
| 281 RETURN_ON_FAILURE(TlclForceClear()); |
| 282 /* TODO: reboot */ |
| 283 return 9999; |
| 284 } else { |
| 285 return result; |
| 286 } |
| 287 } |
| 288 |
| 224 uint32_t GetStoredVersions(int type, uint16_t* key_version, uint16_t* version) { | 289 uint32_t GetStoredVersions(int type, uint16_t* key_version, uint16_t* version) { |
| 225 | 290 |
| 226 /* TODO: should verify that SetupTPM() has been called. Note that | 291 /* TODO: should verify that SetupTPM() has been called. Note that |
| 227 * SetupTPM() does hardware setup AND sets global variables. When we | 292 * SetupTPM() does hardware setup AND sets global variables. When we |
| 228 * get down into kernel verification, the hardware setup persists, but | 293 * get down into kernel verification, the hardware setup persists, but |
| 229 * we don't have access to the global variables. So I guess we DO need | 294 * we don't have access to the global variables. So I guess we DO need |
| 230 * to call SetupTPM() there, and have it be smart enough not to redo the | 295 * to call SetupTPM() there, and have it be smart enough not to redo the |
| 231 * hardware init, but it still needs to re-read the flags... */ | 296 * hardware init, but it still needs to re-read the flags... */ |
| 232 | 297 |
| 233 switch (type) { | 298 switch (type) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 250 case FIRMWARE_VERSIONS: | 315 case FIRMWARE_VERSIONS: |
| 251 RETURN_ON_FAILURE(TlclWrite(FIRMWARE_VERSIONS_NV_INDEX, | 316 RETURN_ON_FAILURE(TlclWrite(FIRMWARE_VERSIONS_NV_INDEX, |
| 252 (uint8_t*) &combined_version, | 317 (uint8_t*) &combined_version, |
| 253 sizeof(uint32_t))); | 318 sizeof(uint32_t))); |
| 254 break; | 319 break; |
| 255 | 320 |
| 256 case KERNEL_VERSIONS: | 321 case KERNEL_VERSIONS: |
| 257 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, | 322 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, |
| 258 (uint8_t*) &combined_version, | 323 (uint8_t*) &combined_version, |
| 259 sizeof(uint32_t))); | 324 sizeof(uint32_t))); |
| 260 break; | |
| 261 } | |
| 262 /* TODO(semenzato): change TlclIsOwned to return a TPM status directly and | |
| 263 * the "owned" value by reference. | |
| 264 */ | |
| 265 if (!TlclIsOwned()) { | |
| 266 RETURN_ON_FAILURE(TlclForceClear()); | |
| 267 /* TODO: Reboot here. No return. */ | |
| 268 return 9999; | |
| 269 } | 325 } |
| 270 return TPM_SUCCESS; | 326 return TPM_SUCCESS; |
| 271 } | 327 } |
| 272 | 328 |
| 273 uint32_t LockFirmwareVersions() { | 329 uint32_t LockFirmwareVersions() { |
| 274 return TlclSetGlobalLock(); | 330 return TlclSetGlobalLock(); |
| 275 } | 331 } |
| 276 | 332 |
| 277 uint32_t LockKernelVersionsByLockingPP() { | 333 uint32_t LockKernelVersionsByLockingPP() { |
| 278 return TlclLockPhysicalPresence(); | 334 return TlclLockPhysicalPresence(); |
| 279 } | 335 } |
| OLD | NEW |