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

Side by Side Diff: firmware/lib/rollback_index.c

Issue 2869022: New rollback_index API. (Closed) Base URL: ssh://git@chromiumos-git/vboot_reference.git
Patch Set: small API change Created 10 years, 5 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
« no previous file with comments | « firmware/lib/include/rollback_index.h ('k') | firmware/lib/vboot_firmware.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "tlcl.h" 11 #include "tlcl.h"
12 #include "tss_constants.h" 12 #include "tss_constants.h"
13 #include "utility.h" 13 #include "utility.h"
14 14
15 uint16_t g_firmware_key_version = 0; 15 static int g_rollback_recovery_mode = 0;
16 uint16_t g_firmware_version = 0;
17 uint16_t g_kernel_key_version = 0;
18 uint16_t g_kernel_version = 0;
19 16
20 /* disable MSVC warning on const logical expression (as in } while(0);) */ 17 /* disable MSVC warning on const logical expression (as in } while(0);) */
21 __pragma(warning (disable: 4127)) 18 __pragma(warning (disable: 4127))
22 19
23 #define RETURN_ON_FAILURE(tpm_command) do { \ 20 #define RETURN_ON_FAILURE(tpm_command) do { \
24 uint32_t result; \ 21 uint32_t result; \
25 if ((result = (tpm_command)) != TPM_SUCCESS) { \ 22 if ((result = (tpm_command)) != TPM_SUCCESS) { \
26 return result; \ 23 return result; \
27 } \ 24 } \
28 } while (0) 25 } while (0)
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 uint32_t must_use_backup; 123 uint32_t must_use_backup;
127 RETURN_ON_FAILURE(TlclRead(KERNEL_MUST_USE_BACKUP_NV_INDEX, 124 RETURN_ON_FAILURE(TlclRead(KERNEL_MUST_USE_BACKUP_NV_INDEX,
128 (uint8_t*) &must_use_backup, sizeof(uint32_t))); 125 (uint8_t*) &must_use_backup, sizeof(uint32_t)));
129 if (must_use_backup != distrust) { 126 if (must_use_backup != distrust) {
130 RETURN_ON_FAILURE(SafeWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, 127 RETURN_ON_FAILURE(SafeWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX,
131 (uint8_t*) &distrust, sizeof(uint32_t))); 128 (uint8_t*) &distrust, sizeof(uint32_t)));
132 } 129 }
133 return TPM_SUCCESS; 130 return TPM_SUCCESS;
134 } 131 }
135 132
136 static uint32_t GetTPMRollbackIndices(int type) {
137 uint32_t firmware_versions;
138 uint32_t kernel_versions;
139
140 /* We perform the reads, making sure they succeed. A failure means that the
141 * rollback index locations are missing or somehow messed up. We let the
142 * caller deal with that.
143 */
144 switch (type) {
145 case FIRMWARE_VERSIONS:
146 RETURN_ON_FAILURE(TlclRead(FIRMWARE_VERSIONS_NV_INDEX,
147 (uint8_t*) &firmware_versions,
148 sizeof(firmware_versions)));
149 g_firmware_key_version = (uint16_t) (firmware_versions >> 16);
150 g_firmware_version = (uint16_t) (firmware_versions & 0xffff);
151 break;
152 case KERNEL_VERSIONS:
153 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX,
154 (uint8_t*) &kernel_versions,
155 sizeof(kernel_versions)));
156 g_kernel_key_version = (uint16_t) (kernel_versions >> 16);
157 g_kernel_version = (uint16_t) (kernel_versions & 0xffff);
158 break;
159 }
160
161 return TPM_SUCCESS;
162 }
163
164 /* Checks if the kernel version space has been mucked with. If it has, 133 /* Checks if the kernel version space has been mucked with. If it has,
165 * reconstructs it using the backup value. 134 * reconstructs it using the backup value.
166 */ 135 */
167 uint32_t RecoverKernelSpace(void) { 136 uint32_t RecoverKernelSpace(void) {
168 uint32_t perms = 0; 137 uint32_t perms = 0;
169 uint8_t buffer[KERNEL_SPACE_SIZE]; 138 uint8_t buffer[KERNEL_SPACE_SIZE];
170 int read_OK = 0; 139 int read_OK = 0;
171 int perms_OK = 0; 140 int perms_OK = 0;
172 uint32_t backup_combined_versions; 141 uint32_t backup_combined_versions;
173 uint32_t must_use_backup; 142 uint32_t must_use_backup;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 sizeof(past_developer))); 206 sizeof(past_developer)));
238 if (past_developer != current_developer) { 207 if (past_developer != current_developer) {
239 RETURN_ON_FAILURE(TPMClearAndReenable()); 208 RETURN_ON_FAILURE(TPMClearAndReenable());
240 RETURN_ON_FAILURE(SafeWrite(DEVELOPER_MODE_NV_INDEX, 209 RETURN_ON_FAILURE(SafeWrite(DEVELOPER_MODE_NV_INDEX,
241 (uint8_t*) &current_developer, 210 (uint8_t*) &current_developer,
242 sizeof(current_developer))); 211 sizeof(current_developer)));
243 } 212 }
244 return TPM_SUCCESS; 213 return TPM_SUCCESS;
245 } 214 }
246 215
247 static uint32_t SetupTPM_(int mode, int developer_flag) { 216 /* SetupTPM starts the TPM and establishes the root of trust for the
217 * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a
218 * TPM hardware failure. 3 An unexpected TPM state due to some attack. In
219 * general we cannot easily distinguish the kind of failure, so our strategy is
220 * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM
221 * again, which executes (almost) the same sequence of operations. There is a
222 * good chance that, if recovery mode was entered because of a TPM failure, the
223 * failure will repeat itself. (In general this is impossible to guarantee
224 * because we have no way of creating the exact TPM initial state at the
225 * previous boot.) In recovery mode, we ignore the failure and continue, thus
226 * giving the recovery kernel a chance to fix things (that's why we don't set
227 * bGlobalLock). The choice is between a knowingly insecure device and a
228 * bricked device.
229 *
230 * As a side note, observe that we go through considerable hoops to avoid using
231 * the STCLEAR permissions for the index spaces. We do this to avoid writing
232 * to the TPM flashram at every reboot or wake-up, because of concerns about
233 * the durability of the NVRAM.
234 */
235 static uint32_t SetupTPM(int recovery_mode,
236 int developer_mode) {
248 uint8_t disable; 237 uint8_t disable;
249 uint8_t deactivated; 238 uint8_t deactivated;
239
250 TlclLibInit(); 240 TlclLibInit();
251 RETURN_ON_FAILURE(TlclStartup()); 241 RETURN_ON_FAILURE(TlclStartup());
252 RETURN_ON_FAILURE(TlclContinueSelfTest()); 242 RETURN_ON_FAILURE(TlclContinueSelfTest());
253 RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); 243 RETURN_ON_FAILURE(TlclAssertPhysicalPresence());
254 /* Checks that the TPM is enabled and activated. */ 244 /* Checks that the TPM is enabled and activated. */
255 RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated)); 245 RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated));
256 if (disable || deactivated) { 246 if (disable || deactivated) {
257 RETURN_ON_FAILURE(TlclSetEnable()); 247 RETURN_ON_FAILURE(TlclSetEnable());
258 RETURN_ON_FAILURE(TlclSetDeactivated(0)); 248 RETURN_ON_FAILURE(TlclSetDeactivated(0));
259 return TPM_E_MUST_REBOOT; 249 return TPM_E_MUST_REBOOT;
260 } 250 }
261 /* We expect this to fail the first time we run on a device, because the TPM 251 /* We expect this to fail the first time we run on a device, because the TPM
262 * has not been initialized yet. 252 * has not been initialized yet.
263 */ 253 */
264 if (RecoverKernelSpace() != TPM_SUCCESS) { 254 if (RecoverKernelSpace() != TPM_SUCCESS) {
265 int initialized = 0; 255 int initialized = 0;
266 RETURN_ON_FAILURE(GetSpacesInitialized(&initialized)); 256 RETURN_ON_FAILURE(GetSpacesInitialized(&initialized));
267 if (initialized) { 257 if (initialized) {
268 return TPM_E_ALREADY_INITIALIZED; 258 return TPM_E_ALREADY_INITIALIZED;
269 } else { 259 } else {
270 RETURN_ON_FAILURE(InitializeSpaces()); 260 RETURN_ON_FAILURE(InitializeSpaces());
271 RETURN_ON_FAILURE(RecoverKernelSpace()); 261 RETURN_ON_FAILURE(RecoverKernelSpace());
272 } 262 }
273 } 263 }
274 RETURN_ON_FAILURE(BackupKernelSpace()); 264 RETURN_ON_FAILURE(BackupKernelSpace());
275 RETURN_ON_FAILURE(SetDistrustKernelSpaceAtNextBoot(mode == RO_RECOVERY_MODE)); 265 RETURN_ON_FAILURE(SetDistrustKernelSpaceAtNextBoot(recovery_mode));
276 RETURN_ON_FAILURE(GetTPMRollbackIndices(FIRMWARE_VERSIONS)); 266 RETURN_ON_FAILURE(CheckDeveloperModeTransition(developer_mode));
277 RETURN_ON_FAILURE(GetTPMRollbackIndices(KERNEL_VERSIONS));
278 267
279 RETURN_ON_FAILURE(CheckDeveloperModeTransition(developer_flag)); 268 if (recovery_mode) {
280 269 /* In recovery mode global variables are usable. */
281 /* As a courtesy (I hope) to the caller, lock the firmware versions if we are 270 g_rollback_recovery_mode = 1;
282 * in recovery mode. The normal mode may need to update the firmware
283 * versions, so they cannot be locked here.
284 */
285 if (mode == RO_RECOVERY_MODE) {
286 RETURN_ON_FAILURE(LockFirmwareVersions());
287 } 271 }
288 return TPM_SUCCESS; 272 return TPM_SUCCESS;
289 } 273 }
290 274
291 /* SetupTPM starts the TPM and establishes the root of trust for the
292 * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a
293 * TPM hardware failure. 3 An unexpected TPM state due to some attack. In
294 * general we cannot easily distinguish the kind of failure, so our strategy is
295 * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM
296 * again, which executes (almost) the same sequence of operations. There is a
297 * good chance that, if recovery mode was entered because of a TPM failure, the
298 * failure will repeat itself. (In general this is impossible to guarantee
299 * because we have no way of creating the exact TPM initial state at the
300 * previous boot.) In recovery mode, we ignore the failure and continue, thus
301 * giving the recovery kernel a chance to fix things (that's why we don't set
302 * bGlobalLock). The choice is between a knowingly insecure device and a
303 * bricked device.
304 *
305 * As a side note, observe that we go through considerable hoops to avoid using
306 * the STCLEAR permissions for the index spaces. We do this to avoid writing
307 * to the TPM flashram at every reboot or wake-up, because of concerns about
308 * the durability of the NVRAM.
309 */
310 uint32_t SetupTPM(int mode, int developer_flag) {
311 switch (mode) {
312 case RO_RECOVERY_MODE:
313 case RO_NORMAL_MODE: {
314 uint32_t result = SetupTPM_(mode, developer_flag);
315 if (mode == RO_NORMAL_MODE) {
316 return result;
317 } else {
318 /* In recovery mode we want to keep going even if there are errors. */
319 return TPM_SUCCESS;
320 }
321 }
322 case RW_NORMAL_MODE:
323 RETURN_ON_FAILURE(GetTPMRollbackIndices(KERNEL_VERSIONS));
324 default:
325 return TPM_E_INTERNAL_INCONSISTENCY;
326 }
327 }
328
329 uint32_t GetStoredVersions(int type, uint16_t* key_version, uint16_t* version) {
330 /* TODO: should verify that SetupTPM() has been called.
331 *
332 * Note that SetupTPM() does hardware setup AND sets global variables. When
333 * we get down into kernel verification, the hardware setup persists, but we
334 * lose the global variables.
335 */
336 switch (type) {
337 case FIRMWARE_VERSIONS:
338 *key_version = g_firmware_key_version;
339 *version = g_firmware_version;
340 break;
341 case KERNEL_VERSIONS:
342 *key_version = g_kernel_key_version;
343 *version = g_kernel_version;
344 break;
345 }
346
347 return TPM_SUCCESS;
348 }
349
350 uint32_t WriteStoredVersions(int type, uint16_t key_version, uint16_t version) {
351 uint32_t combined_version = (key_version << 16) & version;
352 switch (type) {
353 case FIRMWARE_VERSIONS:
354 RETURN_ON_FAILURE(SafeWrite(FIRMWARE_VERSIONS_NV_INDEX,
355 (uint8_t*) &combined_version,
356 sizeof(uint32_t)));
357 break;
358
359 case KERNEL_VERSIONS:
360 RETURN_ON_FAILURE(SafeWrite(KERNEL_VERSIONS_NV_INDEX,
361 (uint8_t*) &combined_version,
362 sizeof(uint32_t)));
363 }
364 return TPM_SUCCESS;
365 }
366
367 uint32_t LockFirmwareVersions() {
368 return TlclSetGlobalLock();
369 }
370
371 uint32_t LockKernelVersionsByLockingPP() {
372 return TlclLockPhysicalPresence();
373 }
374
375 /* disable MSVC warnings on unused arguments */ 275 /* disable MSVC warnings on unused arguments */
376 __pragma(warning (disable: 4100)) 276 __pragma(warning (disable: 4100))
377 277
378 /* NEW APIS! HELP ME LUIGI, YOU'RE MY ONLY HOPE! */ 278 uint32_t RollbackFirmwareSetup(int developer_mode) {
279 return SetupTPM(0, developer_mode);
280 }
379 281
380 uint32_t RollbackFirmwareSetup(int developer_mode, 282 uint32_t RollbackFirmwareRead(uint16_t* key_version, uint16_t* version) {
381 uint16_t* key_version, uint16_t* version) { 283 uint32_t firmware_versions;
284 /* Gets firmware versions. */
285 RETURN_ON_FAILURE(TlclRead(FIRMWARE_VERSIONS_NV_INDEX,
286 (uint8_t*) &firmware_versions,
287 sizeof(firmware_versions)));
288 *key_version = (uint16_t) (firmware_versions >> 16);
289 *version = (uint16_t) (firmware_versions & 0xffff);
382 return TPM_SUCCESS; 290 return TPM_SUCCESS;
383 } 291 }
384 292
385 uint32_t RollbackFirmwareWrite(uint16_t key_version, uint16_t version) { 293 uint32_t RollbackFirmwareWrite(uint16_t key_version, uint16_t version) {
386 return TPM_SUCCESS; 294 uint32_t combined_version = (key_version << 16) & version;
295 return SafeWrite(FIRMWARE_VERSIONS_NV_INDEX,
296 (uint8_t*) &combined_version,
297 sizeof(uint32_t));
387 } 298 }
388 299
389 uint32_t RollbackFirmwareLock(void) { 300 uint32_t RollbackFirmwareLock(void) {
390 return TPM_SUCCESS; 301 return TlclSetGlobalLock();
391 } 302 }
392 303
393 uint32_t RollbackKernelRecovery(int developer_mode) { 304 uint32_t RollbackKernelRecovery(int developer_mode) {
305 uint32_t result = SetupTPM(1, developer_mode);
306 if (result == TPM_SUCCESS) {
307 RETURN_ON_FAILURE(TlclSetGlobalLock());
308 }
394 return TPM_SUCCESS; 309 return TPM_SUCCESS;
395 } 310 }
396 311
397 uint32_t RollbackKernelRead(uint16_t* key_version, uint16_t* version) { 312 uint32_t RollbackKernelRead(uint16_t* key_version, uint16_t* version) {
313 uint32_t kernel_versions;
314 if (g_rollback_recovery_mode) {
315 *key_version = 0;
316 *version = 0;
317 } else {
318 /* Reads kernel versions from TPM. */
319 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX,
320 (uint8_t*) &kernel_versions,
321 sizeof(kernel_versions)));
322 *key_version = (uint16_t) (kernel_versions >> 16);
323 *version = (uint16_t) (kernel_versions & 0xffff);
324 }
398 return TPM_SUCCESS; 325 return TPM_SUCCESS;
399 } 326 }
400 327
401 uint32_t RollbackKernelWrite(uint16_t key_version, uint16_t version) { 328 uint32_t RollbackKernelWrite(uint16_t key_version, uint16_t version) {
329 if (!g_rollback_recovery_mode) {
330 uint32_t combined_version = (key_version << 16) & version;
331 return SafeWrite(KERNEL_VERSIONS_NV_INDEX,
332 (uint8_t*) &combined_version,
333 sizeof(uint32_t));
334 }
402 return TPM_SUCCESS; 335 return TPM_SUCCESS;
403 } 336 }
404 337
405 uint32_t RollbackKernelLock(void) { 338 uint32_t RollbackKernelLock(void) {
406 return TPM_SUCCESS; 339 if (!g_rollback_recovery_mode) {
340 return TlclLockPhysicalPresence();
341 } else {
342 return TPM_SUCCESS;
343 }
407 } 344 }
OLDNEW
« no previous file with comments | « firmware/lib/include/rollback_index.h ('k') | firmware/lib/vboot_firmware.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698