Gaurav Shah | ce0cc30 | 2010-03-24 13:48:55 -0700 | [diff] [blame] | 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 |
| 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 "rollback_index.h" |
| 10 | |
Gaurav Shah | ce0cc30 | 2010-03-24 13:48:55 -0700 | [diff] [blame] | 11 | #include "tlcl.h" |
Gaurav Shah | 887e3d4 | 2010-04-27 16:26:48 -0700 | [diff] [blame] | 12 | #include "tss_constants.h" |
Randall Spangler | f302905 | 2010-06-16 13:42:58 -0700 | [diff] [blame] | 13 | #include "utility.h" |
Gaurav Shah | ce0cc30 | 2010-03-24 13:48:55 -0700 | [diff] [blame] | 14 | |
Luigi Semenzato | 2b9ddae | 2010-06-28 13:34:31 -0700 | [diff] [blame] | 15 | static int g_rollback_recovery_mode = 0; |
Gaurav Shah | ce0cc30 | 2010-03-24 13:48:55 -0700 | [diff] [blame] | 16 | |
vbendeb | 3ecaf77 | 2010-06-24 16:19:53 -0700 | [diff] [blame] | 17 | /* disable MSVC warning on const logical expression (as in } while(0);) */ |
| 18 | __pragma(warning (disable: 4127)) |
| 19 | |
Luigi Semenzato | 4f11c36 | 2010-06-10 11:01:04 -0700 | [diff] [blame] | 20 | #define RETURN_ON_FAILURE(tpm_command) do { \ |
| 21 | uint32_t result; \ |
| 22 | if ((result = (tpm_command)) != TPM_SUCCESS) { \ |
Randall Spangler | 7a786b7 | 2010-07-08 13:29:42 -0700 | [diff] [blame] | 23 | VBDEBUG(("Rollback: %08x returned by " #tpm_command "\n", (int)result)); \ |
Luigi Semenzato | 4f11c36 | 2010-06-10 11:01:04 -0700 | [diff] [blame] | 24 | return result; \ |
| 25 | } \ |
Luigi Semenzato | 59204c5 | 2010-06-09 13:37:15 -0700 | [diff] [blame] | 26 | } while (0) |
| 27 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 28 | |
Luigi Semenzato | 416f681 | 2010-07-08 12:12:12 -0700 | [diff] [blame] | 29 | uint32_t TPMClearAndReenable(void) { |
Randall Spangler | 3e1081f | 2010-07-19 10:04:21 -0700 | [diff] [blame] | 30 | VBDEBUG(("TPM: Clear and re-enable\n")); |
Luigi Semenzato | 361049c | 2010-06-22 13:37:53 -0700 | [diff] [blame] | 31 | RETURN_ON_FAILURE(TlclForceClear()); |
| 32 | RETURN_ON_FAILURE(TlclSetEnable()); |
| 33 | RETURN_ON_FAILURE(TlclSetDeactivated(0)); |
Randall Spangler | ada3fa9 | 2010-07-20 15:35:49 -0700 | [diff] [blame] | 34 | |
Luigi Semenzato | 361049c | 2010-06-22 13:37:53 -0700 | [diff] [blame] | 35 | return TPM_SUCCESS; |
| 36 | } |
| 37 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 38 | |
Luigi Semenzato | 361049c | 2010-06-22 13:37:53 -0700 | [diff] [blame] | 39 | /* Like TlclWrite(), but checks for write errors due to hitting the 64-write |
| 40 | * limit and clears the TPM when that happens. This can only happen when the |
| 41 | * TPM is unowned, so it is OK to clear it (and we really have no choice). |
| 42 | * This is not expected to happen frequently, but it could happen. |
| 43 | */ |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 44 | static uint32_t SafeWrite(uint32_t index, const void* data, uint32_t length) { |
Luigi Semenzato | 361049c | 2010-06-22 13:37:53 -0700 | [diff] [blame] | 45 | uint32_t result = TlclWrite(index, data, length); |
| 46 | if (result == TPM_E_MAXNVWRITES) { |
| 47 | RETURN_ON_FAILURE(TPMClearAndReenable()); |
| 48 | return TlclWrite(index, data, length); |
| 49 | } else { |
| 50 | return result; |
| 51 | } |
| 52 | } |
| 53 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 54 | |
Luigi Semenzato | 8510d91 | 2010-07-08 15:40:30 -0700 | [diff] [blame] | 55 | /* Similarly to SafeWrite(), this ensures we don't fail a DefineSpace because |
| 56 | * we hit the TPM write limit. This is even less likely to happen than with |
| 57 | * writes because we only define spaces once at initialization, but we'd rather |
| 58 | * be paranoid about this. |
| 59 | */ |
| 60 | static uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size) { |
| 61 | uint32_t result = TlclDefineSpace(index, perm, size); |
| 62 | if (result == TPM_E_MAXNVWRITES) { |
| 63 | RETURN_ON_FAILURE(TPMClearAndReenable()); |
| 64 | return TlclDefineSpace(index, perm, size); |
| 65 | } else { |
| 66 | return result; |
| 67 | } |
| 68 | } |
| 69 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 70 | |
| 71 | /* Functions to read and write firmware and kernel spaces. */ |
| 72 | static uint32_t ReadSpaceFirmware(RollbackSpaceFirmware* rsf) { |
| 73 | return TlclRead(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware)); |
Luigi Semenzato | 4f11c36 | 2010-06-10 11:01:04 -0700 | [diff] [blame] | 74 | } |
| 75 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 76 | static uint32_t WriteSpaceFirmware(const RollbackSpaceFirmware* rsf) { |
| 77 | return SafeWrite(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware)); |
Luigi Semenzato | 4f11c36 | 2010-06-10 11:01:04 -0700 | [diff] [blame] | 78 | } |
| 79 | |
Randall Spangler | bb5d9f1 | 2010-08-16 15:36:07 -0700 | [diff] [blame^] | 80 | #ifndef DISABLE_ROLLBACK_TPM |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 81 | static uint32_t ReadSpaceKernel(RollbackSpaceKernel* rsk) { |
| 82 | return TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel)); |
| 83 | } |
Randall Spangler | bb5d9f1 | 2010-08-16 15:36:07 -0700 | [diff] [blame^] | 84 | #endif |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 85 | |
| 86 | static uint32_t WriteSpaceKernel(const RollbackSpaceKernel* rsk) { |
| 87 | return SafeWrite(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel)); |
| 88 | } |
| 89 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 90 | /* Creates the NVRAM spaces, and sets their initial values as needed. */ |
| 91 | static uint32_t InitializeSpaces(RollbackSpaceFirmware* rsf, |
| 92 | RollbackSpaceKernel* rsk) { |
| 93 | static const RollbackSpaceFirmware rsf_init = { |
| 94 | ROLLBACK_SPACE_FIRMWARE_VERSION, 0, 0, 0}; |
| 95 | static const RollbackSpaceKernel rsk_init = { |
| 96 | ROLLBACK_SPACE_KERNEL_VERSION, ROLLBACK_SPACE_KERNEL_UID, 0, 0}; |
Randall Spangler | 3e1081f | 2010-07-19 10:04:21 -0700 | [diff] [blame] | 97 | uint8_t nvlocked = 0; |
Gaurav Shah | ce0cc30 | 2010-03-24 13:48:55 -0700 | [diff] [blame] | 98 | |
Randall Spangler | 3e1081f | 2010-07-19 10:04:21 -0700 | [diff] [blame] | 99 | VBDEBUG(("TPM: Initializing spaces\n")); |
Gaurav Shah | ce0cc30 | 2010-03-24 13:48:55 -0700 | [diff] [blame] | 100 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 101 | /* The TPM will not enforce the NV authorization restrictions until the |
Randall Spangler | 63dffcb | 2010-08-05 15:13:14 -0700 | [diff] [blame] | 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. */ |
Randall Spangler | 3e1081f | 2010-07-19 10:04:21 -0700 | [diff] [blame] | 104 | RETURN_ON_FAILURE(TlclGetFlags(NULL, NULL, &nvlocked)); |
| 105 | VBDEBUG(("TPM: nvlocked=%d\n", nvlocked)); |
| 106 | if (!nvlocked) { |
| 107 | VBDEBUG(("TPM: Enabling NV locking\n")); |
| 108 | RETURN_ON_FAILURE(TlclSetNvLocked()); |
| 109 | } |
| 110 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 111 | /* Initialize the firmware and kernel spaces */ |
| 112 | Memcpy(rsf, &rsf_init, sizeof(RollbackSpaceFirmware)); |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 113 | Memcpy(rsk, &rsk_init, sizeof(RollbackSpaceKernel)); |
Gaurav Shah | ce0cc30 | 2010-03-24 13:48:55 -0700 | [diff] [blame] | 114 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 115 | /* Define and set firmware and kernel spaces */ |
| 116 | RETURN_ON_FAILURE(SafeDefineSpace(FIRMWARE_NV_INDEX, |
| 117 | TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE, |
| 118 | sizeof(RollbackSpaceFirmware))); |
| 119 | RETURN_ON_FAILURE(WriteSpaceFirmware(rsf)); |
| 120 | RETURN_ON_FAILURE(SafeDefineSpace(KERNEL_NV_INDEX, TPM_NV_PER_PPWRITE, |
| 121 | sizeof(RollbackSpaceKernel))); |
| 122 | RETURN_ON_FAILURE(WriteSpaceKernel(rsk)); |
Luigi Semenzato | 59204c5 | 2010-06-09 13:37:15 -0700 | [diff] [blame] | 123 | return TPM_SUCCESS; |
Gaurav Shah | ce0cc30 | 2010-03-24 13:48:55 -0700 | [diff] [blame] | 124 | } |
| 125 | |
Luigi Semenzato | 2666f10 | 2010-06-15 08:12:32 -0700 | [diff] [blame] | 126 | |
Luigi Semenzato | 2b9ddae | 2010-06-28 13:34:31 -0700 | [diff] [blame] | 127 | /* SetupTPM starts the TPM and establishes the root of trust for the |
| 128 | * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a |
| 129 | * TPM hardware failure. 3 An unexpected TPM state due to some attack. In |
| 130 | * general we cannot easily distinguish the kind of failure, so our strategy is |
| 131 | * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM |
| 132 | * again, which executes (almost) the same sequence of operations. There is a |
| 133 | * good chance that, if recovery mode was entered because of a TPM failure, the |
| 134 | * failure will repeat itself. (In general this is impossible to guarantee |
| 135 | * because we have no way of creating the exact TPM initial state at the |
| 136 | * previous boot.) In recovery mode, we ignore the failure and continue, thus |
| 137 | * giving the recovery kernel a chance to fix things (that's why we don't set |
| 138 | * bGlobalLock). The choice is between a knowingly insecure device and a |
| 139 | * bricked device. |
| 140 | * |
| 141 | * As a side note, observe that we go through considerable hoops to avoid using |
| 142 | * the STCLEAR permissions for the index spaces. We do this to avoid writing |
| 143 | * to the TPM flashram at every reboot or wake-up, because of concerns about |
| 144 | * the durability of the NVRAM. |
| 145 | */ |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 146 | uint32_t SetupTPM(int recovery_mode, int developer_mode, |
| 147 | RollbackSpaceFirmware* rsf) { |
| 148 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 149 | int rsf_dirty = 0; |
| 150 | uint8_t new_flags = 0; |
Luigi Semenzato | 596b640 | 2010-05-27 14:04:52 -0700 | [diff] [blame] | 151 | uint8_t disable; |
| 152 | uint8_t deactivated; |
Luigi Semenzato | 416f681 | 2010-07-08 12:12:12 -0700 | [diff] [blame] | 153 | uint32_t result; |
Luigi Semenzato | 2b9ddae | 2010-06-28 13:34:31 -0700 | [diff] [blame] | 154 | |
Randall Spangler | 3e1081f | 2010-07-19 10:04:21 -0700 | [diff] [blame] | 155 | VBDEBUG(("TPM: SetupTPM(r%d, d%d)\n", recovery_mode, developer_mode)); |
| 156 | |
| 157 | /* TODO: TlclLibInit() should be able to return failure */ |
Luigi Semenzato | 59204c5 | 2010-06-09 13:37:15 -0700 | [diff] [blame] | 158 | TlclLibInit(); |
Randall Spangler | 3e1081f | 2010-07-19 10:04:21 -0700 | [diff] [blame] | 159 | |
Luigi Semenzato | 59204c5 | 2010-06-09 13:37:15 -0700 | [diff] [blame] | 160 | RETURN_ON_FAILURE(TlclStartup()); |
Randall Spangler | 3e1081f | 2010-07-19 10:04:21 -0700 | [diff] [blame] | 161 | #ifdef USE_CONTINUE_SELF_TEST |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 162 | /* TODO: ContinueSelfTest() should be faster than SelfTestFull, but |
| 163 | * may also not work properly in older TPM firmware. For now, do |
| 164 | * the full self test. */ |
Luigi Semenzato | 59204c5 | 2010-06-09 13:37:15 -0700 | [diff] [blame] | 165 | RETURN_ON_FAILURE(TlclContinueSelfTest()); |
Randall Spangler | 3e1081f | 2010-07-19 10:04:21 -0700 | [diff] [blame] | 166 | #else |
| 167 | RETURN_ON_FAILURE(TlclSelfTestFull()); |
| 168 | #endif |
Luigi Semenzato | 59204c5 | 2010-06-09 13:37:15 -0700 | [diff] [blame] | 169 | RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 170 | |
| 171 | /* Check that the TPM is enabled and activated. */ |
Randall Spangler | 3e1081f | 2010-07-19 10:04:21 -0700 | [diff] [blame] | 172 | RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated, NULL)); |
Luigi Semenzato | 596b640 | 2010-05-27 14:04:52 -0700 | [diff] [blame] | 173 | if (disable || deactivated) { |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 174 | VBDEBUG(("TPM: disabled (%d) or deactivated (%d). Fixing...\n", |
| 175 | disable, deactivated)); |
Luigi Semenzato | 59204c5 | 2010-06-09 13:37:15 -0700 | [diff] [blame] | 176 | RETURN_ON_FAILURE(TlclSetEnable()); |
| 177 | RETURN_ON_FAILURE(TlclSetDeactivated(0)); |
Randall Spangler | 3e1081f | 2010-07-19 10:04:21 -0700 | [diff] [blame] | 178 | VBDEBUG(("TPM: Must reboot to re-enable\n")); |
Luigi Semenzato | 2666f10 | 2010-06-15 08:12:32 -0700 | [diff] [blame] | 179 | return TPM_E_MUST_REBOOT; |
Luigi Semenzato | 596b640 | 2010-05-27 14:04:52 -0700 | [diff] [blame] | 180 | } |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 181 | |
| 182 | /* Read the firmware space. */ |
| 183 | result = ReadSpaceFirmware(rsf); |
| 184 | if (TPM_E_BADINDEX == result) { |
Randall Spangler | bb5d9f1 | 2010-08-16 15:36:07 -0700 | [diff] [blame^] | 185 | RollbackSpaceKernel rsk; |
| 186 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 187 | /* This is the first time we've run, and the TPM has not been |
| 188 | * initialized. Initialize it. */ |
| 189 | VBDEBUG(("TPM: Not initialized yet.\n")); |
| 190 | RETURN_ON_FAILURE(InitializeSpaces(rsf, &rsk)); |
| 191 | } else if (TPM_SUCCESS != result) { |
| 192 | VBDEBUG(("TPM: Firmware space in a bad state; giving up.\n")); |
| 193 | return TPM_E_CORRUPTED_STATE; |
| 194 | } |
| 195 | VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n", |
| 196 | rsf->struct_version, rsf->flags, rsf->fw_versions)); |
| 197 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 198 | /* Clear ownership if developer flag has toggled */ |
| 199 | if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) != |
| 200 | (rsf->flags & FLAG_LAST_BOOT_DEVELOPER)) { |
| 201 | VBDEBUG(("TPM: Developer flag changed; clearing owner.\n")); |
| 202 | RETURN_ON_FAILURE(TPMClearAndReenable()); |
Luigi Semenzato | 2666f10 | 2010-06-15 08:12:32 -0700 | [diff] [blame] | 203 | } |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 204 | |
| 205 | /* Update flags */ |
| 206 | if (developer_mode) |
| 207 | new_flags |= FLAG_LAST_BOOT_DEVELOPER; |
Randall Spangler | bb5d9f1 | 2010-08-16 15:36:07 -0700 | [diff] [blame^] | 208 | if (recovery_mode) |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 209 | g_rollback_recovery_mode = 1; /* Global variables are usable in |
| 210 | * recovery mode */ |
Randall Spangler | bb5d9f1 | 2010-08-16 15:36:07 -0700 | [diff] [blame^] | 211 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 212 | if (rsf->flags != new_flags) { |
| 213 | rsf->flags = new_flags; |
| 214 | rsf_dirty = 1; |
| 215 | } |
| 216 | |
| 217 | /* If firmware space is dirty, flush it back to the TPM */ |
| 218 | if (rsf_dirty) { |
| 219 | VBDEBUG(("TPM: Updating firmware space.\n")); |
| 220 | RETURN_ON_FAILURE(WriteSpaceFirmware(rsf)); |
| 221 | } |
| 222 | |
Randall Spangler | 3e1081f | 2010-07-19 10:04:21 -0700 | [diff] [blame] | 223 | VBDEBUG(("TPM: SetupTPM() succeeded\n")); |
Luigi Semenzato | 59204c5 | 2010-06-09 13:37:15 -0700 | [diff] [blame] | 224 | return TPM_SUCCESS; |
Gaurav Shah | ce0cc30 | 2010-03-24 13:48:55 -0700 | [diff] [blame] | 225 | } |
| 226 | |
vbendeb | 3ecaf77 | 2010-06-24 16:19:53 -0700 | [diff] [blame] | 227 | /* disable MSVC warnings on unused arguments */ |
| 228 | __pragma(warning (disable: 4100)) |
Randall Spangler | 1078838 | 2010-06-23 15:35:31 -0700 | [diff] [blame] | 229 | |
Randall Spangler | 39f6611 | 2010-07-14 09:10:23 -0700 | [diff] [blame] | 230 | |
| 231 | #ifdef DISABLE_ROLLBACK_TPM |
| 232 | |
Randall Spangler | ada3fa9 | 2010-07-20 15:35:49 -0700 | [diff] [blame] | 233 | /* Dummy implementations which don't support TPM rollback protection */ |
Randall Spangler | 39f6611 | 2010-07-14 09:10:23 -0700 | [diff] [blame] | 234 | |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 235 | uint32_t RollbackFirmwareSetup(int developer_mode, uint32_t* version) { |
Randall Spangler | ada3fa9 | 2010-07-20 15:35:49 -0700 | [diff] [blame] | 236 | #ifndef CHROMEOS_ENVIRONMENT |
| 237 | /* Initialize the TPM, but ignore return codes. In ChromeOS |
| 238 | * environment, don't even talk to the TPM. */ |
| 239 | TlclLibInit(); |
| 240 | TlclStartup(); |
Randall Spangler | 63dffcb | 2010-08-05 15:13:14 -0700 | [diff] [blame] | 241 | TlclSelfTestFull(); |
Randall Spangler | ada3fa9 | 2010-07-20 15:35:49 -0700 | [diff] [blame] | 242 | #endif |
Randall Spangler | 39f6611 | 2010-07-14 09:10:23 -0700 | [diff] [blame] | 243 | |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 244 | *version = 0; |
Randall Spangler | 39f6611 | 2010-07-14 09:10:23 -0700 | [diff] [blame] | 245 | return TPM_SUCCESS; |
| 246 | } |
| 247 | |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 248 | uint32_t RollbackFirmwareWrite(uint32_t version) { |
Randall Spangler | 39f6611 | 2010-07-14 09:10:23 -0700 | [diff] [blame] | 249 | return TPM_SUCCESS; |
| 250 | } |
| 251 | |
| 252 | uint32_t RollbackFirmwareLock(void) { |
| 253 | return TPM_SUCCESS; |
| 254 | } |
| 255 | |
| 256 | uint32_t RollbackKernelRecovery(int developer_mode) { |
Randall Spangler | ada3fa9 | 2010-07-20 15:35:49 -0700 | [diff] [blame] | 257 | #ifndef CHROMEOS_ENVIRONMENT |
| 258 | /* Initialize the TPM, but ignore return codes. In ChromeOS |
| 259 | * environment, don't even talk to the TPM. */ |
| 260 | TlclLibInit(); |
| 261 | TlclStartup(); |
Randall Spangler | 63dffcb | 2010-08-05 15:13:14 -0700 | [diff] [blame] | 262 | TlclSelfTestFull(); |
Randall Spangler | ada3fa9 | 2010-07-20 15:35:49 -0700 | [diff] [blame] | 263 | #endif |
Randall Spangler | 39f6611 | 2010-07-14 09:10:23 -0700 | [diff] [blame] | 264 | return TPM_SUCCESS; |
| 265 | } |
| 266 | |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 267 | uint32_t RollbackKernelRead(uint32_t* version) { |
| 268 | *version = 0; |
Randall Spangler | 39f6611 | 2010-07-14 09:10:23 -0700 | [diff] [blame] | 269 | return TPM_SUCCESS; |
| 270 | } |
| 271 | |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 272 | uint32_t RollbackKernelWrite(uint32_t version) { |
Randall Spangler | 39f6611 | 2010-07-14 09:10:23 -0700 | [diff] [blame] | 273 | return TPM_SUCCESS; |
| 274 | } |
| 275 | |
| 276 | uint32_t RollbackKernelLock(void) { |
| 277 | return TPM_SUCCESS; |
| 278 | } |
| 279 | |
| 280 | #else |
| 281 | |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 282 | uint32_t RollbackFirmwareSetup(int developer_mode, uint32_t* version) { |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 283 | RollbackSpaceFirmware rsf; |
Randall Spangler | 1078838 | 2010-06-23 15:35:31 -0700 | [diff] [blame] | 284 | |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 285 | RETURN_ON_FAILURE(SetupTPM(0, developer_mode, &rsf)); |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 286 | *version = rsf.fw_versions; |
Randall Spangler | bb5d9f1 | 2010-08-16 15:36:07 -0700 | [diff] [blame^] | 287 | VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)rsf.fw_versions)); |
Randall Spangler | 1078838 | 2010-06-23 15:35:31 -0700 | [diff] [blame] | 288 | return TPM_SUCCESS; |
| 289 | } |
| 290 | |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 291 | uint32_t RollbackFirmwareWrite(uint32_t version) { |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 292 | RollbackSpaceFirmware rsf; |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 293 | |
| 294 | RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf)); |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 295 | VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)rsf.fw_versions, |
| 296 | (int)version)); |
| 297 | rsf.fw_versions = version; |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 298 | return WriteSpaceFirmware(&rsf); |
Randall Spangler | 1078838 | 2010-06-23 15:35:31 -0700 | [diff] [blame] | 299 | } |
| 300 | |
| 301 | uint32_t RollbackFirmwareLock(void) { |
Luigi Semenzato | 2b9ddae | 2010-06-28 13:34:31 -0700 | [diff] [blame] | 302 | return TlclSetGlobalLock(); |
Randall Spangler | 1078838 | 2010-06-23 15:35:31 -0700 | [diff] [blame] | 303 | } |
| 304 | |
| 305 | uint32_t RollbackKernelRecovery(int developer_mode) { |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 306 | RollbackSpaceFirmware rsf; |
| 307 | uint32_t result = SetupTPM(1, developer_mode, &rsf); |
Luigi Semenzato | 5e9c0b9 | 2010-07-02 10:36:37 -0700 | [diff] [blame] | 308 | /* In recovery mode we ignore TPM malfunctions or corruptions, and leave the |
| 309 | * TPM completely unlocked if and only if the dev mode switch is ON. The |
| 310 | * recovery kernel will fix the TPM (if needed) and lock it ASAP. We leave |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 311 | * Physical Presence on in either case. */ |
Luigi Semenzato | 5e9c0b9 | 2010-07-02 10:36:37 -0700 | [diff] [blame] | 312 | if (!developer_mode) { |
Luigi Semenzato | 2b9ddae | 2010-06-28 13:34:31 -0700 | [diff] [blame] | 313 | RETURN_ON_FAILURE(TlclSetGlobalLock()); |
| 314 | } |
Luigi Semenzato | 416f681 | 2010-07-08 12:12:12 -0700 | [diff] [blame] | 315 | /* We still return the result of SetupTPM even though we expect the caller to |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 316 | * ignore it. It's useful in unit testing. */ |
Luigi Semenzato | 416f681 | 2010-07-08 12:12:12 -0700 | [diff] [blame] | 317 | return result; |
Randall Spangler | 1078838 | 2010-06-23 15:35:31 -0700 | [diff] [blame] | 318 | } |
| 319 | |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 320 | uint32_t RollbackKernelRead(uint32_t* version) { |
Luigi Semenzato | 2b9ddae | 2010-06-28 13:34:31 -0700 | [diff] [blame] | 321 | if (g_rollback_recovery_mode) { |
Luigi Semenzato | 2b9ddae | 2010-06-28 13:34:31 -0700 | [diff] [blame] | 322 | *version = 0; |
| 323 | } else { |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 324 | RollbackSpaceKernel rsk; |
Randall Spangler | bb5d9f1 | 2010-08-16 15:36:07 -0700 | [diff] [blame^] | 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). */ |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 333 | RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); |
Randall Spangler | bb5d9f1 | 2010-08-16 15:36:07 -0700 | [diff] [blame^] | 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 | |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 338 | *version = rsk.kernel_versions; |
| 339 | VBDEBUG(("TPM: RollbackKernelRead %x\n", (int)rsk.kernel_versions)); |
Luigi Semenzato | 2b9ddae | 2010-06-28 13:34:31 -0700 | [diff] [blame] | 340 | } |
Randall Spangler | 1078838 | 2010-06-23 15:35:31 -0700 | [diff] [blame] | 341 | return TPM_SUCCESS; |
| 342 | } |
| 343 | |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 344 | uint32_t RollbackKernelWrite(uint32_t version) { |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 345 | if (g_rollback_recovery_mode) { |
| 346 | return TPM_SUCCESS; |
| 347 | } else { |
| 348 | RollbackSpaceKernel rsk; |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 349 | RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); |
| 350 | VBDEBUG(("TPM: RollbackKernelWrite %x --> %x\n", (int)rsk.kernel_versions, |
Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 351 | (int)version)); |
| 352 | rsk.kernel_versions = version; |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 353 | return WriteSpaceKernel(&rsk); |
Luigi Semenzato | 2b9ddae | 2010-06-28 13:34:31 -0700 | [diff] [blame] | 354 | } |
Randall Spangler | 1078838 | 2010-06-23 15:35:31 -0700 | [diff] [blame] | 355 | } |
| 356 | |
| 357 | uint32_t RollbackKernelLock(void) { |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 358 | if (g_rollback_recovery_mode) { |
Luigi Semenzato | 2b9ddae | 2010-06-28 13:34:31 -0700 | [diff] [blame] | 359 | return TPM_SUCCESS; |
Randall Spangler | 4abede3 | 2010-08-12 16:40:32 -0700 | [diff] [blame] | 360 | } else { |
| 361 | return TlclLockPhysicalPresence(); |
Luigi Semenzato | 2b9ddae | 2010-06-28 13:34:31 -0700 | [diff] [blame] | 362 | } |
Randall Spangler | 1078838 | 2010-06-23 15:35:31 -0700 | [diff] [blame] | 363 | } |
Randall Spangler | 39f6611 | 2010-07-14 09:10:23 -0700 | [diff] [blame] | 364 | |
| 365 | #endif // DISABLE_ROLLBACK_TPM |