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

Side by Side Diff: tests/rollback_index_test.c

Issue 2857030: Exhaustive test for rollback code (Closed) Base URL: ssh://git@chromiumos-git/vboot_reference.git
Patch Set: Fix write count handling and improve comments. 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 | « tests/rbtest.conf ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
6 /* Exhaustive testing for correctness and integrity of TPM locking code from
7 * all interesting initial conditions.
8 *
9 * This program iterates through a large number of initial states of the TPM at
10 * power on, and executes the code related to initialing the TPM and managing
11 * the anti-rollback indices.
12 *
13 * This program must be run on a system with "TPM-agnostic" BIOS: that is, the
14 * system must have a TPM (as of this date, the emulator isn't good enough,
15 * because it doesn't support bGlobalLock), but the firmware should not issue a
16 * TPM_Startup. In addition, the TPM drivers must be loaded (tpm_tis, tpm, and
17 * tpm_bios) but tcsd should NOT be running. However, tcsd must be installed,
18 * as well as the command tpm_takeownership from the TPM tools, and tpm-nvtool
19 * from third-party/tpm.
20 *
21 * This program must be run as root. It issues multiple reboots, saving and
22 * restoring the state from a file. Typically it works in two phases: on one
23 * reboot it sets the TPM to a certain state, and in the next reboot it runs
24 * the test.
25 *
26 * This program may take a long time to complete.
27 *
28 * A companion upstart file rbtest.conf contains test setup instructions. Look
29 * around for it.
30 */
31
32 #include "rollback_index.h"
33 #include "tlcl.h"
34 #include "tss_constants.h"
35 #include "utility.h"
36
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <sys/types.h>
41 #include <syslog.h>
42 #include <unistd.h>
43
44 #define RETURN_ON_FAILURE(tpm_command) do { \
45 uint32_t result; \
46 if ((result = (tpm_command)) != TPM_SUCCESS) { \
47 return result; \
48 } \
49 } while (0)
50
51 #define WRITE_BUCKET_NV_INDEX 0x1050
52 #define STATEPATH "/mnt/stateful_partition/var/spool/rbtest.state"
53 #define TPM_ANY_FAILURE (-1)
54
55 #define TPM_MAX_NV_WRITE_NOOWNER 64
56 #define MAX_NV_WRITES_AT_BOOT 18 /* see comment below */
57 #define INITIALIZATION_NV_WRITES 11 /* see below */
58
59 const int high_writecount = TPM_MAX_NV_WRITE_NOOWNER;
60 /* The -1 below is to make sure there is at least one case when we don't hit
61 * the write limit. It is probably unnecessary, but we pay this cost to avoid
62 * an off-by-one error.
63 */
64 const int low_writecount = TPM_MAX_NV_WRITE_NOOWNER - MAX_NV_WRITES_AT_BOOT - 1;
65 const int low_writecount_when_initialized = TPM_MAX_NV_WRITE_NOOWNER
66 - MAX_NV_WRITES_AT_BOOT + INITIALIZATION_NV_WRITES;
67
68 /*
69 * This structure contains all TPM states of interest, and other testing
70 * states. It is saved and restored from a file across all reboots.
71 *
72 * OWNED/UNOWNED
73 * ACTIVATED/DEACTIVATED
74 * ENABLED/DISABLED
75 * WRITE COUNT
76 *
77 * The write count tests hitting the write limit with an unowned TPM. After
78 * resetting the TPM we reset the write count to zero, then we perform
79 * |writecount| writes to bring the count to the desired number.
80 *
81 * Low write counts are not interesting, because we know they cannot cause the
82 * code to hit the limit during a single boot. There are a total of N
83 * SafeWrite and SafeDefineSpace call sites, where N = MAX_NV_WRITES_AT_BOOT.
84 * Every call site can be reached at most once at every boot (there are no
85 * loops or multiple nested calls). So we only need to test N + 1 different
86 * initial values of the NVRAM write count (between 64 - (N + 1)) and 64).
87 *
88 * A number of calls happen at initialization, so when the TPM_IS_INITIALIZED
89 * space exists, we only need to start checking at TPM_MAX_NV_WRITE_NOOWNER -
90 * MAX_NV_WRITES_AT_BOOT + INITIALIZATION_NV_WRITES.
91 *
92 * TPM_IS_INITIALIZED space exists/does not exist
93 * KERNEL_MUST_USE_BACKUP = 0 or 1
94 * KERNEL_VERSIONS exists/does not
95 * KERNEL_VERSIONS space has wrong permissions
96 * KERNEL_VERSIONS does not contain the replacement-prevention value
97 * KERNEL_VERSIONS and KERNEL_VERSIONS_BACKUP are the same/are not
98 * DEVELOPER_MODE_NV_INDEX = 0 or 1
99 *
100 * developer switch on/off
101 * recovery switch on/off
102 */
103
104 typedef struct RBTState {
105 /* Internal testing state */
106 int advancing; /* this is 1 if we are setting the TPM to the next initial
107 state, 0 if we are running the test. */
108
109 /* TPM state */
110 int writecount;
111 int owned;
112 int disable;
113 int deactivated;
114 int TPM_IS_INITIALIZED_exists;
115 int KERNEL_MUST_USE_BACKUP;
116 int KERNEL_VERSIONS_exists;
117 int KERNEL_VERSIONS_wrong_permissions;
118 int KERNEL_VERSIONS_wrong_value;
119 int KERNEL_VERSIONS_same_as_backup;
120 int DEVELOPER_MODE; /* content of DEVELOPER_MODE space */
121 int developer; /* setting of developer mode switch */
122 int recovery; /* booting in recovery mode */
123 } RBTState;
124
125 RBTState RBTS;
126
127 /* Set to 1 if the TPM was cleared in this run, to avoid clearing it again
128 * before we set the write count.
129 */
130 int tpm_was_just_cleared = 0;
131
132 const char* RBTS_format =
133 "advancing=%d, owned=%d, disable=%d, activated=%d, "
134 "writecount=%d, TII_exists=%d, KMUB=%d, "
135 "KV_exists=%d, KV_wp=%d, KV_wv=%d, KV_sab=%d, DM=%d, dm=%d, rm=%d";
136
137 static void Log(const char* format, ...) {
138 va_list ap;
139 va_start(ap, format);
140 vsyslog(LOG_INFO, format, ap);
141 va_end(ap);
142 va_start(ap, format);
143 vfprintf(stderr, format, ap);
144 va_end(ap);
145 fprintf(stderr, "\n");
146 }
147
148 static void reboot(void) {
149 int status;
150 Log("requesting reboot");
151 status = system("/sbin/reboot");
152 if (status != 0) {
153 Log("reboot failed with status %d", status);
154 exit(1);
155 }
156 }
157
158 static void RollbackTest_SaveState(FILE* file) {
159 rewind(file);
160 fprintf(file, RBTS_format,
161 RBTS.advancing,
162 RBTS.owned,
163 RBTS.disable,
164 RBTS.deactivated,
165 RBTS.writecount,
166 RBTS.TPM_IS_INITIALIZED_exists,
167 RBTS.KERNEL_MUST_USE_BACKUP,
168 RBTS.KERNEL_VERSIONS_exists,
169 RBTS.KERNEL_VERSIONS_wrong_permissions,
170 RBTS.KERNEL_VERSIONS_wrong_value,
171 RBTS.KERNEL_VERSIONS_same_as_backup,
172 RBTS.DEVELOPER_MODE,
173 RBTS.developer,
174 RBTS.recovery);
175 }
176
177 static void RollbackTest_RestoreState(FILE* file) {
178 if (fscanf(file, RBTS_format,
179 &RBTS.advancing,
180 &RBTS.owned,
181 &RBTS.disable,
182 &RBTS.deactivated,
183 &RBTS.writecount,
184 &RBTS.TPM_IS_INITIALIZED_exists,
185 &RBTS.KERNEL_MUST_USE_BACKUP,
186 &RBTS.KERNEL_VERSIONS_exists,
187 &RBTS.KERNEL_VERSIONS_wrong_permissions,
188 &RBTS.KERNEL_VERSIONS_wrong_value,
189 &RBTS.KERNEL_VERSIONS_same_as_backup,
190 &RBTS.DEVELOPER_MODE,
191 &RBTS.developer,
192 &RBTS.recovery) != sizeof(RBTS)/sizeof(int)) {
193 Log("failed to restore state");
194 exit(1);
195 }
196 }
197
198 static void RollbackTest_LogState(void) {
199 Log(RBTS_format,
200 RBTS.advancing,
201 RBTS.owned,
202 RBTS.disable,
203 RBTS.deactivated,
204 RBTS.writecount,
205 RBTS.TPM_IS_INITIALIZED_exists,
206 RBTS.KERNEL_MUST_USE_BACKUP,
207 RBTS.KERNEL_VERSIONS_exists,
208 RBTS.KERNEL_VERSIONS_wrong_permissions,
209 RBTS.KERNEL_VERSIONS_wrong_value,
210 RBTS.KERNEL_VERSIONS_same_as_backup,
211 RBTS.DEVELOPER_MODE,
212 RBTS.developer,
213 RBTS.recovery);
214 }
215
216 /* Executes a TPM command from the shell.
217 */
218 static void RollbackTest_TPMShellCommand(char* command) {
219 int status;
220 TlclCloseDevice();
221 status = system("/usr/sbin/tcsd");
222 if (status != 0) {
223 Log("could not start tcsd");
224 exit(1);
225 }
226 status = system("/usr/bin/sleep 0.1");
227 status = system(command);
228 if (status != 0) {
229 Log("command %s returned 0x%x", command, status);
230 exit(1);
231 }
232 status = system("/usr/bin/pkill tcsd");
233 if (status != 0) {
234 Log("could not kill tcsd, status 0x%x", status);
235 exit(1);
236 }
237 status = system("/usr/bin/sleep 0.1");
238 TlclOpenDevice();
239 }
240
241 /* Sets or clears ownership.
242 */
243 static uint32_t RollbackTest_SetOwnership(int ownership) {
244 if (ownership) {
245 /* Requesting owned state */
246 int owned = TlclIsOwned();
247 if (!owned) {
248 Log("acquiring ownership");
249 RollbackTest_TPMShellCommand("/usr/sbin/tpm_takeownership -y -z");
250 Log("ownership acquired");
251 }
252 } else {
253 /* Requesting unowned state */
254 Log("clearing TPM");
255 RETURN_ON_FAILURE(TPMClearAndReenable());
256 tpm_was_just_cleared = 1;
257 }
258 return TPM_SUCCESS;
259 }
260
261 /* Removes a space. This is a huge pain, because spaces can be removed only
262 * when the TPM is owned.
263 */
264 static uint32_t RollbackTest_RemoveSpace(uint32_t index) {
265 char command[1024];
266 RollbackTest_SetOwnership(1);
267 snprintf(command, sizeof(command),
268 "/usr/bin/tpm-nvtool --release --index 0x%x --owner_password \"\"",
269 index);
270 Log("releasing space %x with command: %s", index, command);
271 RollbackTest_TPMShellCommand(command);
272 Log("space %x released", index);
273 return TPM_SUCCESS;
274 }
275
276 /* Checks if the TPM is disabled/deactivated, and optionally enables/activates.
277 * Does not disable/deactivate here because it might interfere with other
278 * operations.
279 */
280 static uint32_t RollbackTest_PartiallyAdjustFlags(uint8_t* disable,
281 uint8_t* deactivated) {
282 RETURN_ON_FAILURE(TlclGetFlags(disable, deactivated));
283
284 if (*deactivated && !RBTS.deactivated) {
285 /* Needs to enable before we can activate. */
286 RETURN_ON_FAILURE(TlclSetEnable());
287 *disable = 0;
288 /* Needs to reboot after activating. */
289 RETURN_ON_FAILURE(TlclSetDeactivated(0));
290 reboot();
291 }
292 /* We disable and deactivate at the end, if needed. */
293
294 if (*disable && !RBTS.disable) {
295 RETURN_ON_FAILURE(TlclSetEnable());
296 }
297 return TPM_SUCCESS;
298 }
299
300 /* Removes or creates the TPM_IS_INITIALIZED space.
301 */
302 static uint32_t RollbackTest_AdjustIsInitialized(void) {
303 int initialized;
304 RETURN_ON_FAILURE(GetSpacesInitialized(&initialized));
305 if (RBTS.TPM_IS_INITIALIZED_exists && !initialized) {
306 RETURN_ON_FAILURE(TlclDefineSpace(TPM_IS_INITIALIZED_NV_INDEX,
307 TPM_NV_PER_PPWRITE, sizeof(uint32_t)));
308 }
309 if (!RBTS.TPM_IS_INITIALIZED_exists && initialized) {
310 RETURN_ON_FAILURE(RollbackTest_RemoveSpace(TPM_IS_INITIALIZED_NV_INDEX));
311 }
312 return TPM_SUCCESS;
313 }
314
315 /* Sets or clears KERNEL_MUST_USE_BACKUP.
316 */
317 static uint32_t RollbackTest_AdjustMustUseBackup(void) {
318 uint32_t must_use_backup;
319 RETURN_ON_FAILURE(TlclRead(KERNEL_MUST_USE_BACKUP_NV_INDEX,
320 (uint8_t*) &must_use_backup,
321 sizeof(must_use_backup)));
322 if (RBTS.KERNEL_MUST_USE_BACKUP != must_use_backup) {
323 RETURN_ON_FAILURE(TlclWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX,
324 (uint8_t*) &must_use_backup,
325 sizeof(must_use_backup)));
326 }
327 return TPM_SUCCESS;
328 }
329
330 /* Adjusts KERNEL_VERSIONS space.
331 */
332 static uint32_t RollbackTest_AdjustKernelVersions(int* wrong_value) {
333 uint8_t kdata[KERNEL_SPACE_SIZE];
334 int exists;
335 uint32_t result;
336
337 result = TlclRead(KERNEL_VERSIONS_NV_INDEX, kdata, sizeof(kdata));
338 if (result != TPM_SUCCESS && result != TPM_E_BADINDEX) {
339 return result;
340 }
341 *wrong_value = Memcmp(kdata + sizeof(uint32_t), KERNEL_SPACE_UID,
342 KERNEL_SPACE_UID_SIZE); /* for later use */
343 exists = result == TPM_SUCCESS;
344 if (RBTS.KERNEL_VERSIONS_exists && !exists) {
345 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX,
346 TPM_NV_PER_PPWRITE, KERNEL_SPACE_SIZE));
347 }
348 if (!RBTS.KERNEL_VERSIONS_exists && exists) {
349 RETURN_ON_FAILURE(RollbackTest_RemoveSpace(KERNEL_VERSIONS_NV_INDEX));
350 }
351 return TPM_SUCCESS;
352 }
353
354 /* Adjusts permissions of KERNEL_VERSIONS space. Updates |wrong_value| to
355 * reflect that currently the space contains the wrong value (i.e. does not
356 * contain the GRWL identifier).
357 */
358 static uint32_t RollbackTest_AdjustKernelPermissions(int* wrong_value) {
359 uint32_t perms;
360
361 /* Wrong permissions */
362 RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_VERSIONS_NV_INDEX, &perms));
363 if (RBTS.KERNEL_VERSIONS_wrong_permissions && perms == TPM_NV_PER_PPWRITE) {
364 /* Redefines with wrong permissions. */
365 RETURN_ON_FAILURE(RollbackTest_RemoveSpace(KERNEL_VERSIONS_NV_INDEX));
366 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX,
367 TPM_NV_PER_PPWRITE |
368 TPM_NV_PER_GLOBALLOCK,
369 KERNEL_SPACE_SIZE));
370 *wrong_value = 1;
371 }
372 if (!RBTS.KERNEL_VERSIONS_wrong_permissions &&
373 perms != TPM_NV_PER_PPWRITE) {
374 /* Redefines with right permissions. */
375 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX,
376 TPM_NV_PER_PPWRITE, 0));
377 RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX,
378 TPM_NV_PER_PPWRITE,
379 KERNEL_SPACE_SIZE));
380 *wrong_value = 1;
381 }
382 return TPM_SUCCESS;
383 }
384
385 static uint32_t RollbackTest_AdjustKernelValue(int wrong_value) {
386 if (!RBTS.KERNEL_VERSIONS_wrong_value && wrong_value) {
387 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX,
388 KERNEL_SPACE_INIT_DATA, KERNEL_SPACE_SIZE));
389 }
390 if (RBTS.KERNEL_VERSIONS_wrong_value && !wrong_value) {
391 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX,
392 (uint8_t*) "mickey mouse",
393 KERNEL_SPACE_SIZE));
394 }
395 return TPM_SUCCESS;
396 }
397
398 /* Adjusts value of KERNEL_VERSIONS_BACKUP space.
399 */
400 static uint32_t RollbackTest_AdjustKernelBackup(void) {
401 /* Same as backup */
402 uint32_t kv, kvbackup;
403 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX,
404 (uint8_t*) &kv, sizeof(kv)));
405 RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX,
406 (uint8_t*) &kvbackup, sizeof(kvbackup)));
407 if (RBTS.KERNEL_VERSIONS_same_as_backup && kv != kvbackup) {
408 kvbackup = kv;
409 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX,
410 (uint8_t*) &kvbackup, sizeof(kvbackup)));
411 }
412 if (!RBTS.KERNEL_VERSIONS_same_as_backup && kv == kvbackup) {
413 kvbackup = kv + 1;
414 RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX,
415 (uint8_t*) &kvbackup, sizeof(kvbackup)));
416 }
417 return TPM_SUCCESS;
418 }
419
420 /* Adjust the value in the developer mode transition space.
421 */
422 static uint32_t RollbackTest_AdjustDeveloperMode(void) {
423 uint32_t dev;
424 /* Developer mode transitions */
425 RETURN_ON_FAILURE(TlclRead(DEVELOPER_MODE_NV_INDEX,
426 (uint8_t*) &dev, sizeof(dev)));
427
428 if (RBTS.developer != dev) {
429 dev = RBTS.developer;
430 RETURN_ON_FAILURE(TlclWrite(DEVELOPER_MODE_NV_INDEX,
431 (uint8_t*) &dev, sizeof(dev)));
432 }
433 return TPM_SUCCESS;
434 }
435
436 /* Changes the unowned write count.
437 */
438 static uint32_t RollbackTest_AdjustWriteCount(void) {
439 int i;
440 if (!RBTS.owned) {
441 /* Sets the unowned write count, but only if we think that it will make a
442 * difference for the test. In other words: we're trying to reduce the
443 * number if initial states with some reasoning that we hope is correct.
444 */
445 if (RBTS.writecount > low_writecount) {
446 if (!tpm_was_just_cleared) {
447 /* Unknown write count: must clear the TPM to reset to 0 */
448 RETURN_ON_FAILURE(TPMClearAndReenable());
449 }
450 for (i = 0; i < RBTS.writecount; i++) {
451 /* Changes the value to ensure that the TPM won't optimize away
452 * writes.
453 */
454 uint8_t b = (uint8_t) i;
455 RETURN_ON_FAILURE(TlclWrite(WRITE_BUCKET_NV_INDEX, &b, 1));
456 }
457 }
458 }
459 return TPM_SUCCESS;
460 }
461
462 /* Sets the TPM to the right state for the next test run.
463 *
464 * Functionally correct ordering is tricky. Optimal ordering is even trickier
465 * (no claim to this). May succeed only partially and require a reboot to
466 * continue (if the TPM was deactivated at boot).
467 */
468 static uint32_t RollbackTest_SetTPMState(int initialize) {
469 uint8_t disable, deactivated;
470 int wrong_value = 0;
471
472 /* Initializes if needed */
473 if (initialize) {
474 TlclLibInit();
475 /* Don't worry if we're already started. */
476 (void) TlclStartup();
477 RETURN_ON_FAILURE(TlclContinueSelfTest());
478 RETURN_ON_FAILURE(TlclAssertPhysicalPresence());
479 }
480
481 RETURN_ON_FAILURE(RollbackTest_PartiallyAdjustFlags(&disable, &deactivated));
482 RETURN_ON_FAILURE(RollbackTest_AdjustIsInitialized());
483 RETURN_ON_FAILURE(RollbackTest_AdjustMustUseBackup());
484 RETURN_ON_FAILURE(RollbackTest_AdjustKernelVersions(&wrong_value));
485
486 if (RBTS.KERNEL_VERSIONS_exists) {
487 /* Adjusting these states only makes sense when the kernel versions space
488 * exists. */
489 RETURN_ON_FAILURE(RollbackTest_AdjustKernelPermissions(&wrong_value));
490 RETURN_ON_FAILURE(RollbackTest_AdjustKernelValue(wrong_value));
491 RETURN_ON_FAILURE(RollbackTest_AdjustKernelBackup());
492 }
493
494 RETURN_ON_FAILURE(RollbackTest_AdjustDeveloperMode());
495 RETURN_ON_FAILURE(RollbackTest_SetOwnership(RBTS.owned));
496 /* Do not remove spaces between SetOwnership and AdjustWriteCount, as that
497 * might change the ownership state. Also do not issue any writes from now
498 * on, because AdjustWriteCount tries to avoid unneccessary clears, and after
499 * that, any writes will obviously change the write count.
500 */
501 RETURN_ON_FAILURE(RollbackTest_AdjustWriteCount());
502
503 /* Finally, disables and/or deactivates. Must deactivate before disabling
504 */
505 if (!deactivated && RBTS.deactivated) {
506 RETURN_ON_FAILURE(TlclSetDeactivated(1));
507 }
508 /* It's better to do this last, even though most commands we use work with
509 * the TPM disabled.
510 */
511 if (!disable && RBTS.disable) {
512 RETURN_ON_FAILURE(TlclClearEnable());
513 }
514 return TPM_SUCCESS;
515 }
516
517 #define ADVANCE(rbts_field, min, max) do { \
518 if (RBTS.rbts_field == max) { \
519 RBTS.rbts_field = min; \
520 } else { \
521 RBTS.rbts_field++; \
522 return 0; \
523 } \
524 } while (0)
525
526 #define ADVANCEB(field) ADVANCE(field, 0, 1)
527
528 static int RollbackTest_AdvanceState(void) {
529 /* This is a generalized counter. It advances an element of the RTBS
530 * structure, and when it hits its maximum value, it resets the element and
531 * moves on to the next element, similar to the way a decimal counter
532 * increases each digit from 0 to 9 and back to 0 with a carry.
533 *
534 * Tip: put the expensive state changes at the end.
535 */
536 ADVANCEB(developer);
537 ADVANCEB(recovery);
538 ADVANCEB(TPM_IS_INITIALIZED_exists);
539 ADVANCEB(KERNEL_MUST_USE_BACKUP);
540 if (RBTS.owned) {
541 ADVANCEB(KERNEL_VERSIONS_exists);
542 ADVANCEB(KERNEL_VERSIONS_wrong_permissions);
543 ADVANCEB(KERNEL_VERSIONS_wrong_value);
544 ADVANCEB(KERNEL_VERSIONS_same_as_backup);
545 }
546 ADVANCEB(DEVELOPER_MODE);
547 /* The writecount is meaningful only when the TPM is not owned. */
548 if (!RBTS.owned) {
549 ADVANCE(writecount, low_writecount, high_writecount);
550 if (RBTS.TPM_IS_INITIALIZED_exists) {
551 /* We don't have to go through the full range in this case. */
552 if (RBTS.writecount < low_writecount_when_initialized) {
553 RBTS.writecount = low_writecount_when_initialized;
554 }
555 }
556 }
557 ADVANCEB(deactivated);
558 ADVANCEB(disable);
559 ADVANCEB(owned);
560 if (RBTS.owned == 0) {
561 /* overflow */
562 return 1;
563 }
564 return 0;
565 }
566
567 static void RollbackTest_InitializeState(void) {
568 FILE* file = fopen(STATEPATH, "w");
569 if (file == NULL) {
570 fprintf(stderr, "could not open %s for writing\n", STATEPATH);
571 exit(1);
572 }
573 RBTS.writecount = low_writecount;
574 RollbackTest_SaveState(file);
575 }
576
577 uint32_t RollbackTest_Test(void) {
578 uint16_t key_version, version;
579
580 if (RBTS.recovery) {
581 if (RBTS.developer) {
582 /* Developer Recovery mode */
583 RETURN_ON_FAILURE(RollbackKernelRecovery(1));
584 } else {
585 /* Normal Recovery mode */
586 RETURN_ON_FAILURE(RollbackKernelRecovery(0));
587 }
588 } else {
589 if (RBTS.developer) {
590 /* Developer mode */
591 key_version = 0;
592 version = 0;
593 RETURN_ON_FAILURE(RollbackFirmwareSetup(1));
594 RETURN_ON_FAILURE(RollbackFirmwareLock());
595 } else {
596 /* Normal mode */
597 key_version = 0;
598 version = 0;
599 RETURN_ON_FAILURE(RollbackFirmwareSetup(0));
600 RETURN_ON_FAILURE(RollbackFirmwareLock());
601 RETURN_ON_FAILURE(RollbackKernelRead(&key_version, &version));
602 RETURN_ON_FAILURE(RollbackKernelWrite(key_version, version));
603 RETURN_ON_FAILURE(RollbackKernelLock());
604 }
605 }
606 return TPM_SUCCESS;
607 }
608
609 /* One-time call to create the WRITE_BUCKET space.
610 */
611 static uint32_t RollbackTest_InitializeTPM(void) {
612 TlclLibInit();
613 RETURN_ON_FAILURE(TlclStartup());
614 RETURN_ON_FAILURE(TlclContinueSelfTest());
615 RETURN_ON_FAILURE(TlclAssertPhysicalPresence());
616 RETURN_ON_FAILURE(TlclDefineSpace(WRITE_BUCKET_NV_INDEX,
617 TPM_NV_PER_PPWRITE, 1));
618 RETURN_ON_FAILURE(RollbackTest_SetTPMState(0));
619 return TPM_SUCCESS;
620 }
621
622 static void RollbackTest_Initialize(void) {
623 Log("initializing");
624 RollbackTest_InitializeState();
625 if (RollbackTest_InitializeTPM() != TPM_SUCCESS) {
626 Log("couldn't initialize TPM");
627 exit(1);
628 }
629 }
630
631 /* Advances the desired TPM state and sets the TPM to the new state.
632 */
633 static void RollbackTest_Advance(FILE* file) {
634 uint32_t result;
635 Log("advancing state");
636 if (RollbackTest_AdvanceState()) {
637 Log("done");
638 exit(0);
639 }
640 result = RollbackTest_SetTPMState(1);
641 if (result == TPM_SUCCESS) {
642 RBTS.advancing = 0;
643 RollbackTest_SaveState(file);
644 reboot();
645 } else {
646 Log("SetTPMState failed with 0x%x\n", result);
647 exit(1);
648 }
649 }
650
651 /* Performs the test for the current TPM state, and verify that the outcome
652 * matches the expectations.
653 */
654 static void RollbackTest_RunOneTest(FILE* file) {
655 uint32_t result;
656 uint32_t expected_result = TPM_SUCCESS;
657
658 if (!RBTS.KERNEL_VERSIONS_exists ||
659 RBTS.KERNEL_VERSIONS_wrong_permissions ||
660 RBTS.KERNEL_VERSIONS_wrong_value) {
661 expected_result = TPM_E_CORRUPTED_STATE;
662 }
663
664 if (!RBTS.KERNEL_VERSIONS_exists && !RBTS.TPM_IS_INITIALIZED_exists) {
665 /* The space will be recreated */
666 expected_result = TPM_SUCCESS;
667 }
668
669 if ((!RBTS.TPM_IS_INITIALIZED_exists || !RBTS.KERNEL_VERSIONS_exists)
670 && RBTS.owned) {
671 /* Cannot create spaces without owner authorization */
672 expected_result = TPM_E_OWNER_SET;
673 }
674
675 if (RBTS.TPM_IS_INITIALIZED_exists && !RBTS.KERNEL_VERSIONS_exists) {
676 expected_result = TPM_ANY_FAILURE;
677 }
678
679 result = RollbackTest_Test();
680
681 if (result == expected_result ||
682 (result != TPM_SUCCESS && expected_result == TPM_ANY_FAILURE)) {
683 Log("test succeeded with 0x%x\n", result);
684 RBTS.advancing = 1;
685 RollbackTest_SaveState(file);
686 reboot();
687 } else {
688 Log("test failed with 0x%x, expecting 0x%x\n", result, expected_result);
689 exit(1);
690 }
691 }
692
693 static FILE* RollbackTest_OpenState(void) {
694 FILE* file = fopen(STATEPATH, "r+");
695 if (file == NULL) {
696 Log("%s could not be opened", STATEPATH);
697 exit(1);
698 }
699 return file;
700 }
701
702 /* Sync saved state with TPM state.
703 */
704 static void RollbackTest_Sync(void) {
705 FILE *file = RollbackTest_OpenState();
706 uint32_t result;
707 RollbackTest_RestoreState(file);
708 Log("Syncing state");
709 result = RollbackTest_SetTPMState(1);
710 if (result != TPM_SUCCESS) {
711 Log("Sync failed with %x", result);
712 exit(1);
713 }
714 }
715
716 /* Runs one testing iteration and advances the testing state.
717 */
718 static void RollbackTest_Run(void) {
719 FILE* file = RollbackTest_OpenState();
720 RollbackTest_RestoreState(file);
721 RollbackTest_LogState();
722 if (RBTS.advancing) {
723 RollbackTest_Advance(file);
724 } else {
725 RollbackTest_RunOneTest(file);
726 }
727 }
728
729 int main(int argc, char** argv) {
730
731 openlog("rbtest", LOG_CONS | LOG_PERROR, LOG_USER);
732
733 if (geteuid() != 0) {
734 fprintf(stderr, "rollback-test: must run as root\n");
735 exit(1);
736 }
737
738 if (argc == 2 && strcmp(argv[1], "initialize") == 0) {
739 RollbackTest_Initialize();
740 } else if (argc == 2 && strcmp(argv[1], "sync") == 0) {
741 RollbackTest_Sync();
742 } else if (argc == 1) {
743 RollbackTest_Run();
744 } else {
745 fprintf(stderr, "usage: rollback-test [ initialize ]\n");
746 exit(1);
747 }
748 return 0;
749 }
OLDNEW
« no previous file with comments | « tests/rbtest.conf ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698