| 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 <stdint.h> | 11 #include <stdint.h> |
| 12 | 12 |
| 13 #include "utility.h" | 13 #include "utility.h" |
| 14 #include "tlcl.h" | 14 #include "tlcl.h" |
| 15 #include "tss_constants.h" | 15 #include "tss_constants.h" |
| 16 | 16 |
| 17 uint16_t g_firmware_key_version = 0; | 17 uint16_t g_firmware_key_version = 0; |
| 18 uint16_t g_firmware_version = 0; | 18 uint16_t g_firmware_version = 0; |
| 19 uint16_t g_kernel_key_version = 0; | 19 uint16_t g_kernel_key_version = 0; |
| 20 uint16_t g_kernel_version = 0; | 20 uint16_t g_kernel_version = 0; |
| 21 | 21 |
| 22 static void InitializeSpaces(void) { | 22 static int InitializeSpaces(void) { |
| 23 uint16_t zero = 0; | 23 uint32_t zero = 0; |
| 24 uint32_t space_holder; |
| 24 uint32_t firmware_perm = TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE; | 25 uint32_t firmware_perm = TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE; |
| 25 uint32_t kernel_perm = TPM_NV_PER_PPWRITE; | 26 uint32_t kernel_perm = TPM_NV_PER_PPWRITE; |
| 26 | 27 |
| 27 debug("Initializing spaces\n"); | 28 debug("Initializing spaces\n"); |
| 28 TlclSetNvLocked(); /* useful only the first time */ | |
| 29 | 29 |
| 30 TlclDefineSpace(FIRMWARE_KEY_VERSION_NV_INDEX, | 30 if (TlclRead(TPM_IS_INITIALIZED_NV_INDEX, |
| 31 firmware_perm, sizeof(uint16_t)); | 31 (uint8_t*) &space_holder, sizeof(space_holder)) == TPM_SUCCESS) { |
| 32 TlclWrite(FIRMWARE_KEY_VERSION_NV_INDEX, (uint8_t*) &zero, sizeof(uint16_t)); | 32 /* Spaces are already initialized, so this is an error */ |
| 33 return 0; |
| 34 } |
| 35 |
| 36 TlclSetNvLocked(); |
| 33 | 37 |
| 34 TlclDefineSpace(FIRMWARE_VERSION_NV_INDEX, firmware_perm, sizeof(uint16_t)); | 38 TlclDefineSpace(FIRMWARE_VERSIONS_NV_INDEX, firmware_perm, sizeof(uint32_t)); |
| 35 TlclWrite(FIRMWARE_VERSION_NV_INDEX, (uint8_t*) &zero, sizeof(uint16_t)); | 39 TlclWrite(FIRMWARE_VERSIONS_NV_INDEX, (uint8_t*) &zero, sizeof(uint32_t)); |
| 36 | 40 |
| 37 TlclDefineSpace(KERNEL_KEY_VERSION_NV_INDEX, kernel_perm, sizeof(uint16_t)); | 41 TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX, kernel_perm, sizeof(uint32_t)); |
| 38 TlclWrite(KERNEL_KEY_VERSION_NV_INDEX, (uint8_t*) &zero, sizeof(uint16_t)); | 42 TlclWrite(KERNEL_VERSIONS_NV_INDEX, (uint8_t*) &zero, sizeof(uint32_t)); |
| 39 | 43 |
| 40 TlclDefineSpace(KERNEL_VERSION_NV_INDEX, kernel_perm, sizeof(uint16_t)); | 44 /* The space KERNEL_VERSIONS_BACKUP_NV_INDEX is used to protect the kernel |
| 41 TlclWrite(KERNEL_VERSION_NV_INDEX, (uint8_t*) &zero, sizeof(uint16_t)); | 45 * versions when entering recovery mode. The content of space |
| 46 * KERNEL_BACKUP_IS_VALID determines whether the backup value (1) or the |
| 47 * regular value (0) should be trusted. |
| 48 */ |
| 49 TlclDefineSpace(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
| 50 firmware_perm, sizeof(uint32_t)); |
| 51 TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
| 52 (uint8_t*) &zero, sizeof(uint32_t)); |
| 53 TlclDefineSpace(KERNEL_BACKUP_IS_VALID_NV_INDEX, |
| 54 firmware_perm, sizeof(uint32_t)); |
| 55 TlclWrite(KERNEL_BACKUP_IS_VALID_NV_INDEX, |
| 56 (uint8_t*) &zero, sizeof(uint32_t)); |
| 57 |
| 58 /* The space TPM_IS_INITIALIZED_NV_INDEX is used to indicate that the TPM |
| 59 * initialization has completed. Without it we cannot be sure that the last |
| 60 * space to be created was also initialized (power could have been lost right |
| 61 * after its creation). |
| 62 */ |
| 63 TlclDefineSpace(TPM_IS_INITIALIZED_NV_INDEX, firmware_perm, sizeof(uint32_t)); |
| 64 return 1; |
| 42 } | 65 } |
| 43 | 66 |
| 44 static void EnterRecovery(void) { | 67 /* Enters the recovery mode. If |unlocked| is true, there is some problem with |
| 45 /* Temporary recovery stub. Currently just initalizes spaces. */ | 68 * the TPM, so do not attempt to do any more TPM operations, and particularly |
| 46 InitializeSpaces(); | 69 * do not set bGlobalLock. |
| 70 */ |
| 71 static void EnterRecovery(int unlocked) { |
| 72 uint32_t combined_versions; |
| 73 uint32_t one = 1; |
| 74 |
| 75 if (!unlocked) { |
| 76 /* Saves the kernel versions and indicates that we should trust the saved |
| 77 * ones. |
| 78 */ |
| 79 TlclRead(KERNEL_VERSIONS_NV_INDEX, (uint8_t*) &combined_versions, |
| 80 sizeof(uint32_t)); |
| 81 TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, (uint8_t*) &combined_versions, |
| 82 sizeof(uint32_t)); |
| 83 TlclWrite(KERNEL_BACKUP_IS_VALID_NV_INDEX, (uint8_t*) &one, |
| 84 sizeof(uint32_t)); |
| 85 /* Protects the firmware and backup kernel versions. */ |
| 86 LockFirmwareVersions(); |
| 87 } |
| 88 debug("entering recovery mode"); |
| 89 |
| 90 /* and then what? */ |
| 47 } | 91 } |
| 48 | 92 |
| 49 static int GetTPMRollbackIndices(void) { | 93 static int GetTPMRollbackIndices(void) { |
| 50 /* We just perform the reads, making sure they succeed. A failure means that | 94 uint32_t backup_is_valid; |
| 51 * the rollback index locations are some how messed up and we must jump to | 95 uint32_t firmware_versions; |
| 52 * recovery */ | 96 uint32_t kernel_versions; |
| 53 if (TPM_SUCCESS != TlclRead(FIRMWARE_KEY_VERSION_NV_INDEX, | 97 |
| 54 (uint8_t*) &g_firmware_key_version, | 98 if (TlclRead(KERNEL_BACKUP_IS_VALID_NV_INDEX, (uint8_t*) &backup_is_valid, |
| 55 sizeof(g_firmware_key_version)) || | 99 sizeof(uint32_t)) != TPM_SUCCESS) { |
| 56 TPM_SUCCESS != TlclRead(FIRMWARE_KEY_VERSION_NV_INDEX, | 100 EnterRecovery(1); |
| 57 (uint8_t*) &g_firmware_key_version, | 101 } |
| 58 sizeof(g_firmware_key_version)) || | 102 if (backup_is_valid) { |
| 59 TPM_SUCCESS != TlclRead(FIRMWARE_KEY_VERSION_NV_INDEX, | 103 /* We reach this path if the previous boot went into recovery mode and we |
| 60 (uint8_t*) &g_firmware_key_version, | 104 * made a copy of the kernel versions to protect them. |
| 61 sizeof(g_firmware_key_version)) || | 105 */ |
| 62 TPM_SUCCESS != TlclRead(FIRMWARE_KEY_VERSION_NV_INDEX, | 106 uint32_t protected_combined_versions; |
| 63 (uint8_t*) &g_firmware_key_version, | 107 uint32_t unsafe_combined_versions; |
| 64 sizeof(g_firmware_key_version))) | 108 uint32_t result; |
| 109 uint32_t zero = 0; |
| 110 if (TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, |
| 111 (uint8_t*) &protected_combined_versions, |
| 112 sizeof(uint32_t)) != TPM_SUCCESS) { |
| 113 EnterRecovery(1); |
| 114 } |
| 115 result = TlclRead(KERNEL_VERSIONS_NV_INDEX, |
| 116 (uint8_t*) &unsafe_combined_versions, sizeof(uint32_t)); |
| 117 if (result == TPM_E_BADINDEX) { |
| 118 /* Jeez, someone removed the space. This is either hostile or extremely |
| 119 * incompetent. Foo to them. Politeness and lack of an adequate |
| 120 * character set prevent me from expressing my true feelings. |
| 121 */ |
| 122 TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX, TPM_NV_PER_PPWRITE, |
| 123 sizeof(uint32_t)); |
| 124 } else if (result != TPM_SUCCESS) { |
| 125 EnterRecovery(1); |
| 126 } |
| 127 if (result == TPM_E_BADINDEX || |
| 128 protected_combined_versions != unsafe_combined_versions) { |
| 129 TlclWrite(KERNEL_VERSIONS_NV_INDEX, |
| 130 (uint8_t*) &protected_combined_versions, sizeof(uint32_t)); |
| 131 } |
| 132 /* We recovered and now we can reset the BACKUP_IS_VALID flag. |
| 133 */ |
| 134 TlclWrite(KERNEL_BACKUP_IS_VALID_NV_INDEX, (uint8_t*) &zero, 0); |
| 135 } |
| 136 |
| 137 /* We perform the reads, making sure they succeed. A failure means that the |
| 138 * rollback index locations are missing or somehow messed up. We let the |
| 139 * caller deal with that. |
| 140 */ |
| 141 if (TPM_SUCCESS != TlclRead(FIRMWARE_VERSIONS_NV_INDEX, |
| 142 (uint8_t*) &firmware_versions, |
| 143 sizeof(firmware_versions)) || |
| 144 TPM_SUCCESS != TlclRead(KERNEL_VERSIONS_NV_INDEX, |
| 145 (uint8_t*) &kernel_versions, |
| 146 sizeof(kernel_versions))) |
| 65 return 0; | 147 return 0; |
| 148 |
| 149 g_firmware_key_version = firmware_versions >> 16; |
| 150 g_firmware_version = firmware_versions && 0xffff; |
| 151 g_kernel_key_version = kernel_versions >> 16; |
| 152 g_kernel_version = kernel_versions && 0xffff; |
| 153 |
| 66 return 1; | 154 return 1; |
| 67 } | 155 } |
| 68 | 156 |
| 69 | 157 |
| 70 void SetupTPM(void) { | 158 void SetupTPM(void) { |
| 71 uint8_t disable; | 159 uint8_t disable; |
| 72 uint8_t deactivated; | 160 uint8_t deactivated; |
| 73 TlclLibinit(); | 161 TlclLibinit(); |
| 74 TlclStartup(); | 162 TlclStartup(); |
| 75 /* TODO(gauravsh): The call to self test should probably be deferred. | 163 /* TODO(gauravsh): The call to self test should probably be deferred. |
| 76 * As per semenzato@chromium.org - | 164 * As per semenzato@chromium.org - |
| 77 * TlclStartup should be called before the firmware initializes the memory | 165 * TlclStartup should be called before the firmware initializes the memory |
| 78 * controller, so the selftest can run in parallel with that. Here we should | 166 * controller, so the selftest can run in parallel with that. Here we should |
| 79 * just call TlclSelftestFull to make sure the self test has | 167 * just call TlclSelftestFull to make sure the self test has |
| 80 * completed---unless we want to rely on the NVRAM operations being available | 168 * completed---unless we want to rely on the NVRAM operations being available |
| 81 * before the selftest completes. */ | 169 * before the selftest completes. */ |
| 82 TlclSelftestfull(); | 170 TlclSelftestfull(); |
| 83 TlclAssertPhysicalPresence(); | 171 TlclAssertPhysicalPresence(); |
| 84 /* Check that the TPM is enabled and activated. */ | 172 /* Check that the TPM is enabled and activated. */ |
| 85 if(TlclGetFlags(&disable, &deactivated) != TPM_SUCCESS) { | 173 if(TlclGetFlags(&disable, &deactivated) != TPM_SUCCESS) { |
| 86 debug("failed to get TPM flags"); | 174 debug("failed to get TPM flags"); |
| 87 EnterRecovery(); | 175 EnterRecovery(1); |
| 88 } | 176 } |
| 89 if (disable || deactivated) { | 177 if (disable || deactivated) { |
| 90 TlclSetEnable(); | 178 TlclSetEnable(); |
| 91 if (TlclSetDeactivated(0) != TPM_SUCCESS) { | 179 if (TlclSetDeactivated(0) != TPM_SUCCESS) { |
| 92 debug("failed to activate TPM"); | 180 debug("failed to activate TPM"); |
| 93 EnterRecovery(); | 181 EnterRecovery(1); |
| 94 } | 182 } |
| 95 } | 183 } |
| 184 /* We expect this to fail the first time we run on a device, indicating that |
| 185 * the TPM has not been initialized yet. */ |
| 96 if (!GetTPMRollbackIndices()) { | 186 if (!GetTPMRollbackIndices()) { |
| 97 debug("failed to get rollback indices"); | 187 debug("failed to get rollback indices"); |
| 98 EnterRecovery(); | 188 if (!InitializeSpaces()) { |
| 189 /* If InitializeSpaces() fails (possibly because it had been executed |
| 190 * already), something is wrong. */ |
| 191 EnterRecovery(1); |
| 192 } |
| 99 } | 193 } |
| 100 } | 194 } |
| 101 | 195 |
| 196 void GetStoredVersions(int type, uint16_t* key_version, uint16_t* version) { |
| 197 switch (type) { |
| 198 case FIRMWARE_VERSIONS: |
| 199 *key_version = g_firmware_key_version; |
| 200 *version = g_firmware_version; |
| 201 break; |
| 202 case KERNEL_VERSIONS: |
| 203 *key_version = g_kernel_key_version; |
| 204 *version = g_kernel_version; |
| 205 break; |
| 206 } |
| 207 } |
| 102 | 208 |
| 103 uint16_t GetStoredVersion(int type) { | 209 int WriteStoredVersions(int type, uint16_t key_version, uint16_t version) { |
| 210 uint32_t combined_version = (key_version << 16) & version; |
| 104 switch (type) { | 211 switch (type) { |
| 105 case FIRMWARE_KEY_VERSION: | 212 case FIRMWARE_VERSIONS: |
| 106 return g_firmware_key_version; | 213 return (TPM_SUCCESS == TlclWrite(FIRMWARE_VERSIONS_NV_INDEX, |
| 214 (uint8_t*) &combined_version, |
| 215 sizeof(uint32_t))); |
| 107 break; | 216 break; |
| 108 case FIRMWARE_VERSION: | 217 case KERNEL_VERSIONS: |
| 109 return g_firmware_version; | 218 return (TPM_SUCCESS == TlclWrite(KERNEL_VERSIONS_NV_INDEX, |
| 110 break; | 219 (uint8_t*) &combined_version, |
| 111 case KERNEL_KEY_VERSION: | 220 sizeof(uint32_t))); |
| 112 return g_kernel_key_version; | |
| 113 break; | |
| 114 case KERNEL_VERSION: | |
| 115 return g_kernel_version; | |
| 116 break; | 221 break; |
| 117 } | 222 } |
| 118 return 0; | 223 return 0; |
| 119 } | |
| 120 | |
| 121 int WriteStoredVersion(int type, uint16_t version) { | |
| 122 switch (type) { | |
| 123 case FIRMWARE_KEY_VERSION: | |
| 124 return (TPM_SUCCESS == TlclWrite(FIRMWARE_KEY_VERSION_NV_INDEX, | |
| 125 (uint8_t*) &version, | |
| 126 sizeof(uint16_t))); | |
| 127 break; | |
| 128 case FIRMWARE_VERSION: | |
| 129 return (TPM_SUCCESS == TlclWrite(FIRMWARE_VERSION_NV_INDEX, | |
| 130 (uint8_t*) &version, | |
| 131 sizeof(uint16_t))); | |
| 132 break; | |
| 133 case KERNEL_KEY_VERSION: | |
| 134 return (TPM_SUCCESS == TlclWrite(KERNEL_KEY_VERSION_NV_INDEX, | |
| 135 (uint8_t*) &version, | |
| 136 sizeof(uint16_t))); | |
| 137 break; | |
| 138 case KERNEL_VERSION: | |
| 139 return (TPM_SUCCESS == TlclWrite(KERNEL_VERSION_NV_INDEX, | |
| 140 (uint8_t*) &version, | |
| 141 sizeof(uint16_t))); | |
| 142 break; | |
| 143 } | |
| 144 return 0; | |
| 145 } | 224 } |
| 146 | 225 |
| 147 void LockFirmwareVersions() { | 226 void LockFirmwareVersions() { |
| 148 if (TlclSetGlobalLock() != TPM_SUCCESS) { | 227 if (TlclSetGlobalLock() != TPM_SUCCESS) { |
| 149 debug("failed to set global lock"); | 228 debug("failed to set global lock"); |
| 150 EnterRecovery(); | 229 EnterRecovery(1); |
| 151 } | 230 } |
| 152 } | 231 } |
| 153 | 232 |
| 154 void LockKernelVersionsByLockingPP() { | 233 void LockKernelVersionsByLockingPP() { |
| 155 if (TlclLockPhysicalPresence() != TPM_SUCCESS) { | 234 if (TlclLockPhysicalPresence() != TPM_SUCCESS) { |
| 156 debug("failed to turn off PP"); | 235 debug("failed to turn off PP"); |
| 157 EnterRecovery(); | 236 EnterRecovery(1); |
| 158 } | 237 } |
| 159 } | 238 } |
| OLD | NEW |