| 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 return result; \ | 23 return result; \ |
| 24 } \ | 24 } \ |
| 25 } while (0) | 25 } while (0) |
| 26 | 26 |
| 27 static uint32_t TPMClearAndReenable() { | 27 uint32_t TPMClearAndReenable(void) { |
| 28 RETURN_ON_FAILURE(TlclForceClear()); | 28 RETURN_ON_FAILURE(TlclForceClear()); |
| 29 RETURN_ON_FAILURE(TlclSetEnable()); | 29 RETURN_ON_FAILURE(TlclSetEnable()); |
| 30 RETURN_ON_FAILURE(TlclSetDeactivated(0)); | 30 RETURN_ON_FAILURE(TlclSetDeactivated(0)); |
| 31 return TPM_SUCCESS; | 31 return TPM_SUCCESS; |
| 32 } | 32 } |
| 33 | 33 |
| 34 /* Like TlclWrite(), but checks for write errors due to hitting the 64-write | 34 /* Like TlclWrite(), but checks for write errors due to hitting the 64-write |
| 35 * limit and clears the TPM when that happens. This can only happen when the | 35 * limit and clears the TPM when that happens. This can only happen when the |
| 36 * TPM is unowned, so it is OK to clear it (and we really have no choice). | 36 * TPM is unowned, so it is OK to clear it (and we really have no choice). |
| 37 * This is not expected to happen frequently, but it could happen. | 37 * This is not expected to happen frequently, but it could happen. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 51 TPM_NV_PER_PPWRITE, KERNEL_SPACE_SIZE)); | 51 TPM_NV_PER_PPWRITE, KERNEL_SPACE_SIZE)); |
| 52 RETURN_ON_FAILURE(SafeWrite(KERNEL_VERSIONS_NV_INDEX, KERNEL_SPACE_INIT_DATA, | 52 RETURN_ON_FAILURE(SafeWrite(KERNEL_VERSIONS_NV_INDEX, KERNEL_SPACE_INIT_DATA, |
| 53 KERNEL_SPACE_SIZE)); | 53 KERNEL_SPACE_SIZE)); |
| 54 return TPM_SUCCESS; | 54 return TPM_SUCCESS; |
| 55 } | 55 } |
| 56 | 56 |
| 57 /* When the return value is TPM_SUCCESS, this function sets *|initialized| to 1 | 57 /* When the return value is TPM_SUCCESS, this function sets *|initialized| to 1 |
| 58 * if the spaces have been fully initialized, to 0 if not. Otherwise | 58 * if the spaces have been fully initialized, to 0 if not. Otherwise |
| 59 * *|initialized| is not changed. | 59 * *|initialized| is not changed. |
| 60 */ | 60 */ |
| 61 static uint32_t GetSpacesInitialized(int* initialized) { | 61 uint32_t GetSpacesInitialized(int* initialized) { |
| 62 uint32_t space_holder; | 62 uint32_t space_holder; |
| 63 uint32_t result; | 63 uint32_t result; |
| 64 result = TlclRead(TPM_IS_INITIALIZED_NV_INDEX, | 64 result = TlclRead(TPM_IS_INITIALIZED_NV_INDEX, |
| 65 (uint8_t*) &space_holder, sizeof(space_holder)); | 65 (uint8_t*) &space_holder, sizeof(space_holder)); |
| 66 switch (result) { | 66 switch (result) { |
| 67 case TPM_SUCCESS: | 67 case TPM_SUCCESS: |
| 68 *initialized = 1; | 68 *initialized = 1; |
| 69 break; | 69 break; |
| 70 case TPM_E_BADINDEX: | 70 case TPM_E_BADINDEX: |
| 71 *initialized = 0; | 71 *initialized = 0; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 /* If we can't read the kernel space, or it has the wrong permission, or it | 147 /* If we can't read the kernel space, or it has the wrong permission, or it |
| 148 * doesn't contain the right identifier, we give up. This will need to be | 148 * doesn't contain the right identifier, we give up. This will need to be |
| 149 * fixed by the recovery kernel. We have to worry about this because at any | 149 * fixed by the recovery kernel. We have to worry about this because at any |
| 150 * time (even with PP turned off) the TPM owner can remove and redefine a | 150 * time (even with PP turned off) the TPM owner can remove and redefine a |
| 151 * PP-protected space (but not write to it). | 151 * PP-protected space (but not write to it). |
| 152 */ | 152 */ |
| 153 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, (uint8_t*) &buffer, | 153 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, (uint8_t*) &buffer, |
| 154 KERNEL_SPACE_SIZE)); | 154 KERNEL_SPACE_SIZE)); |
| 155 RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_VERSIONS_NV_INDEX, &perms)); | 155 RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_VERSIONS_NV_INDEX, &perms)); |
| 156 if (perms != TPM_NV_PER_PPWRITE || | 156 if (perms != TPM_NV_PER_PPWRITE || |
| 157 !Memcmp(buffer + sizeof(uint32_t), KERNEL_SPACE_UID, | 157 Memcmp(buffer + sizeof(uint32_t), KERNEL_SPACE_UID, |
| 158 KERNEL_SPACE_UID_SIZE)) { | 158 KERNEL_SPACE_UID_SIZE) != 0) { |
| 159 return TPM_E_CORRUPTED_STATE; | 159 return TPM_E_CORRUPTED_STATE; |
| 160 } | 160 } |
| 161 | 161 |
| 162 if (must_use_backup) { | 162 if (must_use_backup) { |
| 163 /* We must use the backup space because in the preceding boot cycle the | 163 /* We must use the backup space because in the preceding boot cycle the |
| 164 * primary space was left unlocked and cannot be trusted. | 164 * primary space was left unlocked and cannot be trusted. |
| 165 */ | 165 */ |
| 166 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, | 166 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
| 167 (uint8_t*) &backup_combined_versions, | 167 (uint8_t*) &backup_combined_versions, |
| 168 sizeof(uint32_t))); | 168 sizeof(uint32_t))); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 * | 226 * |
| 227 * As a side note, observe that we go through considerable hoops to avoid using | 227 * As a side note, observe that we go through considerable hoops to avoid using |
| 228 * the STCLEAR permissions for the index spaces. We do this to avoid writing | 228 * the STCLEAR permissions for the index spaces. We do this to avoid writing |
| 229 * to the TPM flashram at every reboot or wake-up, because of concerns about | 229 * to the TPM flashram at every reboot or wake-up, because of concerns about |
| 230 * the durability of the NVRAM. | 230 * the durability of the NVRAM. |
| 231 */ | 231 */ |
| 232 static uint32_t SetupTPM(int recovery_mode, | 232 static uint32_t SetupTPM(int recovery_mode, |
| 233 int developer_mode) { | 233 int developer_mode) { |
| 234 uint8_t disable; | 234 uint8_t disable; |
| 235 uint8_t deactivated; | 235 uint8_t deactivated; |
| 236 uint32_t result; |
| 236 | 237 |
| 237 TlclLibInit(); | 238 TlclLibInit(); |
| 238 RETURN_ON_FAILURE(TlclStartup()); | 239 RETURN_ON_FAILURE(TlclStartup()); |
| 239 RETURN_ON_FAILURE(TlclContinueSelfTest()); | 240 RETURN_ON_FAILURE(TlclContinueSelfTest()); |
| 240 RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); | 241 RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); |
| 241 /* Checks that the TPM is enabled and activated. */ | 242 /* Checks that the TPM is enabled and activated. */ |
| 242 RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated)); | 243 RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated)); |
| 243 if (disable || deactivated) { | 244 if (disable || deactivated) { |
| 244 RETURN_ON_FAILURE(TlclSetEnable()); | 245 RETURN_ON_FAILURE(TlclSetEnable()); |
| 245 RETURN_ON_FAILURE(TlclSetDeactivated(0)); | 246 RETURN_ON_FAILURE(TlclSetDeactivated(0)); |
| 246 return TPM_E_MUST_REBOOT; | 247 return TPM_E_MUST_REBOOT; |
| 247 } | 248 } |
| 248 /* We expect this to fail the first time we run on a device, because the TPM | 249 result = RecoverKernelSpace(); |
| 249 * has not been initialized yet. | 250 if (result != TPM_SUCCESS) { |
| 250 */ | 251 /* Check if this is the first time we run and the TPM has not been |
| 251 if (RecoverKernelSpace() != TPM_SUCCESS) { | 252 * initialized yet. |
| 253 */ |
| 252 int initialized = 0; | 254 int initialized = 0; |
| 253 RETURN_ON_FAILURE(GetSpacesInitialized(&initialized)); | 255 RETURN_ON_FAILURE(GetSpacesInitialized(&initialized)); |
| 254 if (initialized) { | 256 if (initialized) { |
| 255 return TPM_E_ALREADY_INITIALIZED; | 257 return result; |
| 256 } else { | 258 } else { |
| 257 RETURN_ON_FAILURE(InitializeSpaces()); | 259 RETURN_ON_FAILURE(InitializeSpaces()); |
| 258 RETURN_ON_FAILURE(RecoverKernelSpace()); | 260 RETURN_ON_FAILURE(RecoverKernelSpace()); |
| 259 } | 261 } |
| 260 } | 262 } |
| 261 RETURN_ON_FAILURE(BackupKernelSpace()); | 263 RETURN_ON_FAILURE(BackupKernelSpace()); |
| 262 RETURN_ON_FAILURE(SetDistrustKernelSpaceAtNextBoot(recovery_mode)); | 264 RETURN_ON_FAILURE(SetDistrustKernelSpaceAtNextBoot(recovery_mode)); |
| 263 RETURN_ON_FAILURE(CheckDeveloperModeTransition(developer_mode)); | 265 RETURN_ON_FAILURE(CheckDeveloperModeTransition(developer_mode)); |
| 264 | 266 |
| 265 if (recovery_mode) { | 267 if (recovery_mode) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 292 return SafeWrite(FIRMWARE_VERSIONS_NV_INDEX, | 294 return SafeWrite(FIRMWARE_VERSIONS_NV_INDEX, |
| 293 (uint8_t*) &combined_version, | 295 (uint8_t*) &combined_version, |
| 294 sizeof(uint32_t)); | 296 sizeof(uint32_t)); |
| 295 } | 297 } |
| 296 | 298 |
| 297 uint32_t RollbackFirmwareLock(void) { | 299 uint32_t RollbackFirmwareLock(void) { |
| 298 return TlclSetGlobalLock(); | 300 return TlclSetGlobalLock(); |
| 299 } | 301 } |
| 300 | 302 |
| 301 uint32_t RollbackKernelRecovery(int developer_mode) { | 303 uint32_t RollbackKernelRecovery(int developer_mode) { |
| 302 (void) SetupTPM(1, developer_mode); | 304 uint32_t result = SetupTPM(1, developer_mode); |
| 303 /* In recovery mode we ignore TPM malfunctions or corruptions, and leave the | 305 /* In recovery mode we ignore TPM malfunctions or corruptions, and leave the |
| 304 * TPM completely unlocked if and only if the dev mode switch is ON. The | 306 * TPM completely unlocked if and only if the dev mode switch is ON. The |
| 305 * recovery kernel will fix the TPM (if needed) and lock it ASAP. We leave | 307 * recovery kernel will fix the TPM (if needed) and lock it ASAP. We leave |
| 306 * Physical Presence on in either case. | 308 * Physical Presence on in either case. |
| 307 */ | 309 */ |
| 308 if (!developer_mode) { | 310 if (!developer_mode) { |
| 309 RETURN_ON_FAILURE(TlclSetGlobalLock()); | 311 RETURN_ON_FAILURE(TlclSetGlobalLock()); |
| 310 } | 312 } |
| 311 return TPM_SUCCESS; | 313 /* We still return the result of SetupTPM even though we expect the caller to |
| 314 * ignore it. It's useful in unit testing. |
| 315 */ |
| 316 return result; |
| 312 } | 317 } |
| 313 | 318 |
| 314 uint32_t RollbackKernelRead(uint16_t* key_version, uint16_t* version) { | 319 uint32_t RollbackKernelRead(uint16_t* key_version, uint16_t* version) { |
| 315 uint32_t kernel_versions; | 320 uint32_t kernel_versions; |
| 316 if (g_rollback_recovery_mode) { | 321 if (g_rollback_recovery_mode) { |
| 317 *key_version = 0; | 322 *key_version = 0; |
| 318 *version = 0; | 323 *version = 0; |
| 319 } else { | 324 } else { |
| 320 /* Reads kernel versions from TPM. */ | 325 /* Reads kernel versions from TPM. */ |
| 321 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, | 326 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 337 return TPM_SUCCESS; | 342 return TPM_SUCCESS; |
| 338 } | 343 } |
| 339 | 344 |
| 340 uint32_t RollbackKernelLock(void) { | 345 uint32_t RollbackKernelLock(void) { |
| 341 if (!g_rollback_recovery_mode) { | 346 if (!g_rollback_recovery_mode) { |
| 342 return TlclLockPhysicalPresence(); | 347 return TlclLockPhysicalPresence(); |
| 343 } else { | 348 } else { |
| 344 return TPM_SUCCESS; | 349 return TPM_SUCCESS; |
| 345 } | 350 } |
| 346 } | 351 } |
| OLD | NEW |