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 |