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 uint16_t g_firmware_key_version = 0; | 15 uint16_t g_firmware_key_version = 0; |
16 uint16_t g_firmware_version = 0; | 16 uint16_t g_firmware_version = 0; |
17 uint16_t g_kernel_key_version = 0; | 17 uint16_t g_kernel_key_version = 0; |
18 uint16_t g_kernel_version = 0; | 18 uint16_t g_kernel_version = 0; |
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() { |
| 28 RETURN_ON_FAILURE(TlclForceClear()); |
| 29 RETURN_ON_FAILURE(TlclSetEnable()); |
| 30 RETURN_ON_FAILURE(TlclSetDeactivated(0)); |
| 31 return TPM_SUCCESS; |
| 32 } |
| 33 |
| 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 |
| 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. |
| 38 */ |
| 39 static uint32_t SafeWrite(uint32_t index, uint8_t* data, uint32_t length) { |
| 40 uint32_t result = TlclWrite(index, data, length); |
| 41 if (result == TPM_E_MAXNVWRITES) { |
| 42 RETURN_ON_FAILURE(TPMClearAndReenable()); |
| 43 return TlclWrite(index, data, length); |
| 44 } else { |
| 45 return result; |
| 46 } |
| 47 } |
| 48 |
27 static uint32_t InitializeKernelVersionsSpaces(void) { | 49 static uint32_t InitializeKernelVersionsSpaces(void) { |
28 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX, | 50 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX, |
29 TPM_NV_PER_PPWRITE, KERNEL_SPACE_SIZE)); | 51 TPM_NV_PER_PPWRITE, KERNEL_SPACE_SIZE)); |
30 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, KERNEL_SPACE_INIT_DATA, | 52 RETURN_ON_FAILURE(SafeWrite(KERNEL_VERSIONS_NV_INDEX, KERNEL_SPACE_INIT_DATA, |
31 KERNEL_SPACE_SIZE)); | 53 KERNEL_SPACE_SIZE)); |
32 return TPM_SUCCESS; | 54 return TPM_SUCCESS; |
33 } | 55 } |
34 | 56 |
35 /* 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 |
36 * 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 |
37 * *|initialized| is not changed. | 59 * *|initialized| is not changed. |
38 */ | 60 */ |
39 static uint32_t GetSpacesInitialized(int* initialized) { | 61 static uint32_t GetSpacesInitialized(int* initialized) { |
40 uint32_t space_holder; | 62 uint32_t space_holder; |
(...skipping 17 matching lines...) Expand all Loading... |
58 static uint32_t InitializeSpaces(void) { | 80 static uint32_t InitializeSpaces(void) { |
59 uint32_t zero = 0; | 81 uint32_t zero = 0; |
60 uint32_t firmware_perm = TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE; | 82 uint32_t firmware_perm = TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE; |
61 | 83 |
62 debug("Initializing spaces\n"); | 84 debug("Initializing spaces\n"); |
63 | 85 |
64 RETURN_ON_FAILURE(TlclSetNvLocked()); | 86 RETURN_ON_FAILURE(TlclSetNvLocked()); |
65 | 87 |
66 RETURN_ON_FAILURE(TlclDefineSpace(FIRMWARE_VERSIONS_NV_INDEX, | 88 RETURN_ON_FAILURE(TlclDefineSpace(FIRMWARE_VERSIONS_NV_INDEX, |
67 firmware_perm, sizeof(uint32_t))); | 89 firmware_perm, sizeof(uint32_t))); |
68 RETURN_ON_FAILURE(TlclWrite(FIRMWARE_VERSIONS_NV_INDEX, | 90 RETURN_ON_FAILURE(SafeWrite(FIRMWARE_VERSIONS_NV_INDEX, |
69 (uint8_t*) &zero, sizeof(uint32_t))); | 91 (uint8_t*) &zero, sizeof(uint32_t))); |
70 | 92 |
71 RETURN_ON_FAILURE(InitializeKernelVersionsSpaces()); | 93 RETURN_ON_FAILURE(InitializeKernelVersionsSpaces()); |
72 | 94 |
73 /* The space KERNEL_VERSIONS_BACKUP_NV_INDEX is used to protect the kernel | 95 /* The space KERNEL_VERSIONS_BACKUP_NV_INDEX is used to protect the kernel |
74 * versions. The content of space KERNEL_MUST_USE_BACKUP determines whether | 96 * versions. The content of space KERNEL_MUST_USE_BACKUP determines whether |
75 * only the backup value should be trusted. | 97 * only the backup value should be trusted. |
76 */ | 98 */ |
77 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_BACKUP_NV_INDEX, | 99 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
78 firmware_perm, sizeof(uint32_t))); | 100 firmware_perm, sizeof(uint32_t))); |
79 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, | 101 RETURN_ON_FAILURE(SafeWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
80 (uint8_t*) &zero, sizeof(uint32_t))); | 102 (uint8_t*) &zero, sizeof(uint32_t))); |
81 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_MUST_USE_BACKUP_NV_INDEX, | 103 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_MUST_USE_BACKUP_NV_INDEX, |
82 firmware_perm, sizeof(uint32_t))); | 104 firmware_perm, sizeof(uint32_t))); |
83 RETURN_ON_FAILURE(TlclWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, | 105 RETURN_ON_FAILURE(SafeWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, |
84 (uint8_t*) &zero, sizeof(uint32_t))); | 106 (uint8_t*) &zero, sizeof(uint32_t))); |
85 RETURN_ON_FAILURE(TlclDefineSpace(DEVELOPER_MODE_NV_INDEX, | 107 RETURN_ON_FAILURE(TlclDefineSpace(DEVELOPER_MODE_NV_INDEX, |
86 firmware_perm, sizeof(uint32_t))); | 108 firmware_perm, sizeof(uint32_t))); |
87 RETURN_ON_FAILURE(TlclWrite(DEVELOPER_MODE_NV_INDEX, | 109 RETURN_ON_FAILURE(SafeWrite(DEVELOPER_MODE_NV_INDEX, |
88 (uint8_t*) &zero, sizeof(uint32_t))); | 110 (uint8_t*) &zero, sizeof(uint32_t))); |
89 | 111 |
90 /* The space TPM_IS_INITIALIZED_NV_INDEX is used to indicate that the TPM | 112 /* The space TPM_IS_INITIALIZED_NV_INDEX is used to indicate that the TPM |
91 * initialization has completed. Without it we cannot be sure that the last | 113 * initialization has completed. Without it we cannot be sure that the last |
92 * space to be created was also initialized (power could have been lost right | 114 * space to be created was also initialized (power could have been lost right |
93 * after its creation). | 115 * after its creation). |
94 */ | 116 */ |
95 RETURN_ON_FAILURE(TlclDefineSpace(TPM_IS_INITIALIZED_NV_INDEX, | 117 RETURN_ON_FAILURE(TlclDefineSpace(TPM_IS_INITIALIZED_NV_INDEX, |
96 firmware_perm, sizeof(uint32_t))); | 118 firmware_perm, sizeof(uint32_t))); |
97 return TPM_SUCCESS; | 119 return TPM_SUCCESS; |
98 } | 120 } |
99 | 121 |
100 static uint32_t SetDistrustKernelSpaceAtNextBoot(uint32_t distrust) { | 122 static uint32_t SetDistrustKernelSpaceAtNextBoot(uint32_t distrust) { |
101 uint32_t must_use_backup; | 123 uint32_t must_use_backup; |
102 RETURN_ON_FAILURE(TlclRead(KERNEL_MUST_USE_BACKUP_NV_INDEX, | 124 RETURN_ON_FAILURE(TlclRead(KERNEL_MUST_USE_BACKUP_NV_INDEX, |
103 (uint8_t*) &must_use_backup, sizeof(uint32_t))); | 125 (uint8_t*) &must_use_backup, sizeof(uint32_t))); |
104 if (must_use_backup != distrust) { | 126 if (must_use_backup != distrust) { |
105 RETURN_ON_FAILURE(TlclWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, | 127 RETURN_ON_FAILURE(SafeWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, |
106 (uint8_t*) &distrust, sizeof(uint32_t))); | 128 (uint8_t*) &distrust, sizeof(uint32_t))); |
107 } | 129 } |
108 return TPM_SUCCESS; | 130 return TPM_SUCCESS; |
109 } | 131 } |
110 | 132 |
111 static uint32_t GetTPMRollbackIndices(int type) { | 133 static uint32_t GetTPMRollbackIndices(int type) { |
112 uint32_t firmware_versions; | 134 uint32_t firmware_versions; |
113 uint32_t kernel_versions; | 135 uint32_t kernel_versions; |
114 | 136 |
115 /* We perform the reads, making sure they succeed. A failure means that the | 137 /* We perform the reads, making sure they succeed. A failure means that the |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 | 188 |
167 /* Either we detected that something went wrong, or we cannot trust the | 189 /* Either we detected that something went wrong, or we cannot trust the |
168 * PP-protected kernel space. Attempts to fix. It is not always necessary | 190 * PP-protected kernel space. Attempts to fix. It is not always necessary |
169 * to redefine the space, but we might as well, since this path should be | 191 * to redefine the space, but we might as well, since this path should be |
170 * taken quite seldom (after recovery mode and after an attack). | 192 * taken quite seldom (after recovery mode and after an attack). |
171 */ | 193 */ |
172 RETURN_ON_FAILURE(InitializeKernelVersionsSpaces()); | 194 RETURN_ON_FAILURE(InitializeKernelVersionsSpaces()); |
173 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, | 195 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
174 (uint8_t*) &backup_combined_versions, | 196 (uint8_t*) &backup_combined_versions, |
175 sizeof(uint32_t))); | 197 sizeof(uint32_t))); |
176 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, | 198 RETURN_ON_FAILURE(SafeWrite(KERNEL_VERSIONS_NV_INDEX, |
177 (uint8_t*) &backup_combined_versions, | 199 (uint8_t*) &backup_combined_versions, |
178 sizeof(uint32_t))); | 200 sizeof(uint32_t))); |
179 if (must_use_backup) { | 201 if (must_use_backup) { |
180 uint32_t zero = 0; | 202 uint32_t zero = 0; |
181 RETURN_ON_FAILURE(TlclWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, | 203 RETURN_ON_FAILURE(SafeWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, |
182 (uint8_t*) &zero, 0)); | 204 (uint8_t*) &zero, 0)); |
183 | |
184 } | 205 } |
185 return TPM_SUCCESS; | 206 return TPM_SUCCESS; |
186 } | 207 } |
187 | 208 |
188 static uint32_t BackupKernelSpace(void) { | 209 static uint32_t BackupKernelSpace(void) { |
189 uint32_t kernel_versions; | 210 uint32_t kernel_versions; |
190 uint32_t backup_versions; | 211 uint32_t backup_versions; |
191 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, | 212 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, |
192 (uint8_t*) &kernel_versions, sizeof(uint32_t))); | 213 (uint8_t*) &kernel_versions, sizeof(uint32_t))); |
193 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, | 214 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
194 (uint8_t*) &backup_versions, sizeof(uint32_t))); | 215 (uint8_t*) &backup_versions, sizeof(uint32_t))); |
195 if (kernel_versions == backup_versions) { | 216 if (kernel_versions == backup_versions) { |
196 return TPM_SUCCESS; | 217 return TPM_SUCCESS; |
197 } else if (kernel_versions < backup_versions) { | 218 } else if (kernel_versions < backup_versions) { |
198 /* This cannot happen. We're screwed. */ | 219 /* This cannot happen. We're screwed. */ |
199 return TPM_E_INTERNAL_INCONSISTENCY; | 220 return TPM_E_INTERNAL_INCONSISTENCY; |
200 } | 221 } |
201 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, | 222 RETURN_ON_FAILURE(SafeWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
202 (uint8_t*) &kernel_versions, sizeof(uint32_t))); | 223 (uint8_t*) &kernel_versions, sizeof(uint32_t))); |
203 return TPM_SUCCESS; | 224 return TPM_SUCCESS; |
204 } | 225 } |
205 | 226 |
206 /* Checks for transitions between protected mode to developer mode. When going | 227 /* Checks for transitions between protected mode to developer mode. When going |
207 * into developer mode, clear the TPM. | 228 * into developer mode, clear the TPM. |
208 */ | 229 */ |
209 static uint32_t CheckDeveloperModeTransition(uint32_t current_developer) { | 230 static uint32_t CheckDeveloperModeTransition(uint32_t current_developer) { |
210 uint32_t past_developer; | 231 uint32_t past_developer; |
211 int must_clear; | |
212 RETURN_ON_FAILURE(TlclRead(DEVELOPER_MODE_NV_INDEX, | 232 RETURN_ON_FAILURE(TlclRead(DEVELOPER_MODE_NV_INDEX, |
213 (uint8_t*) &past_developer, | 233 (uint8_t*) &past_developer, |
214 sizeof(past_developer))); | 234 sizeof(past_developer))); |
215 must_clear = current_developer != past_developer; | |
216 if (must_clear) { | |
217 RETURN_ON_FAILURE(TlclForceClear()); | |
218 } | |
219 if (past_developer != current_developer) { | 235 if (past_developer != current_developer) { |
220 /* (Unauthorized) writes to the TPM succeed even when the TPM is disabled | 236 RETURN_ON_FAILURE(TPMClearAndReenable()); |
221 * and deactivated. | 237 RETURN_ON_FAILURE(SafeWrite(DEVELOPER_MODE_NV_INDEX, |
222 */ | |
223 RETURN_ON_FAILURE(TlclWrite(DEVELOPER_MODE_NV_INDEX, | |
224 (uint8_t*) ¤t_developer, | 238 (uint8_t*) ¤t_developer, |
225 sizeof(current_developer))); | 239 sizeof(current_developer))); |
226 } | 240 } |
227 return must_clear ? TPM_E_MUST_REBOOT : TPM_SUCCESS; | 241 return TPM_SUCCESS; |
228 } | 242 } |
229 | 243 |
230 static uint32_t SetupTPM_(int mode, int developer_flag) { | 244 static uint32_t SetupTPM_(int mode, int developer_flag) { |
231 uint8_t disable; | 245 uint8_t disable; |
232 uint8_t deactivated; | 246 uint8_t deactivated; |
233 TlclLibInit(); | 247 TlclLibInit(); |
234 RETURN_ON_FAILURE(TlclStartup()); | 248 RETURN_ON_FAILURE(TlclStartup()); |
235 RETURN_ON_FAILURE(TlclContinueSelfTest()); | 249 RETURN_ON_FAILURE(TlclContinueSelfTest()); |
236 RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); | 250 RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); |
237 /* Checks that the TPM is enabled and activated. */ | 251 /* Checks that the TPM is enabled and activated. */ |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 * As a side note, observe that we go through considerable hoops to avoid using | 302 * As a side note, observe that we go through considerable hoops to avoid using |
289 * the STCLEAR permissions for the index spaces. We do this to avoid writing | 303 * the STCLEAR permissions for the index spaces. We do this to avoid writing |
290 * to the TPM flashram at every reboot or wake-up, because of concerns about | 304 * to the TPM flashram at every reboot or wake-up, because of concerns about |
291 * the durability of the NVRAM. | 305 * the durability of the NVRAM. |
292 */ | 306 */ |
293 uint32_t SetupTPM(int mode, int developer_flag) { | 307 uint32_t SetupTPM(int mode, int developer_flag) { |
294 switch (mode) { | 308 switch (mode) { |
295 case RO_RECOVERY_MODE: | 309 case RO_RECOVERY_MODE: |
296 case RO_NORMAL_MODE: { | 310 case RO_NORMAL_MODE: { |
297 uint32_t result = SetupTPM_(mode, developer_flag); | 311 uint32_t result = SetupTPM_(mode, developer_flag); |
298 if (result == TPM_E_MAXNVWRITES) { | 312 if (mode == RO_NORMAL_MODE) { |
299 /* ForceClears and reboots */ | |
300 RETURN_ON_FAILURE(TlclForceClear()); | |
301 return TPM_E_MUST_REBOOT; | |
302 } else if (mode == RO_NORMAL_MODE) { | |
303 return result; | 313 return result; |
304 } else { | 314 } else { |
305 /* In recovery mode we want to keep going even if there are errors. */ | 315 /* In recovery mode we want to keep going even if there are errors. */ |
306 return TPM_SUCCESS; | 316 return TPM_SUCCESS; |
307 } | 317 } |
308 } | 318 } |
309 case RW_NORMAL_MODE: | 319 case RW_NORMAL_MODE: |
310 /* There are no TPM writes here, so no need to check for write limit errors. | |
311 */ | |
312 RETURN_ON_FAILURE(GetTPMRollbackIndices(KERNEL_VERSIONS)); | 320 RETURN_ON_FAILURE(GetTPMRollbackIndices(KERNEL_VERSIONS)); |
313 default: | 321 default: |
314 return TPM_E_INTERNAL_INCONSISTENCY; | 322 return TPM_E_INTERNAL_INCONSISTENCY; |
315 } | 323 } |
316 } | 324 } |
317 | 325 |
318 uint32_t GetStoredVersions(int type, uint16_t* key_version, uint16_t* version) { | 326 uint32_t GetStoredVersions(int type, uint16_t* key_version, uint16_t* version) { |
319 /* TODO: should verify that SetupTPM() has been called. | 327 /* TODO: should verify that SetupTPM() has been called. |
320 * | 328 * |
321 * Note that SetupTPM() does hardware setup AND sets global variables. When | 329 * Note that SetupTPM() does hardware setup AND sets global variables. When |
(...skipping 11 matching lines...) Expand all Loading... |
333 break; | 341 break; |
334 } | 342 } |
335 | 343 |
336 return TPM_SUCCESS; | 344 return TPM_SUCCESS; |
337 } | 345 } |
338 | 346 |
339 uint32_t WriteStoredVersions(int type, uint16_t key_version, uint16_t version) { | 347 uint32_t WriteStoredVersions(int type, uint16_t key_version, uint16_t version) { |
340 uint32_t combined_version = (key_version << 16) & version; | 348 uint32_t combined_version = (key_version << 16) & version; |
341 switch (type) { | 349 switch (type) { |
342 case FIRMWARE_VERSIONS: | 350 case FIRMWARE_VERSIONS: |
343 RETURN_ON_FAILURE(TlclWrite(FIRMWARE_VERSIONS_NV_INDEX, | 351 RETURN_ON_FAILURE(SafeWrite(FIRMWARE_VERSIONS_NV_INDEX, |
344 (uint8_t*) &combined_version, | 352 (uint8_t*) &combined_version, |
345 sizeof(uint32_t))); | 353 sizeof(uint32_t))); |
346 break; | 354 break; |
347 | 355 |
348 case KERNEL_VERSIONS: | 356 case KERNEL_VERSIONS: |
349 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, | 357 RETURN_ON_FAILURE(SafeWrite(KERNEL_VERSIONS_NV_INDEX, |
350 (uint8_t*) &combined_version, | 358 (uint8_t*) &combined_version, |
351 sizeof(uint32_t))); | 359 sizeof(uint32_t))); |
352 } | 360 } |
353 return TPM_SUCCESS; | 361 return TPM_SUCCESS; |
354 } | 362 } |
355 | 363 |
356 uint32_t LockFirmwareVersions() { | 364 uint32_t LockFirmwareVersions() { |
357 return TlclSetGlobalLock(); | 365 return TlclSetGlobalLock(); |
358 } | 366 } |
359 | 367 |
360 uint32_t LockKernelVersionsByLockingPP() { | 368 uint32_t LockKernelVersionsByLockingPP() { |
361 return TlclLockPhysicalPresence(); | 369 return TlclLockPhysicalPresence(); |
362 } | 370 } |
OLD | NEW |