| 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 "tlcl.h" | 11 #include "tlcl.h" |
| 12 #include "tss_constants.h" | 12 #include "tss_constants.h" |
| 13 #include "utility.h" | 13 #include "utility.h" |
| 14 | 14 |
| 15 static int g_rollback_recovery_mode = 0; | 15 static int g_rollback_recovery_mode = 0; |
| 16 | 16 |
| 17 /* disable MSVC warning on const logical expression (as in } while(0);) */ | 17 /* disable MSVC warning on const logical expression (as in } while(0);) */ |
| 18 __pragma(warning (disable: 4127)) | 18 __pragma(warning (disable: 4127)) |
| 19 | 19 |
| 20 #define RETURN_ON_FAILURE(tpm_command) do { \ | 20 #define RETURN_ON_FAILURE(tpm_command) do { \ |
| 21 uint32_t result; \ | 21 uint32_t result; \ |
| 22 if ((result = (tpm_command)) != TPM_SUCCESS) { \ | 22 if ((result = (tpm_command)) != TPM_SUCCESS) { \ |
| 23 VBDEBUG(("Rollback: %08x returned by " #tpm_command "\n", (int)result)); \ | 23 VBDEBUG(("Rollback: %08x returned by " #tpm_command "\n", (int)result)); \ |
| 24 return result; \ | 24 return result; \ |
| 25 } \ | 25 } \ |
| 26 } while (0) | 26 } while (0) |
| 27 | 27 |
| 28 uint32_t TPMClearAndReenable(void) { | 28 uint32_t TPMClearAndReenable(void) { |
| 29 VBDEBUG(("TPM: Clear and re-enable\n")); |
| 29 RETURN_ON_FAILURE(TlclForceClear()); | 30 RETURN_ON_FAILURE(TlclForceClear()); |
| 30 RETURN_ON_FAILURE(TlclSetEnable()); | 31 RETURN_ON_FAILURE(TlclSetEnable()); |
| 31 RETURN_ON_FAILURE(TlclSetDeactivated(0)); | 32 RETURN_ON_FAILURE(TlclSetDeactivated(0)); |
| 33 |
| 32 return TPM_SUCCESS; | 34 return TPM_SUCCESS; |
| 33 } | 35 } |
| 34 | 36 |
| 35 /* Like TlclWrite(), but checks for write errors due to hitting the 64-write | 37 /* Like TlclWrite(), but checks for write errors due to hitting the 64-write |
| 36 * limit and clears the TPM when that happens. This can only happen when the | 38 * limit and clears the TPM when that happens. This can only happen when the |
| 37 * TPM is unowned, so it is OK to clear it (and we really have no choice). | 39 * TPM is unowned, so it is OK to clear it (and we really have no choice). |
| 38 * This is not expected to happen frequently, but it could happen. | 40 * This is not expected to happen frequently, but it could happen. |
| 39 */ | 41 */ |
| 40 static uint32_t SafeWrite(uint32_t index, uint8_t* data, uint32_t length) { | 42 static uint32_t SafeWrite(uint32_t index, uint8_t* data, uint32_t length) { |
| 41 uint32_t result = TlclWrite(index, data, length); | 43 uint32_t result = TlclWrite(index, data, length); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 break; | 91 break; |
| 90 } | 92 } |
| 91 return result; | 93 return result; |
| 92 } | 94 } |
| 93 | 95 |
| 94 /* Creates the NVRAM spaces, and sets their initial values as needed. | 96 /* Creates the NVRAM spaces, and sets their initial values as needed. |
| 95 */ | 97 */ |
| 96 static uint32_t InitializeSpaces(void) { | 98 static uint32_t InitializeSpaces(void) { |
| 97 uint32_t zero = 0; | 99 uint32_t zero = 0; |
| 98 uint32_t firmware_perm = TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE; | 100 uint32_t firmware_perm = TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE; |
| 101 uint8_t nvlocked = 0; |
| 102 uint32_t i; |
| 99 | 103 |
| 100 VBDEBUG(("Initializing spaces\n")); | 104 VBDEBUG(("TPM: Initializing spaces\n")); |
| 101 | 105 |
| 102 RETURN_ON_FAILURE(TlclSetNvLocked()); | 106 #ifdef FORCE_CLEAR_ON_INIT |
| 107 /* Force the TPM clear, in case it previously had an owner, so that we can |
| 108 * redefine the NVRAM spaces. */ |
| 109 RETURN_ON_FAILURE(TPMClearAndReenable()); |
| 110 #endif |
| 111 |
| 112 /* The TPM will not enforce the NV authorization restrictions until the |
| 113 * execution of a TPM_NV_DefineSpace with the handle of TPM_NV_INDEX_LOCK. |
| 114 * Create that space if it doesn't already exist. */ |
| 115 RETURN_ON_FAILURE(TlclGetFlags(NULL, NULL, &nvlocked)); |
| 116 VBDEBUG(("TPM: nvlocked=%d\n", nvlocked)); |
| 117 if (!nvlocked) { |
| 118 VBDEBUG(("TPM: Enabling NV locking\n")); |
| 119 RETURN_ON_FAILURE(TlclSetNvLocked()); |
| 120 } |
| 121 |
| 122 /* If the spaces were previously defined, we need to undefine them before we |
| 123 * can redefine them. Undefine by setting size=0. Ignore these return codes, |
| 124 * since they fail if the spaces aren't actually defined? */ |
| 125 for (i = FIRST_ROLLBACK_NV_INDEX; i <= LAST_ROLLBACK_NV_INDEX; i++) |
| 126 SafeDefineSpace(i, firmware_perm, 0); |
| 103 | 127 |
| 104 RETURN_ON_FAILURE(SafeDefineSpace(FIRMWARE_VERSIONS_NV_INDEX, | 128 RETURN_ON_FAILURE(SafeDefineSpace(FIRMWARE_VERSIONS_NV_INDEX, |
| 105 firmware_perm, sizeof(uint32_t))); | 129 firmware_perm, sizeof(uint32_t))); |
| 106 RETURN_ON_FAILURE(SafeWrite(FIRMWARE_VERSIONS_NV_INDEX, | 130 RETURN_ON_FAILURE(SafeWrite(FIRMWARE_VERSIONS_NV_INDEX, |
| 107 (uint8_t*) &zero, sizeof(uint32_t))); | 131 (uint8_t*) &zero, sizeof(uint32_t))); |
| 108 | 132 |
| 109 RETURN_ON_FAILURE(InitializeKernelVersionsSpaces()); | 133 RETURN_ON_FAILURE(InitializeKernelVersionsSpaces()); |
| 110 | 134 |
| 111 /* The space KERNEL_VERSIONS_BACKUP_NV_INDEX is used to protect the kernel | 135 /* The space KERNEL_VERSIONS_BACKUP_NV_INDEX is used to protect the kernel |
| 112 * versions. The content of space KERNEL_MUST_USE_BACKUP determines whether | 136 * versions. The content of space KERNEL_MUST_USE_BACKUP determines whether |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 /* Checks if the kernel version space has been mucked with. If it has, | 173 /* Checks if the kernel version space has been mucked with. If it has, |
| 150 * reconstructs it using the backup value. | 174 * reconstructs it using the backup value. |
| 151 */ | 175 */ |
| 152 uint32_t RecoverKernelSpace(void) { | 176 uint32_t RecoverKernelSpace(void) { |
| 153 uint32_t perms = 0; | 177 uint32_t perms = 0; |
| 154 uint8_t buffer[KERNEL_SPACE_SIZE]; | 178 uint8_t buffer[KERNEL_SPACE_SIZE]; |
| 155 uint32_t backup_combined_versions; | 179 uint32_t backup_combined_versions; |
| 156 uint32_t must_use_backup; | 180 uint32_t must_use_backup; |
| 157 uint32_t zero = 0; | 181 uint32_t zero = 0; |
| 158 | 182 |
| 183 VBDEBUG(("TPM: RecoverKernelSpace()\n")); |
| 184 |
| 159 RETURN_ON_FAILURE(TlclRead(KERNEL_MUST_USE_BACKUP_NV_INDEX, | 185 RETURN_ON_FAILURE(TlclRead(KERNEL_MUST_USE_BACKUP_NV_INDEX, |
| 160 (uint8_t*) &must_use_backup, sizeof(uint32_t))); | 186 (uint8_t*) &must_use_backup, sizeof(uint32_t))); |
| 161 /* must_use_backup is true if the previous boot entered recovery mode. */ | 187 /* must_use_backup is true if the previous boot entered recovery mode. */ |
| 162 | 188 |
| 189 VBDEBUG(("TPM: must_use_backup = %d\n", must_use_backup)); |
| 190 |
| 163 /* If we can't read the kernel space, or it has the wrong permission, or it | 191 /* If we can't read the kernel space, or it has the wrong permission, or it |
| 164 * doesn't contain the right identifier, we give up. This will need to be | 192 * doesn't contain the right identifier, we give up. This will need to be |
| 165 * fixed by the recovery kernel. We have to worry about this because at any | 193 * fixed by the recovery kernel. We have to worry about this because at any |
| 166 * time (even with PP turned off) the TPM owner can remove and redefine a | 194 * time (even with PP turned off) the TPM owner can remove and redefine a |
| 167 * PP-protected space (but not write to it). | 195 * PP-protected space (but not write to it). |
| 168 */ | 196 */ |
| 169 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, (uint8_t*) &buffer, | 197 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, (uint8_t*) &buffer, |
| 170 KERNEL_SPACE_SIZE)); | 198 KERNEL_SPACE_SIZE)); |
| 171 RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_VERSIONS_NV_INDEX, &perms)); | 199 RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_VERSIONS_NV_INDEX, &perms)); |
| 172 if (perms != TPM_NV_PER_PPWRITE || | 200 if (perms != TPM_NV_PER_PPWRITE || |
| (...skipping 14 matching lines...) Expand all Loading... |
| 187 sizeof(uint32_t))); | 215 sizeof(uint32_t))); |
| 188 RETURN_ON_FAILURE(SafeWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, | 216 RETURN_ON_FAILURE(SafeWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, |
| 189 (uint8_t*) &zero, 0)); | 217 (uint8_t*) &zero, 0)); |
| 190 } | 218 } |
| 191 return TPM_SUCCESS; | 219 return TPM_SUCCESS; |
| 192 } | 220 } |
| 193 | 221 |
| 194 static uint32_t BackupKernelSpace(void) { | 222 static uint32_t BackupKernelSpace(void) { |
| 195 uint32_t kernel_versions; | 223 uint32_t kernel_versions; |
| 196 uint32_t backup_versions; | 224 uint32_t backup_versions; |
| 225 VBDEBUG(("TPM: BackupKernelSpace()\n")); |
| 197 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, | 226 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, |
| 198 (uint8_t*) &kernel_versions, sizeof(uint32_t))); | 227 (uint8_t*) &kernel_versions, sizeof(uint32_t))); |
| 199 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, | 228 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
| 200 (uint8_t*) &backup_versions, sizeof(uint32_t))); | 229 (uint8_t*) &backup_versions, sizeof(uint32_t))); |
| 201 if (kernel_versions == backup_versions) { | 230 if (kernel_versions == backup_versions) { |
| 202 return TPM_SUCCESS; | 231 return TPM_SUCCESS; |
| 203 } else if (kernel_versions < backup_versions) { | 232 } else if (kernel_versions < backup_versions) { |
| 204 /* This cannot happen. We're screwed. */ | 233 /* This cannot happen. We're screwed. */ |
| 205 return TPM_E_INTERNAL_INCONSISTENCY; | 234 return TPM_E_INTERNAL_INCONSISTENCY; |
| 206 } | 235 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 * As a side note, observe that we go through considerable hoops to avoid using | 272 * As a side note, observe that we go through considerable hoops to avoid using |
| 244 * the STCLEAR permissions for the index spaces. We do this to avoid writing | 273 * the STCLEAR permissions for the index spaces. We do this to avoid writing |
| 245 * to the TPM flashram at every reboot or wake-up, because of concerns about | 274 * to the TPM flashram at every reboot or wake-up, because of concerns about |
| 246 * the durability of the NVRAM. | 275 * the durability of the NVRAM. |
| 247 */ | 276 */ |
| 248 uint32_t SetupTPM(int recovery_mode, int developer_mode) { | 277 uint32_t SetupTPM(int recovery_mode, int developer_mode) { |
| 249 uint8_t disable; | 278 uint8_t disable; |
| 250 uint8_t deactivated; | 279 uint8_t deactivated; |
| 251 uint32_t result; | 280 uint32_t result; |
| 252 | 281 |
| 282 VBDEBUG(("TPM: SetupTPM(r%d, d%d)\n", recovery_mode, developer_mode)); |
| 283 |
| 284 /* TODO: TlclLibInit() should be able to return failure */ |
| 253 TlclLibInit(); | 285 TlclLibInit(); |
| 286 |
| 254 RETURN_ON_FAILURE(TlclStartup()); | 287 RETURN_ON_FAILURE(TlclStartup()); |
| 288 #ifdef USE_CONTINUE_SELF_TEST |
| 289 /* TODO: ContinueSelfTest() should be faster than SelfTestFull, but may also |
| 290 * not work properly in older TPM firmware. For now, do the full self test. *
/ |
| 255 RETURN_ON_FAILURE(TlclContinueSelfTest()); | 291 RETURN_ON_FAILURE(TlclContinueSelfTest()); |
| 292 #else |
| 293 RETURN_ON_FAILURE(TlclSelfTestFull()); |
| 294 #endif |
| 256 RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); | 295 RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); |
| 257 /* Checks that the TPM is enabled and activated. */ | 296 /* Checks that the TPM is enabled and activated. */ |
| 258 RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated)); | 297 RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated, NULL)); |
| 259 if (disable || deactivated) { | 298 if (disable || deactivated) { |
| 299 VBDEBUG(("TPM: disabled (%d) or deactivated (%d). Fixing...\n", disable, de
activated)); |
| 260 RETURN_ON_FAILURE(TlclSetEnable()); | 300 RETURN_ON_FAILURE(TlclSetEnable()); |
| 261 RETURN_ON_FAILURE(TlclSetDeactivated(0)); | 301 RETURN_ON_FAILURE(TlclSetDeactivated(0)); |
| 302 VBDEBUG(("TPM: Must reboot to re-enable\n")); |
| 262 return TPM_E_MUST_REBOOT; | 303 return TPM_E_MUST_REBOOT; |
| 263 } | 304 } |
| 264 result = RecoverKernelSpace(); | 305 result = RecoverKernelSpace(); |
| 265 if (result != TPM_SUCCESS) { | 306 if (result != TPM_SUCCESS) { |
| 266 /* Check if this is the first time we run and the TPM has not been | 307 /* Check if this is the first time we run and the TPM has not been |
| 267 * initialized yet. | 308 * initialized yet. |
| 268 */ | 309 */ |
| 269 int initialized = 0; | 310 int initialized = 0; |
| 311 VBDEBUG(("TPM: RecoverKernelSpace() failed\n")); |
| 270 RETURN_ON_FAILURE(GetSpacesInitialized(&initialized)); | 312 RETURN_ON_FAILURE(GetSpacesInitialized(&initialized)); |
| 271 if (initialized) { | 313 if (initialized) { |
| 314 VBDEBUG(("TPM: Already initialized, so give up\n")); |
| 272 return result; | 315 return result; |
| 273 } else { | 316 } else { |
| 317 VBDEBUG(("TPM: Need to initialize spaces.\n")); |
| 274 RETURN_ON_FAILURE(InitializeSpaces()); | 318 RETURN_ON_FAILURE(InitializeSpaces()); |
| 319 VBDEBUG(("TPM: Retrying RecoverKernelSpace() now that spaces are initializ
ed.\n")); |
| 275 RETURN_ON_FAILURE(RecoverKernelSpace()); | 320 RETURN_ON_FAILURE(RecoverKernelSpace()); |
| 276 } | 321 } |
| 277 } | 322 } |
| 278 RETURN_ON_FAILURE(BackupKernelSpace()); | 323 RETURN_ON_FAILURE(BackupKernelSpace()); |
| 279 RETURN_ON_FAILURE(SetDistrustKernelSpaceAtNextBoot(recovery_mode)); | 324 RETURN_ON_FAILURE(SetDistrustKernelSpaceAtNextBoot(recovery_mode)); |
| 280 RETURN_ON_FAILURE(CheckDeveloperModeTransition(developer_mode)); | 325 RETURN_ON_FAILURE(CheckDeveloperModeTransition(developer_mode)); |
| 281 | 326 |
| 282 if (recovery_mode) { | 327 if (recovery_mode) { |
| 283 /* In recovery mode global variables are usable. */ | 328 /* In recovery mode global variables are usable. */ |
| 284 g_rollback_recovery_mode = 1; | 329 g_rollback_recovery_mode = 1; |
| 285 } | 330 } |
| 331 VBDEBUG(("TPM: SetupTPM() succeeded\n")); |
| 286 return TPM_SUCCESS; | 332 return TPM_SUCCESS; |
| 287 } | 333 } |
| 288 | 334 |
| 289 /* disable MSVC warnings on unused arguments */ | 335 /* disable MSVC warnings on unused arguments */ |
| 290 __pragma(warning (disable: 4100)) | 336 __pragma(warning (disable: 4100)) |
| 291 | 337 |
| 292 | 338 |
| 293 #ifdef DISABLE_ROLLBACK_TPM | 339 #ifdef DISABLE_ROLLBACK_TPM |
| 294 | 340 |
| 295 /* Dummy implementations which don't call into the tpm_lite library */ | 341 /* Dummy implementations which don't call into the tpm_lite library */ |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 | 446 |
| 401 uint32_t RollbackKernelLock(void) { | 447 uint32_t RollbackKernelLock(void) { |
| 402 if (!g_rollback_recovery_mode) { | 448 if (!g_rollback_recovery_mode) { |
| 403 return TlclLockPhysicalPresence(); | 449 return TlclLockPhysicalPresence(); |
| 404 } else { | 450 } else { |
| 405 return TPM_SUCCESS; | 451 return TPM_SUCCESS; |
| 406 } | 452 } |
| 407 } | 453 } |
| 408 | 454 |
| 409 #endif // DISABLE_ROLLBACK_TPM | 455 #endif // DISABLE_ROLLBACK_TPM |
| OLD | NEW |