| 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 |