Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Side by Side Diff: src/platform/vboot_reference/vboot_firmware/lib/rollback_index.c

Issue 2344002: Add recovery mode protection to new NVRAM locking scheme. (Closed) Base URL: ssh://git@chromiumos-git/chromeos
Patch Set: typo in comment Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698