1 /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 * 5 * Functions for querying, manipulating and locking rollback indices 6 * stored in the TPM NVRAM. 7 */ 8 9 #include "sysincludes.h" 10 11 #include "crc8.h" 12 #include "rollback_index.h" 13 #include "tlcl.h" 14 #include "tss_constants.h" 15 #include "utility.h" 16 #include "vboot_api.h" 17 18 #ifndef offsetof 19 #define offsetof(A,B) __builtin_offsetof(A,B) 20 #endif 21 22 /* 23 * Provide protoypes for functions not in the header file. These prototypes 24 * fix -Wmissing-prototypes warnings. 25 */ 26 uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf); 27 uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf); 28 uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk); 29 uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk); 30 31 #ifdef FOR_TEST 32 /* 33 * Compiling for unit test, so we need the real implementations of 34 * rollback functions. The unit test mocks the underlying tlcl 35 * functions, so this is ok to run on the host. 36 */ 37 #undef CHROMEOS_ENVIRONMENT 38 #undef DISABLE_ROLLBACK_TPM 39 #endif 40 41 #define RETURN_ON_FAILURE(tpm_command) do { \ 42 uint32_t result_; \ 43 if ((result_ = (tpm_command)) != TPM_SUCCESS) { \ 44 VBDEBUG(("Rollback: %08x returned by " #tpm_command \ 45 "\n", (int)result_)); \ 46 return result_; \ 47 } \ 48 } while (0) 49 50 51 uint32_t TPMClearAndReenable(void) 52 { 53 VBDEBUG(("TPM: Clear and re-enable\n")); 54 RETURN_ON_FAILURE(TlclForceClear()); 55 RETURN_ON_FAILURE(TlclSetEnable()); 56 RETURN_ON_FAILURE(TlclSetDeactivated(0)); 57 58 return TPM_SUCCESS; 59 } 60 61 uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length) 62 { 63 uint32_t result = TlclWrite(index, data, length); 64 if (result == TPM_E_MAXNVWRITES) { 65 RETURN_ON_FAILURE(TPMClearAndReenable()); 66 return TlclWrite(index, data, length); 67 } else { 68 return result; 69 } 70 } 71 72 uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size) 73 { 74 uint32_t result = TlclDefineSpace(index, perm, size); 75 if (result == TPM_E_MAXNVWRITES) { 76 RETURN_ON_FAILURE(TPMClearAndReenable()); 77 return TlclDefineSpace(index, perm, size); 78 } else { 79 return result; 80 } 81 } 82 83 /* Functions to read and write firmware and kernel spaces. */ 84 uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf) 85 { 86 uint32_t r; 87 int attempts = 3; 88 89 while (attempts--) { 90 r = TlclRead(FIRMWARE_NV_INDEX, rsf, 91 sizeof(RollbackSpaceFirmware)); 92 if (r != TPM_SUCCESS) 93 return r; 94 95 /* 96 * No CRC in this version, so we'll create one when we write 97 * it. Note that we're marking this as version 2, not 98 * ROLLBACK_SPACE_FIRMWARE_VERSION, because version 2 just 99 * added the CRC. Later versions will need to set default 100 * values for any extra fields explicitly (probably here). 101 */ 102 if (rsf->struct_version < 2) { 103 /* Danger Will Robinson! Danger! */ 104 rsf->struct_version = 2; 105 return TPM_SUCCESS; 106 } 107 108 /* 109 * If the CRC is good, we're done. If it's bad, try a couple 110 * more times to see if it gets better before we give up. It 111 * could just be noise. 112 */ 113 if (rsf->crc8 == Crc8(rsf, 114 offsetof(RollbackSpaceFirmware, crc8))) 115 return TPM_SUCCESS; 116 117 VBDEBUG(("TPM: %s() - bad CRC\n", __func__)); 118 } 119 120 VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__)); 121 return TPM_E_CORRUPTED_STATE; 122 } 123 124 uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf) 125 { 126 RollbackSpaceFirmware rsf2; 127 uint32_t r; 128 int attempts = 3; 129 130 /* All writes should use struct_version 2 or greater. */ 131 if (rsf->struct_version < 2) 132 rsf->struct_version = 2; 133 rsf->crc8 = Crc8(rsf, offsetof(RollbackSpaceFirmware, crc8)); 134 135 while (attempts--) { 136 r = SafeWrite(FIRMWARE_NV_INDEX, rsf, 137 sizeof(RollbackSpaceFirmware)); 138 /* Can't write, not gonna try again */ 139 if (r != TPM_SUCCESS) 140 return r; 141 142 /* Read it back to be sure it got the right values. */ 143 r = ReadSpaceFirmware(&rsf2); /* This checks the CRC */ 144 if (r == TPM_SUCCESS) 145 return r; 146 147 VBDEBUG(("TPM: %s() - bad CRC\n", __func__)); 148 /* Try writing it again. Maybe it was garbled on the way out. */ 149 } 150 151 VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__)); 152 return TPM_E_CORRUPTED_STATE; 153 } 154 155 uint32_t SetVirtualDevMode(int val) 156 { 157 RollbackSpaceFirmware rsf; 158 159 VBDEBUG(("TPM: Entering %s()\n", __func__)); 160 if (TPM_SUCCESS != ReadSpaceFirmware(&rsf)) 161 return VBERROR_TPM_FIRMWARE_SETUP; 162 163 VBDEBUG(("TPM: flags were 0x%02x\n", rsf.flags)); 164 if (val) 165 rsf.flags |= FLAG_VIRTUAL_DEV_MODE_ON; 166 else 167 rsf.flags &= ~FLAG_VIRTUAL_DEV_MODE_ON; 168 /* 169 * NOTE: This doesn't update the FLAG_LAST_BOOT_DEVELOPER bit. That 170 * will be done by SetupTPM() on the next boot. 171 */ 172 VBDEBUG(("TPM: flags are now 0x%02x\n", rsf.flags)); 173 174 if (TPM_SUCCESS != WriteSpaceFirmware(&rsf)) 175 return VBERROR_TPM_SET_BOOT_MODE_STATE; 176 177 VBDEBUG(("TPM: Leaving %s()\n", __func__)); 178 return VBERROR_SUCCESS; 179 } 180 181 uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk) 182 { 183 uint32_t r; 184 int attempts = 3; 185 186 while (attempts--) { 187 r = TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel)); 188 if (r != TPM_SUCCESS) 189 return r; 190 191 /* 192 * No CRC in this version, so we'll create one when we write 193 * it. Note that we're marking this as version 2, not 194 * ROLLBACK_SPACE_KERNEL_VERSION, because version 2 just added 195 * the CRC. Later versions will need to set default values for 196 * any extra fields explicitly (probably here). 197 */ 198 if (rsk->struct_version < 2) { 199 /* Danger Will Robinson! Danger! */ 200 rsk->struct_version = 2; 201 return TPM_SUCCESS; 202 } 203 204 /* 205 * If the CRC is good, we're done. If it's bad, try a couple 206 * more times to see if it gets better before we give up. It 207 * could just be noise. 208 */ 209 if (rsk->crc8 == Crc8(rsk, offsetof(RollbackSpaceKernel, crc8))) 210 return TPM_SUCCESS; 211 212 VBDEBUG(("TPM: %s() - bad CRC\n", __func__)); 213 } 214 215 VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__)); 216 return TPM_E_CORRUPTED_STATE; 217 } 218 219 uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk) 220 { 221 RollbackSpaceKernel rsk2; 222 uint32_t r; 223 int attempts = 3; 224 225 /* All writes should use struct_version 2 or greater. */ 226 if (rsk->struct_version < 2) 227 rsk->struct_version = 2; 228 rsk->crc8 = Crc8(rsk, offsetof(RollbackSpaceKernel, crc8)); 229 230 while (attempts--) { 231 r = SafeWrite(KERNEL_NV_INDEX, rsk, 232 sizeof(RollbackSpaceKernel)); 233 /* Can't write, not gonna try again */ 234 if (r != TPM_SUCCESS) 235 return r; 236 237 /* Read it back to be sure it got the right values. */ 238 r = ReadSpaceKernel(&rsk2); /* This checks the CRC */ 239 if (r == TPM_SUCCESS) 240 return r; 241 242 VBDEBUG(("TPM: %s() - bad CRC\n", __func__)); 243 /* Try writing it again. Maybe it was garbled on the way out. */ 244 } 245 246 VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__)); 247 return TPM_E_CORRUPTED_STATE; 248 } 249 250 uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf, 251 RollbackSpaceKernel *rsk) 252 { 253 static const RollbackSpaceFirmware rsf_init = { 254 .struct_version = ROLLBACK_SPACE_FIRMWARE_VERSION, 255 }; 256 static const RollbackSpaceKernel rsk_init = { 257 .struct_version = ROLLBACK_SPACE_KERNEL_VERSION, 258 .uid = ROLLBACK_SPACE_KERNEL_UID, 259 }; 260 TPM_PERMANENT_FLAGS pflags; 261 uint32_t result; 262 263 VBDEBUG(("TPM: One-time initialization\n")); 264 265 /* 266 * Do a full test. This only happens the first time the device is 267 * turned on in the factory, so performance is not an issue. This is 268 * almost certainly not necessary, but it gives us more confidence 269 * about some code paths below that are difficult to 270 * test---specifically the ones that set lifetime flags, and are only 271 * executed once per physical TPM. 272 */ 273 result = TlclSelfTestFull(); 274 if (result != TPM_SUCCESS) 275 return result; 276 277 result = TlclGetPermanentFlags(&pflags); 278 if (result != TPM_SUCCESS) 279 return result; 280 281 /* 282 * TPM may come from the factory without physical presence finalized. 283 * Fix if necessary. 284 */ 285 VBDEBUG(("TPM: physicalPresenceLifetimeLock=%d\n", 286 pflags.physicalPresenceLifetimeLock)); 287 if (!pflags.physicalPresenceLifetimeLock) { 288 VBDEBUG(("TPM: Finalizing physical presence\n")); 289 RETURN_ON_FAILURE(TlclFinalizePhysicalPresence()); 290 } 291 292 /* 293 * The TPM will not enforce the NV authorization restrictions until the 294 * execution of a TPM_NV_DefineSpace with the handle of 295 * TPM_NV_INDEX_LOCK. Here we create that space if it doesn't already 296 * exist. */ 297 VBDEBUG(("TPM: nvLocked=%d\n", pflags.nvLocked)); 298 if (!pflags.nvLocked) { 299 VBDEBUG(("TPM: Enabling NV locking\n")); 300 RETURN_ON_FAILURE(TlclSetNvLocked()); 301 } 302 303 /* Clear TPM owner, in case the TPM is already owned for some reason. */ 304 VBDEBUG(("TPM: Clearing owner\n")); 305 RETURN_ON_FAILURE(TPMClearAndReenable()); 306 307 /* Initializes the firmware and kernel spaces */ 308 Memcpy(rsf, &rsf_init, sizeof(RollbackSpaceFirmware)); 309 Memcpy(rsk, &rsk_init, sizeof(RollbackSpaceKernel)); 310 311 /* Define the backup space. No need to initialize it, though. */ 312 RETURN_ON_FAILURE(SafeDefineSpace( 313 BACKUP_NV_INDEX, TPM_NV_PER_PPWRITE, BACKUP_NV_SIZE)); 314 315 /* Define and initialize the kernel space */ 316 RETURN_ON_FAILURE(SafeDefineSpace(KERNEL_NV_INDEX, TPM_NV_PER_PPWRITE, 317 sizeof(RollbackSpaceKernel))); 318 RETURN_ON_FAILURE(WriteSpaceKernel(rsk)); 319 320 /* Do the firmware space last, so we retry if we don't get this far. */ 321 RETURN_ON_FAILURE(SafeDefineSpace( 322 FIRMWARE_NV_INDEX, 323 TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE, 324 sizeof(RollbackSpaceFirmware))); 325 RETURN_ON_FAILURE(WriteSpaceFirmware(rsf)); 326 327 return TPM_SUCCESS; 328 } 329 330 331 /* 332 * SetupTPM starts the TPM and establishes the root of trust for the 333 * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a 334 * TPM hardware failure. 3 An unexpected TPM state due to some attack. In 335 * general we cannot easily distinguish the kind of failure, so our strategy is 336 * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM 337 * again, which executes (almost) the same sequence of operations. There is a 338 * good chance that, if recovery mode was entered because of a TPM failure, the 339 * failure will repeat itself. (In general this is impossible to guarantee 340 * because we have no way of creating the exact TPM initial state at the 341 * previous boot.) In recovery mode, we ignore the failure and continue, thus 342 * giving the recovery kernel a chance to fix things (that's why we don't set 343 * bGlobalLock). The choice is between a knowingly insecure device and a 344 * bricked device. 345 * 346 * As a side note, observe that we go through considerable hoops to avoid using 347 * the STCLEAR permissions for the index spaces. We do this to avoid writing 348 * to the TPM flashram at every reboot or wake-up, because of concerns about 349 * the durability of the NVRAM. 350 */ 351 uint32_t SetupTPM(int developer_mode, int disable_dev_request, 352 int clear_tpm_owner_request, RollbackSpaceFirmware* rsf) 353 { 354 uint8_t in_flags; 355 uint8_t disable; 356 uint8_t deactivated; 357 uint32_t result; 358 uint32_t versions; 359 360 RETURN_ON_FAILURE(TlclLibInit()); 361 362 #ifdef TEGRA_SOFT_REBOOT_WORKAROUND 363 result = TlclStartup(); 364 if (result == TPM_E_INVALID_POSTINIT) { 365 /* 366 * Some prototype hardware doesn't reset the TPM on a CPU 367 * reset. We do a hard reset to get around this. 368 */ 369 VBDEBUG(("TPM: soft reset detected\n", result)); 370 return TPM_E_MUST_REBOOT; 371 } else if (result != TPM_SUCCESS) { 372 VBDEBUG(("TPM: TlclStartup returned %08x\n", result)); 373 return result; 374 } 375 #else 376 RETURN_ON_FAILURE(TlclStartup()); 377 #endif 378 379 /* 380 * Some TPMs start the self test automatically at power on. In that case we 381 * don't need to call ContinueSelfTest. On some (other) TPMs, 382 * ContinueSelfTest may block. In that case, we definitely don't want to 383 * call it here. For TPMs in the intersection of these two sets, we're 384 * screwed. (In other words: TPMs that require manually starting the 385 * self-test AND block will have poor performance until we split 386 * TlclSendReceive() into Send() and Receive(), and have a state machine to 387 * control setup.) 388 * 389 * This comment is likely to become obsolete in the near future, so don't 390 * trust it. It may have not been updated. 391 */ 392 #ifdef TPM_MANUAL_SELFTEST 393 #ifdef TPM_BLOCKING_CONTINUESELFTEST 394 #warning "lousy TPM!" 395 #endif 396 RETURN_ON_FAILURE(TlclContinueSelfTest()); 397 #endif 398 result = TlclAssertPhysicalPresence(); 399 if (result != TPM_SUCCESS) { 400 /* 401 * It is possible that the TPM was delivered with the physical 402 * presence command disabled. This tries enabling it, then 403 * tries asserting PP again. 404 */ 405 RETURN_ON_FAILURE(TlclPhysicalPresenceCMDEnable()); 406 RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); 407 } 408 409 /* Check that the TPM is enabled and activated. */ 410 RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated, NULL)); 411 if (disable || deactivated) { 412 VBDEBUG(("TPM: disabled (%d) or deactivated (%d). Fixing...\n", 413 disable, deactivated)); 414 RETURN_ON_FAILURE(TlclSetEnable()); 415 RETURN_ON_FAILURE(TlclSetDeactivated(0)); 416 VBDEBUG(("TPM: Must reboot to re-enable\n")); 417 return TPM_E_MUST_REBOOT; 418 } 419 420 /* Read the firmware space. */ 421 result = ReadSpaceFirmware(rsf); 422 if (TPM_E_BADINDEX == result) { 423 RollbackSpaceKernel rsk; 424 425 /* 426 * This is the first time we've run, and the TPM has not been 427 * initialized. Initialize it. 428 */ 429 VBDEBUG(("TPM: Not initialized yet.\n")); 430 RETURN_ON_FAILURE(OneTimeInitializeTPM(rsf, &rsk)); 431 } else if (TPM_SUCCESS != result) { 432 VBDEBUG(("TPM: Firmware space in a bad state; giving up.\n")); 433 return TPM_E_CORRUPTED_STATE; 434 } 435 Memcpy(&versions, &rsf->fw_versions, sizeof(versions)); 436 VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n", 437 rsf->struct_version, rsf->flags, versions)); 438 in_flags = rsf->flags; 439 440 /* If we've been asked to clear the virtual dev-mode flag, do so now */ 441 if (disable_dev_request) { 442 rsf->flags &= ~FLAG_VIRTUAL_DEV_MODE_ON; 443 VBDEBUG(("TPM: Clearing virt dev-switch: f%x\n", rsf->flags)); 444 } 445 446 /* 447 * The developer_mode value that's passed in is only set by a hardware 448 * dev-switch. We should OR it with the virtual switch, whether or not 449 * the virtual switch is used. If it's not used, it shouldn't change, 450 * so it doesn't matter. 451 */ 452 if (rsf->flags & FLAG_VIRTUAL_DEV_MODE_ON) 453 developer_mode = 1; 454 455 /* 456 * Clear ownership if developer flag has toggled, or if an owner-clear 457 * has been requested. 458 */ 459 if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) != 460 (in_flags & FLAG_LAST_BOOT_DEVELOPER)) { 461 VBDEBUG(("TPM: Developer flag changed; clearing owner.\n")); 462 RETURN_ON_FAILURE(TPMClearAndReenable()); 463 } else if (clear_tpm_owner_request) { 464 VBDEBUG(("TPM: Clearing owner as specifically requested.\n")); 465 RETURN_ON_FAILURE(TPMClearAndReenable()); 466 } 467 468 if (developer_mode) 469 rsf->flags |= FLAG_LAST_BOOT_DEVELOPER; 470 else 471 rsf->flags &= ~FLAG_LAST_BOOT_DEVELOPER; 472 473 474 /* If firmware space is dirty, flush it back to the TPM */ 475 if (rsf->flags != in_flags) { 476 VBDEBUG(("TPM: Updating firmware space.\n")); 477 RETURN_ON_FAILURE(WriteSpaceFirmware(rsf)); 478 } 479 480 VBDEBUG(("TPM: SetupTPM() succeeded\n")); 481 return TPM_SUCCESS; 482 } 483 484 485 #ifdef DISABLE_ROLLBACK_TPM 486 /* Dummy implementations which don't support TPM rollback protection */ 487 488 uint32_t RollbackS3Resume(void) 489 { 490 #ifndef CHROMEOS_ENVIRONMENT 491 /* 492 * Initialize the TPM, but ignore return codes. In ChromeOS 493 * environment, don't even talk to the TPM. 494 */ 495 TlclLibInit(); 496 TlclResume(); 497 #endif 498 return TPM_SUCCESS; 499 } 500 501 uint32_t RollbackFirmwareSetup(int is_hw_dev, 502 int disable_dev_request, 503 int clear_tpm_owner_request, 504 int *is_virt_dev, uint32_t *version) 505 { 506 #ifndef CHROMEOS_ENVIRONMENT 507 /* 508 * Initialize the TPM, but ignores return codes. In ChromeOS 509 * environment, don't even talk to the TPM. 510 */ 511 TlclLibInit(); 512 TlclStartup(); 513 TlclContinueSelfTest(); 514 #endif 515 *is_virt_dev = 0; 516 *version = 0; 517 return TPM_SUCCESS; 518 } 519 520 uint32_t RollbackFirmwareWrite(uint32_t version) 521 { 522 return TPM_SUCCESS; 523 } 524 525 uint32_t RollbackFirmwareLock(void) 526 { 527 return TPM_SUCCESS; 528 } 529 530 uint32_t RollbackKernelRead(uint32_t* version) 531 { 532 *version = 0; 533 return TPM_SUCCESS; 534 } 535 536 uint32_t RollbackKernelWrite(uint32_t version) 537 { 538 return TPM_SUCCESS; 539 } 540 541 uint32_t RollbackBackupRead(uint8_t *raw) 542 { 543 return TPM_SUCCESS; 544 } 545 546 uint32_t RollbackBackupWrite(uint8_t *raw) 547 { 548 return TPM_SUCCESS; 549 } 550 551 uint32_t RollbackKernelLock(int recovery_mode) 552 { 553 return TPM_SUCCESS; 554 } 555 556 #else 557 558 uint32_t RollbackS3Resume(void) 559 { 560 uint32_t result; 561 RETURN_ON_FAILURE(TlclLibInit()); 562 result = TlclResume(); 563 if (result == TPM_E_INVALID_POSTINIT) { 564 /* 565 * We're on a platform where the TPM maintains power in S3, so 566 * it's already initialized. 567 */ 568 return TPM_SUCCESS; 569 } 570 return result; 571 } 572 573 uint32_t RollbackFirmwareSetup(int is_hw_dev, 574 int disable_dev_request, 575 int clear_tpm_owner_request, 576 int *is_virt_dev, uint32_t *version) 577 { 578 RollbackSpaceFirmware rsf; 579 580 /* Set version to 0 in case we fail */ 581 *version = 0; 582 583 RETURN_ON_FAILURE(SetupTPM(is_hw_dev, disable_dev_request, 584 clear_tpm_owner_request, &rsf)); 585 Memcpy(version, &rsf.fw_versions, sizeof(*version)); 586 *is_virt_dev = (rsf.flags & FLAG_VIRTUAL_DEV_MODE_ON) ? 1 : 0; 587 VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)*version)); 588 return TPM_SUCCESS; 589 } 590 591 uint32_t RollbackFirmwareWrite(uint32_t version) 592 { 593 RollbackSpaceFirmware rsf; 594 uint32_t old_version; 595 596 RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf)); 597 Memcpy(&old_version, &rsf.fw_versions, sizeof(old_version)); 598 VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)old_version, 599 (int)version)); 600 Memcpy(&rsf.fw_versions, &version, sizeof(version)); 601 return WriteSpaceFirmware(&rsf); 602 } 603 604 uint32_t RollbackFirmwareLock(void) 605 { 606 return TlclSetGlobalLock(); 607 } 608 609 uint32_t RollbackKernelRead(uint32_t* version) 610 { 611 RollbackSpaceKernel rsk; 612 uint32_t perms, uid; 613 614 /* 615 * Read the kernel space and verify its permissions. If the kernel 616 * space has the wrong permission, or it doesn't contain the right 617 * identifier, we give up. This will need to be fixed by the 618 * recovery kernel. We have to worry about this because at any time 619 * (even with PP turned off) the TPM owner can remove and redefine a 620 * PP-protected space (but not write to it). 621 */ 622 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); 623 RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms)); 624 Memcpy(&uid, &rsk.uid, sizeof(uid)); 625 if (TPM_NV_PER_PPWRITE != perms || ROLLBACK_SPACE_KERNEL_UID != uid) 626 return TPM_E_CORRUPTED_STATE; 627 628 Memcpy(version, &rsk.kernel_versions, sizeof(*version)); 629 VBDEBUG(("TPM: RollbackKernelRead %x\n", (int)*version)); 630 return TPM_SUCCESS; 631 } 632 633 uint32_t RollbackKernelWrite(uint32_t version) 634 { 635 RollbackSpaceKernel rsk; 636 uint32_t old_version; 637 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); 638 Memcpy(&old_version, &rsk.kernel_versions, sizeof(old_version)); 639 VBDEBUG(("TPM: RollbackKernelWrite %x --> %x\n", 640 (int)old_version, (int)version)); 641 Memcpy(&rsk.kernel_versions, &version, sizeof(version)); 642 return WriteSpaceKernel(&rsk); 643 } 644 645 /* 646 * We don't really care whether the TPM owner has been messing with this or 647 * not. We lock it along with the Kernel space just to avoid problems, but it's 648 * only useful in dev-mode and only when the battery has been drained 649 * completely. There aren't any security issues. It's just in the TPM because 650 * we don't have any other place to keep it. 651 */ 652 uint32_t RollbackBackupRead(uint8_t *raw) 653 { 654 uint32_t r; 655 r = TlclRead(BACKUP_NV_INDEX, raw, BACKUP_NV_SIZE); 656 VBDEBUG(("TPM: %s returning 0x%x\n", __func__, r)); 657 return r; 658 } 659 660 uint32_t RollbackBackupWrite(uint8_t *raw) 661 { 662 uint32_t r; 663 r = TlclWrite(BACKUP_NV_INDEX, raw, BACKUP_NV_SIZE); 664 VBDEBUG(("TPM: %s returning 0x%x\n", __func__, r)); 665 return r; 666 } 667 668 uint32_t RollbackKernelLock(int recovery_mode) 669 { 670 if (recovery_mode) 671 return TPM_SUCCESS; 672 else 673 return TlclLockPhysicalPresence(); 674 } 675 676 #endif /* DISABLE_ROLLBACK_TPM */ 677