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 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 | 70 |
71 /* Functions to read and write firmware and kernel spaces. */ | 71 /* Functions to read and write firmware and kernel spaces. */ |
72 static uint32_t ReadSpaceFirmware(RollbackSpaceFirmware* rsf) { | 72 static uint32_t ReadSpaceFirmware(RollbackSpaceFirmware* rsf) { |
73 return TlclRead(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware)); | 73 return TlclRead(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware)); |
74 } | 74 } |
75 | 75 |
76 static uint32_t WriteSpaceFirmware(const RollbackSpaceFirmware* rsf) { | 76 static uint32_t WriteSpaceFirmware(const RollbackSpaceFirmware* rsf) { |
77 return SafeWrite(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware)); | 77 return SafeWrite(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware)); |
78 } | 78 } |
79 | 79 |
| 80 #ifndef DISABLE_ROLLBACK_TPM |
80 static uint32_t ReadSpaceKernel(RollbackSpaceKernel* rsk) { | 81 static uint32_t ReadSpaceKernel(RollbackSpaceKernel* rsk) { |
81 return TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel)); | 82 return TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel)); |
82 } | 83 } |
| 84 #endif |
83 | 85 |
84 static uint32_t WriteSpaceKernel(const RollbackSpaceKernel* rsk) { | 86 static uint32_t WriteSpaceKernel(const RollbackSpaceKernel* rsk) { |
85 return SafeWrite(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel)); | 87 return SafeWrite(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel)); |
86 } | 88 } |
87 | 89 |
88 | |
89 | |
90 /* Creates the NVRAM spaces, and sets their initial values as needed. */ | 90 /* Creates the NVRAM spaces, and sets their initial values as needed. */ |
91 static uint32_t InitializeSpaces(RollbackSpaceFirmware* rsf, | 91 static uint32_t InitializeSpaces(RollbackSpaceFirmware* rsf, |
92 RollbackSpaceKernel* rsk) { | 92 RollbackSpaceKernel* rsk) { |
93 static const RollbackSpaceFirmware rsf_init = { | 93 static const RollbackSpaceFirmware rsf_init = { |
94 ROLLBACK_SPACE_FIRMWARE_VERSION, 0, 0, 0}; | 94 ROLLBACK_SPACE_FIRMWARE_VERSION, 0, 0, 0}; |
95 static const RollbackSpaceKernel rsk_init = { | 95 static const RollbackSpaceKernel rsk_init = { |
96 ROLLBACK_SPACE_KERNEL_VERSION, ROLLBACK_SPACE_KERNEL_UID, 0, 0}; | 96 ROLLBACK_SPACE_KERNEL_VERSION, ROLLBACK_SPACE_KERNEL_UID, 0, 0}; |
97 uint8_t nvlocked = 0; | 97 uint8_t nvlocked = 0; |
98 | 98 |
99 VBDEBUG(("TPM: Initializing spaces\n")); | 99 VBDEBUG(("TPM: Initializing spaces\n")); |
100 | 100 |
101 /* The TPM will not enforce the NV authorization restrictions until the | 101 /* The TPM will not enforce the NV authorization restrictions until the |
102 * execution of a TPM_NV_DefineSpace with the handle of TPM_NV_INDEX_LOCK. | 102 * execution of a TPM_NV_DefineSpace with the handle of TPM_NV_INDEX_LOCK. |
103 * Create that space if it doesn't already exist. */ | 103 * Create that space if it doesn't already exist. */ |
104 RETURN_ON_FAILURE(TlclGetFlags(NULL, NULL, &nvlocked)); | 104 RETURN_ON_FAILURE(TlclGetFlags(NULL, NULL, &nvlocked)); |
105 VBDEBUG(("TPM: nvlocked=%d\n", nvlocked)); | 105 VBDEBUG(("TPM: nvlocked=%d\n", nvlocked)); |
106 if (!nvlocked) { | 106 if (!nvlocked) { |
107 VBDEBUG(("TPM: Enabling NV locking\n")); | 107 VBDEBUG(("TPM: Enabling NV locking\n")); |
108 RETURN_ON_FAILURE(TlclSetNvLocked()); | 108 RETURN_ON_FAILURE(TlclSetNvLocked()); |
109 } | 109 } |
110 | 110 |
111 /* Initialize the firmware and kernel spaces */ | 111 /* Initialize the firmware and kernel spaces */ |
112 Memcpy(rsf, &rsf_init, sizeof(RollbackSpaceFirmware)); | 112 Memcpy(rsf, &rsf_init, sizeof(RollbackSpaceFirmware)); |
113 /* Initialize the backup copy of the kernel space to the same data | |
114 * as the kernel space */ | |
115 Memcpy(&rsf->kernel_backup, &rsk_init, sizeof(RollbackSpaceKernel)); | |
116 Memcpy(rsk, &rsk_init, sizeof(RollbackSpaceKernel)); | 113 Memcpy(rsk, &rsk_init, sizeof(RollbackSpaceKernel)); |
117 | 114 |
118 /* Define and set firmware and kernel spaces */ | 115 /* Define and set firmware and kernel spaces */ |
119 RETURN_ON_FAILURE(SafeDefineSpace(FIRMWARE_NV_INDEX, | 116 RETURN_ON_FAILURE(SafeDefineSpace(FIRMWARE_NV_INDEX, |
120 TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE, | 117 TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE, |
121 sizeof(RollbackSpaceFirmware))); | 118 sizeof(RollbackSpaceFirmware))); |
122 RETURN_ON_FAILURE(WriteSpaceFirmware(rsf)); | 119 RETURN_ON_FAILURE(WriteSpaceFirmware(rsf)); |
123 RETURN_ON_FAILURE(SafeDefineSpace(KERNEL_NV_INDEX, TPM_NV_PER_PPWRITE, | 120 RETURN_ON_FAILURE(SafeDefineSpace(KERNEL_NV_INDEX, TPM_NV_PER_PPWRITE, |
124 sizeof(RollbackSpaceKernel))); | 121 sizeof(RollbackSpaceKernel))); |
125 RETURN_ON_FAILURE(WriteSpaceKernel(rsk)); | 122 RETURN_ON_FAILURE(WriteSpaceKernel(rsk)); |
(...skipping 16 matching lines...) Expand all Loading... |
142 * bricked device. | 139 * bricked device. |
143 * | 140 * |
144 * As a side note, observe that we go through considerable hoops to avoid using | 141 * As a side note, observe that we go through considerable hoops to avoid using |
145 * the STCLEAR permissions for the index spaces. We do this to avoid writing | 142 * the STCLEAR permissions for the index spaces. We do this to avoid writing |
146 * to the TPM flashram at every reboot or wake-up, because of concerns about | 143 * to the TPM flashram at every reboot or wake-up, because of concerns about |
147 * the durability of the NVRAM. | 144 * the durability of the NVRAM. |
148 */ | 145 */ |
149 uint32_t SetupTPM(int recovery_mode, int developer_mode, | 146 uint32_t SetupTPM(int recovery_mode, int developer_mode, |
150 RollbackSpaceFirmware* rsf) { | 147 RollbackSpaceFirmware* rsf) { |
151 | 148 |
152 RollbackSpaceKernel rsk; | |
153 int rsf_dirty = 0; | 149 int rsf_dirty = 0; |
154 uint8_t new_flags = 0; | 150 uint8_t new_flags = 0; |
155 | |
156 uint8_t disable; | 151 uint8_t disable; |
157 uint8_t deactivated; | 152 uint8_t deactivated; |
158 uint32_t result; | 153 uint32_t result; |
159 uint32_t perms; | |
160 | 154 |
161 VBDEBUG(("TPM: SetupTPM(r%d, d%d)\n", recovery_mode, developer_mode)); | 155 VBDEBUG(("TPM: SetupTPM(r%d, d%d)\n", recovery_mode, developer_mode)); |
162 | 156 |
163 /* TODO: TlclLibInit() should be able to return failure */ | 157 /* TODO: TlclLibInit() should be able to return failure */ |
164 TlclLibInit(); | 158 TlclLibInit(); |
165 | 159 |
166 RETURN_ON_FAILURE(TlclStartup()); | 160 RETURN_ON_FAILURE(TlclStartup()); |
167 #ifdef USE_CONTINUE_SELF_TEST | 161 #ifdef USE_CONTINUE_SELF_TEST |
168 /* TODO: ContinueSelfTest() should be faster than SelfTestFull, but | 162 /* TODO: ContinueSelfTest() should be faster than SelfTestFull, but |
169 * may also not work properly in older TPM firmware. For now, do | 163 * may also not work properly in older TPM firmware. For now, do |
(...skipping 11 matching lines...) Expand all Loading... |
181 disable, deactivated)); | 175 disable, deactivated)); |
182 RETURN_ON_FAILURE(TlclSetEnable()); | 176 RETURN_ON_FAILURE(TlclSetEnable()); |
183 RETURN_ON_FAILURE(TlclSetDeactivated(0)); | 177 RETURN_ON_FAILURE(TlclSetDeactivated(0)); |
184 VBDEBUG(("TPM: Must reboot to re-enable\n")); | 178 VBDEBUG(("TPM: Must reboot to re-enable\n")); |
185 return TPM_E_MUST_REBOOT; | 179 return TPM_E_MUST_REBOOT; |
186 } | 180 } |
187 | 181 |
188 /* Read the firmware space. */ | 182 /* Read the firmware space. */ |
189 result = ReadSpaceFirmware(rsf); | 183 result = ReadSpaceFirmware(rsf); |
190 if (TPM_E_BADINDEX == result) { | 184 if (TPM_E_BADINDEX == result) { |
| 185 RollbackSpaceKernel rsk; |
| 186 |
191 /* This is the first time we've run, and the TPM has not been | 187 /* This is the first time we've run, and the TPM has not been |
192 * initialized. Initialize it. */ | 188 * initialized. Initialize it. */ |
193 VBDEBUG(("TPM: Not initialized yet.\n")); | 189 VBDEBUG(("TPM: Not initialized yet.\n")); |
194 RETURN_ON_FAILURE(InitializeSpaces(rsf, &rsk)); | 190 RETURN_ON_FAILURE(InitializeSpaces(rsf, &rsk)); |
195 } else if (TPM_SUCCESS != result) { | 191 } else if (TPM_SUCCESS != result) { |
196 VBDEBUG(("TPM: Firmware space in a bad state; giving up.\n")); | 192 VBDEBUG(("TPM: Firmware space in a bad state; giving up.\n")); |
197 return TPM_E_CORRUPTED_STATE; | 193 return TPM_E_CORRUPTED_STATE; |
198 } | 194 } |
199 VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n", | 195 VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n", |
200 rsf->struct_version, rsf->flags, rsf->fw_versions)); | 196 rsf->struct_version, rsf->flags, rsf->fw_versions)); |
201 | 197 |
202 /* Read the kernel space and verify its permissions. If the kernel | |
203 * space has the wrong permission, or it doesn't contain the right | |
204 * identifier, we give up. This will need to be fixed by the | |
205 * recovery kernel. We have to worry about this because at any time | |
206 * (even with PP turned off) the TPM owner can remove and redefine a | |
207 * PP-protected space (but not write to it). */ | |
208 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); | |
209 RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms)); | |
210 if (TPM_NV_PER_PPWRITE != perms || ROLLBACK_SPACE_KERNEL_UID != rsk.uid) | |
211 return TPM_E_CORRUPTED_STATE; | |
212 VBDEBUG(("TPM: Kernel space sv%d v%x\n", | |
213 rsk.struct_version, rsk.kernel_versions)); | |
214 | |
215 /* If the kernel space and its backup are different, we need to copy | |
216 * one to the other. Which one we copy depends on whether the | |
217 * use-backup flag is set. */ | |
218 if (0 != Memcmp(&rsk, &rsf->kernel_backup, sizeof(RollbackSpaceKernel))) { | |
219 VBDEBUG(("TPM: kernel space and backup are different\n")); | |
220 | |
221 if (rsf->flags & FLAG_KERNEL_SPACE_USE_BACKUP) { | |
222 VBDEBUG(("TPM: use backup kernel space\n")); | |
223 Memcpy(&rsk, &rsf->kernel_backup, sizeof(RollbackSpaceKernel)); | |
224 RETURN_ON_FAILURE(WriteSpaceKernel(&rsk)); | |
225 } else if (rsk.kernel_versions < rsf->kernel_backup.kernel_versions) { | |
226 VBDEBUG(("TPM: kernel versions %x < backup versions %x\n", | |
227 rsk.kernel_versions, rsf->kernel_backup.kernel_versions)); | |
228 return TPM_E_INTERNAL_INCONSISTENCY; | |
229 } else { | |
230 VBDEBUG(("TPM: copy kernel space to backup\n")); | |
231 Memcpy(&rsf->kernel_backup, &rsk, sizeof(RollbackSpaceKernel)); | |
232 rsf_dirty = 1; | |
233 } | |
234 } | |
235 | |
236 /* Clear ownership if developer flag has toggled */ | 198 /* Clear ownership if developer flag has toggled */ |
237 if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) != | 199 if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) != |
238 (rsf->flags & FLAG_LAST_BOOT_DEVELOPER)) { | 200 (rsf->flags & FLAG_LAST_BOOT_DEVELOPER)) { |
239 VBDEBUG(("TPM: Developer flag changed; clearing owner.\n")); | 201 VBDEBUG(("TPM: Developer flag changed; clearing owner.\n")); |
240 RETURN_ON_FAILURE(TPMClearAndReenable()); | 202 RETURN_ON_FAILURE(TPMClearAndReenable()); |
241 } | 203 } |
242 | 204 |
243 /* Update flags */ | 205 /* Update flags */ |
244 if (developer_mode) | 206 if (developer_mode) |
245 new_flags |= FLAG_LAST_BOOT_DEVELOPER; | 207 new_flags |= FLAG_LAST_BOOT_DEVELOPER; |
246 if (recovery_mode) { | 208 if (recovery_mode) |
247 new_flags |= FLAG_KERNEL_SPACE_USE_BACKUP; | |
248 g_rollback_recovery_mode = 1; /* Global variables are usable in | 209 g_rollback_recovery_mode = 1; /* Global variables are usable in |
249 * recovery mode */ | 210 * recovery mode */ |
250 } | 211 |
251 if (rsf->flags != new_flags) { | 212 if (rsf->flags != new_flags) { |
252 rsf->flags = new_flags; | 213 rsf->flags = new_flags; |
253 rsf_dirty = 1; | 214 rsf_dirty = 1; |
254 } | 215 } |
255 | 216 |
256 /* If firmware space is dirty, flush it back to the TPM */ | 217 /* If firmware space is dirty, flush it back to the TPM */ |
257 if (rsf_dirty) { | 218 if (rsf_dirty) { |
258 VBDEBUG(("TPM: Updating firmware space.\n")); | 219 VBDEBUG(("TPM: Updating firmware space.\n")); |
259 RETURN_ON_FAILURE(WriteSpaceFirmware(rsf)); | 220 RETURN_ON_FAILURE(WriteSpaceFirmware(rsf)); |
260 } | 221 } |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 return TPM_SUCCESS; | 277 return TPM_SUCCESS; |
317 } | 278 } |
318 | 279 |
319 #else | 280 #else |
320 | 281 |
321 uint32_t RollbackFirmwareSetup(int developer_mode, uint32_t* version) { | 282 uint32_t RollbackFirmwareSetup(int developer_mode, uint32_t* version) { |
322 RollbackSpaceFirmware rsf; | 283 RollbackSpaceFirmware rsf; |
323 | 284 |
324 RETURN_ON_FAILURE(SetupTPM(0, developer_mode, &rsf)); | 285 RETURN_ON_FAILURE(SetupTPM(0, developer_mode, &rsf)); |
325 *version = rsf.fw_versions; | 286 *version = rsf.fw_versions; |
326 VBDEBUG(("TPM: RollbackFirmwareSetup %x %x %x\n", (int)rsf.fw_versions)); | 287 VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)rsf.fw_versions)); |
327 return TPM_SUCCESS; | 288 return TPM_SUCCESS; |
328 } | 289 } |
329 | 290 |
330 uint32_t RollbackFirmwareWrite(uint32_t version) { | 291 uint32_t RollbackFirmwareWrite(uint32_t version) { |
331 RollbackSpaceFirmware rsf; | 292 RollbackSpaceFirmware rsf; |
332 | 293 |
333 RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf)); | 294 RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf)); |
334 VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)rsf.fw_versions, | 295 VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)rsf.fw_versions, |
335 (int)version)); | 296 (int)version)); |
336 rsf.fw_versions = version; | 297 rsf.fw_versions = version; |
(...skipping 17 matching lines...) Expand all Loading... |
354 /* We still return the result of SetupTPM even though we expect the caller to | 315 /* We still return the result of SetupTPM even though we expect the caller to |
355 * ignore it. It's useful in unit testing. */ | 316 * ignore it. It's useful in unit testing. */ |
356 return result; | 317 return result; |
357 } | 318 } |
358 | 319 |
359 uint32_t RollbackKernelRead(uint32_t* version) { | 320 uint32_t RollbackKernelRead(uint32_t* version) { |
360 if (g_rollback_recovery_mode) { | 321 if (g_rollback_recovery_mode) { |
361 *version = 0; | 322 *version = 0; |
362 } else { | 323 } else { |
363 RollbackSpaceKernel rsk; | 324 RollbackSpaceKernel rsk; |
| 325 uint32_t perms; |
| 326 |
| 327 /* Read the kernel space and verify its permissions. If the kernel |
| 328 * space has the wrong permission, or it doesn't contain the right |
| 329 * identifier, we give up. This will need to be fixed by the |
| 330 * recovery kernel. We have to worry about this because at any time |
| 331 * (even with PP turned off) the TPM owner can remove and redefine a |
| 332 * PP-protected space (but not write to it). */ |
364 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); | 333 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); |
| 334 RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms)); |
| 335 if (TPM_NV_PER_PPWRITE != perms || ROLLBACK_SPACE_KERNEL_UID != rsk.uid) |
| 336 return TPM_E_CORRUPTED_STATE; |
| 337 |
365 *version = rsk.kernel_versions; | 338 *version = rsk.kernel_versions; |
366 VBDEBUG(("TPM: RollbackKernelRead %x\n", (int)rsk.kernel_versions)); | 339 VBDEBUG(("TPM: RollbackKernelRead %x\n", (int)rsk.kernel_versions)); |
367 } | 340 } |
368 return TPM_SUCCESS; | 341 return TPM_SUCCESS; |
369 } | 342 } |
370 | 343 |
371 uint32_t RollbackKernelWrite(uint32_t version) { | 344 uint32_t RollbackKernelWrite(uint32_t version) { |
372 if (g_rollback_recovery_mode) { | 345 if (g_rollback_recovery_mode) { |
373 return TPM_SUCCESS; | 346 return TPM_SUCCESS; |
374 } else { | 347 } else { |
375 RollbackSpaceKernel rsk; | 348 RollbackSpaceKernel rsk; |
376 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); | 349 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); |
377 VBDEBUG(("TPM: RollbackKernelWrite %x --> %x\n", (int)rsk.kernel_versions, | 350 VBDEBUG(("TPM: RollbackKernelWrite %x --> %x\n", (int)rsk.kernel_versions, |
378 (int)version)); | 351 (int)version)); |
379 rsk.kernel_versions = version; | 352 rsk.kernel_versions = version; |
380 return WriteSpaceKernel(&rsk); | 353 return WriteSpaceKernel(&rsk); |
381 } | 354 } |
382 } | 355 } |
383 | 356 |
384 uint32_t RollbackKernelLock(void) { | 357 uint32_t RollbackKernelLock(void) { |
385 if (g_rollback_recovery_mode) { | 358 if (g_rollback_recovery_mode) { |
386 return TPM_SUCCESS; | 359 return TPM_SUCCESS; |
387 } else { | 360 } else { |
388 return TlclLockPhysicalPresence(); | 361 return TlclLockPhysicalPresence(); |
389 } | 362 } |
390 } | 363 } |
391 | 364 |
392 #endif // DISABLE_ROLLBACK_TPM | 365 #endif // DISABLE_ROLLBACK_TPM |
OLD | NEW |