summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2013-01-25 16:02:32 -0800
committerBill Richardson <wfrichar@chromium.org>2013-01-25 16:03:25 -0800
commit9c45cd6562f27e6fbea792b0a3c7d000baa13bd4 (patch)
tree54d8fd79761e3e941a07cf6597c54af2ee7e73fd
parent5c05e01142e8de8d5c9d0582360f67f091b3cdb1 (diff)
parent786a5dca74387de5ffdc51ca5a099a4e90f406da (diff)
downloadvboot-9c45cd6562f27e6fbea792b0a3c7d000baa13bd4.tar.gz
Add logging capability, sync with m/master
BUG=none BRANCH=none TEST=none Change-Id: If2438c007c2233501945db67d238fc5c7defef4b
-rw-r--r--Makefile152
-rw-r--r--firmware/arch/x86/include/biosincludes.h (renamed from firmware/arch/i386/include/biosincludes.h)0
-rw-r--r--firmware/lib/cgptlib/include/cgptlib.h4
-rw-r--r--firmware/lib/cgptlib/include/cgptlib_internal.h11
-rw-r--r--firmware/lib/include/vboot_common.h13
-rw-r--r--firmware/lib/include/vboot_display.h5
-rw-r--r--firmware/lib/rollback_index.c893
-rw-r--r--firmware/lib/vboot_common.c79
-rw-r--r--firmware/lib/vboot_display.c3
-rw-r--r--futility/futility.c98
l---------host/arch/x86_64/lib/crossystem_arch.c (renamed from host/arch/amd64/lib/crossystem_arch.c)0
-rw-r--r--tests/cgptlib_test.c2366
-rw-r--r--tests/rollback_index2_tests.c1630
-rw-r--r--tests/rollback_index3_tests.c45
-rwxr-xr-xtests/run_vboot_ec_tests.sh19
-rwxr-xr-xtests/test_using_qemu.sh40
-rw-r--r--tests/vboot_api_init_tests.c777
-rw-r--r--tests/vboot_common2_tests.c433
-rw-r--r--tests/vboot_common3_tests.c156
-rw-r--r--tests/vboot_common_tests.c387
-rw-r--r--tests/vboot_display_tests.c83
-rw-r--r--tests/vboot_ec_tests.c160
-rw-r--r--tests/vboot_nvstorage_test.c35
-rw-r--r--utility/vbutil_ec.c532
24 files changed, 3985 insertions, 3936 deletions
diff --git a/Makefile b/Makefile
index 878fce0b..883ac308 100644
--- a/Makefile
+++ b/Makefile
@@ -36,8 +36,8 @@
# changed or appended. They must be defined before being used anywhere.
# we should only run pwd once, not every time we refer to ${BUILD}.
-_whereami := $(shell pwd)
-BUILD ?= $(_whereami)/build
+SRCDIR := $(shell pwd)
+BUILD ?= $(SRCDIR)/build
export BUILD
# Target for 'make install'
@@ -52,6 +52,29 @@ ifeq (${V},)
Q := @
endif
+# Architecture detection
+_machname := $(shell uname -m)
+HOST_ARCH ?= ${_machname}
+
+# ARCH and/or FIRMWARE_ARCH are defined by the Chromium OS ebuild.
+# Pick a sane target architecture if none is defined.
+ifeq (${ARCH},)
+ ARCH := ${HOST_ARCH}
+else ifeq (${ARCH},i386)
+ override ARCH := x86
+else ifeq (${ARCH},amd64)
+ override ARCH := x86_64
+endif
+
+# FIRMWARE_ARCH is only defined by the Chromium OS ebuild if compiling
+# for a firmware target (such as u-boot or depthcharge). It must map
+# to the same consistent set of architectures as the host.
+ifeq (${FIRMWARE_ARCH},i386)
+ override FIRMWARE_ARCH := x86
+else ifeq (${FIRMWARE_ARCH},amd64)
+ override FIRMWARE_ARCH := x86_64
+endif
+
# Provide default CC and CFLAGS for firmware builds; if you have any -D flags,
# please add them after this point (e.g., -DVBOOT_DEBUG).
#
@@ -75,7 +98,7 @@ CFLAGS ?= -march=armv5 \
-fno-common -ffixed-r8 \
-mfloat-abi=hard -marm -mabi=aapcs-linux -mno-thumb-interwork \
${COMMON_FLAGS}
-else ifeq (${FIRMWARE_ARCH}, i386)
+else ifeq (${FIRMWARE_ARCH}, x86)
CC ?= i686-pc-linux-gnu-gcc
# Drop -march=i386 to permit use of SSE instructions
CFLAGS ?= \
@@ -103,11 +126,12 @@ endif
# Create / use dependency files
CFLAGS += -MMD -MF $@.d
-# Code coverage. Run like this: COV=1 make runtests coverage
+# Code coverage
ifneq (${COV},)
-COV_FLAGS = -O0 --coverage
-CFLAGS += ${COV_FLAGS}
-LDFLAGS += ${COV_FLAGS}
+ COV_FLAGS = -O0 --coverage
+ CFLAGS += ${COV_FLAGS}
+ LDFLAGS += ${COV_FLAGS}
+ COV_INFO = ${BUILD}/coverage.info
endif
# And a few more default utilities
@@ -115,32 +139,13 @@ LD = ${CC}
CXX ?= g++ # HEY: really?
PKG_CONFIG ?= pkg-config
-# Architecture detection. If we're cross-compiling, we may need to run unit
-# tests inside QEMU.
-_machname := $(shell uname -m)
-HOST_ARCH ?= ${_machname}
-
-# Note: ARCH is defined by the Chromium OS ebuild. Pick a sane target
-# architecture if none is defined.
-ifeq (${ARCH},)
- ARCH := ${HOST_ARCH}
- ifeq (${ARCH}, x86_64)
- ARCH := amd64
- endif
-endif
-
# Determine QEMU architecture needed, if any
ifeq (${ARCH},${HOST_ARCH})
# Same architecture; no need for QEMU
QEMU_ARCH :=
-else ifeq (${HOST_ARCH}-${ARCH},x86_64-i386)
+else ifeq (${HOST_ARCH}-${ARCH},x86_64-x86)
# 64-bit host can run 32-bit targets directly
QEMU_ARCH :=
-else ifeq (${HOST_ARCH}-${ARCH},x86_64-amd64)
- # 64-bit host can run 64-bit directly
- QEMU_ARCH :=
-else ifeq (${ARCH},amd64)
- QEMU_ARCH := x86_64
else
QEMU_ARCH := ${ARCH}
endif
@@ -152,21 +157,21 @@ endif
ifeq (${QEMU_ARCH},)
# Path to build output for running tests is same as for building
BUILD_RUN = ${BUILD}
+ SRC_RUN = ${SRCDIR}
else
$(info Using qemu for testing.)
# Path to build output for running tests is different in the chroot
BUILD_RUN = $(subst ${SYSROOT},,${BUILD})
+ SRC_RUN = $(subst ${SYSROOT},,${SRCDIR})
QEMU_BIN = qemu-${QEMU_ARCH}
- QEMU_OPTS = -drop-ld-preload \
- -E LD_LIBRARY_PATH=/lib64:/lib:/usr/lib64:/usr/lib \
- -E HOME=${HOME} \
- -E BUILD=${BUILD_RUN}
- QEMU_CMD = sudo chroot ${SYSROOT} ${BUILD_RUN}/${QEMU_BIN} ${QEMU_OPTS} --
- RUNTEST = ${QEMU_CMD}
-endif
+ QEMU_RUN = ${BUILD_RUN}/${QEMU_BIN}
+ export QEMU_RUN
+ RUNTEST = tests/test_using_qemu.sh
+endif
+export BUILD_RUN
# Some things only compile inside the Chromium OS chroot.
# TODO: Those things should be in their own repo, not part of vboot_reference
@@ -342,7 +347,6 @@ UTIL_NAMES = ${UTIL_NAMES_STATIC} \
signature_digest_utility \
tpm_init_temp_fix \
tpmc \
- vbutil_ec \
vbutil_firmware \
vbutil_kernel \
vbutil_key \
@@ -401,6 +405,7 @@ ALL_OBJS += ${TESTLIB_OBJS}
TEST_NAMES = \
cgptlib_test \
rollback_index2_tests \
+ rollback_index3_tests \
rsa_padding_test \
rsa_utility_tests \
rsa_verify_benchmark \
@@ -410,7 +415,6 @@ TEST_NAMES = \
tpm_bootmode_tests \
utility_string_tests \
utility_tests \
- vboot_nvstorage_test \
vboot_api_init_tests \
vboot_api_devmode_tests \
vboot_api_firmware_tests \
@@ -419,8 +423,9 @@ TEST_NAMES = \
vboot_common_tests \
vboot_common2_tests \
vboot_common3_tests \
- vboot_ec_tests \
- vboot_firmware_tests
+ vboot_display_tests \
+ vboot_firmware_tests \
+ vboot_nvstorage_test
# Grrr
ifneq (${IN_CHROOT},)
@@ -466,6 +471,8 @@ TEST_NAMES += ${TLCL_TEST_NAMES}
TEST_BINS = $(addprefix ${BUILD}/tests/,${TEST_NAMES})
ALL_DEPS += $(addsuffix .d,${TEST_BINS})
+# Directory containing test keys
+TEST_KEYS = ${SRC_RUN}/tests/testkeys
# ----------------------------------------------------------------------------
# TODO: why not make this include *all* the cgpt files, and simply have
@@ -504,7 +511,7 @@ _dir_create := $(foreach d, \
# Default target.
.PHONY: all
-all: fwlib $(if ${FIRMWARE_ARCH},,host_stuff)
+all: fwlib $(if ${FIRMWARE_ARCH},,host_stuff) $(if ${COV},coverage)
# Host targets
.PHONY: host_stuff
@@ -521,17 +528,6 @@ clean:
.PHONY: install
install: cgpt_install utils_install futil_install
-# Coverage
-# TODO: only if COV=1
-# HEY - depend on runtests?
-COV_INFO = ${BUILD}/coverage.info
-.PHONY: coverage
-coverage:
- rm -f ${COV_INFO}*
- lcov --capture --directory . --base-directory . -o ${COV_INFO}.1
- lcov --remove ${COV_INFO}.1 '/usr/*' -o ${COV_INFO}
- genhtml ${COV_INFO} --output-directory ${BUILD}/coverage
-
# Don't delete intermediate object files
.SECONDARY:
@@ -551,7 +547,7 @@ ALL_DEPS += ${ALL_OBJS:%.o=%.o.d}
# TPM_BLOCKING_CONTINUESELFTEST is defined if TPM_ContinueSelfTest blocks until
# the self test has completed.
-${FWLIB}: CFLAGS += -DTPM_BLOCKING_CONTINUESELFTEST
+${FWLIB_OBJS}: CFLAGS += -DTPM_BLOCKING_CONTINUESELFTEST
# TPM_MANUAL_SELFTEST is defined if the self test must be started manually
# (with a call to TPM_ContinueSelfTest) instead of starting automatically at
@@ -564,24 +560,24 @@ ${FWLIB}: CFLAGS += -DTPM_BLOCKING_CONTINUESELFTEST
ifeq (${FIRMWARE_ARCH},i386)
# Unrolling loops in cryptolib makes it faster
-${FWLIB}: CFLAGS += -DUNROLL_LOOPS
+${FWLIB_OBJS}: CFLAGS += -DUNROLL_LOOPS
# Workaround for coreboot on x86, which will power off asynchronously
# without giving us a chance to react. This is not an example of the Right
# Way to do things. See chrome-os-partner:7689, and the commit message
# that made this change.
-${FWLIB}: CFLAGS += -DSAVE_LOCALE_IMMEDIATELY
+${FWLIB_OBJS}: CFLAGS += -DSAVE_LOCALE_IMMEDIATELY
# On x86 we don't actually read the GBB data into RAM until it is needed.
# Therefore it makes sense to cache it rather than reading it each time.
# Enable this feature.
-${FWLIB}: CFLAGS += -DCOPY_BMP_DATA
+${FWLIB_OBJS}: CFLAGS += -DCOPY_BMP_DATA
endif
ifeq (${FIRMWARE_ARCH},)
# Disable rollback TPM when compiling locally, since otherwise
# load_kernel_test attempts to talk to the TPM.
-${FWLIB}: CFLAGS += -DDISABLE_ROLLBACK_TPM
+${FWLIB_OBJS}: CFLAGS += -DDISABLE_ROLLBACK_TPM
endif
.PHONY: fwlib
@@ -804,12 +800,15 @@ ${BUILD}/utility/dump_kernel_config: ${DUMPKERNELCONFIGLIB}
# GBB utility needs C++ linker. TODO: It shouldn't.
${BUILD}/utility/gbb_utility: LD = ${CXX}
+# Because we play some clever linker script games to add new commands without
+# changing any header files, futility must be linked with ld.bfd, not gold.
+${FUTIL_BIN}: LDFLAGS += -fuse-ld=bfd
+
# Some utilities need external crypto functions
${BUILD}/utility/dumpRSAPublicKey: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/utility/pad_digest_utility: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/utility/signature_digest_utility: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/utility/dev_sign_file: LDLIBS += ${CRYPTO_LIBS}
-${BUILD}/utility/vbutil_ec: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/utility/vbutil_firmware: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/utility/vbutil_kernel: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/utility/vbutil_key: LDLIBS += ${CRYPTO_LIBS}
@@ -818,8 +817,6 @@ ${BUILD}/utility/vbutil_keyblock: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/host/linktest/main: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/vboot_common2_tests: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/vboot_common3_tests: LDLIBS += ${CRYPTO_LIBS}
-${BUILD}/tests/vboot_ec_tests: LDLIBS += ${CRYPTO_LIBS}
-
${BUILD}/utility/bmpblk_utility: LD = ${CXX}
${BUILD}/utility/bmpblk_utility: LDLIBS = -llzma -lyaml
@@ -931,13 +928,13 @@ runtestscripts: test_setup genfuzztestcases
tests/run_cgpt_tests.sh ${BUILD_RUN}/cgpt/cgpt
tests/run_preamble_tests.sh
tests/run_rsa_tests.sh
- tests/run_vboot_common_tests.sh
tests/run_vbutil_kernel_arg_tests.sh
tests/run_vbutil_tests.sh
.PHONY: runmisctests
runmisctests: test_setup
${RUNTEST} ${BUILD_RUN}/tests/rollback_index2_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/rollback_index3_tests
${RUNTEST} ${BUILD_RUN}/tests/rsa_utility_tests
${RUNTEST} ${BUILD_RUN}/tests/sha_tests
${RUNTEST} ${BUILD_RUN}/tests/stateful_util_tests
@@ -948,7 +945,12 @@ runmisctests: test_setup
${RUNTEST} ${BUILD_RUN}/tests/vboot_api_init_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_api_firmware_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_audio_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_common_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_common2_tests ${TEST_KEYS}
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_common3_tests ${TEST_KEYS}
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_display_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_firmware_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_nvstorage_test
.PHONY: runfutiltests
runfutiltests: DESTDIR := ${TEST_INSTALL_DIR}
@@ -957,13 +959,13 @@ runfutiltests: test_setup install
futility/tests/run_futility_tests.sh ${DESTDIR}
# Run long tests, including all permutations of encryption keys (instead of
-# just the ones we use) and tests of currently-unused code (e.g. vboot_ec).
+# just the ones we use) and tests of currently-unused code.
# Not run by automated build.
.PHONY: runlongtests
runlongtests: test_setup genkeys genfuzztestcases
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_common2_tests ${TEST_KEYS} --all
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_common3_tests ${TEST_KEYS} --all
tests/run_preamble_tests.sh --all
- tests/run_vboot_common_tests.sh --all
- tests/run_vboot_ec_tests.sh
tests/run_vbutil_tests.sh --all
# TODO: tests to run when ported to new API
@@ -975,3 +977,29 @@ runlongtests: test_setup genkeys genfuzztestcases
# ${BUILD}/tests/firmware_rollback_tests
# ${BUILD}/tests/kernel_rollback_tests
+# Code coverage
+.PHONY: coverage_init
+coverage_init: test_setup
+ rm -f ${COV_INFO}*
+ lcov -c -i -d . -b . -o ${COV_INFO}.initial
+
+.PHONY: coverage_html
+coverage_html:
+ lcov -c -d . -b . -o ${COV_INFO}.tests
+ lcov -a ${COV_INFO}.initial -a ${COV_INFO}.tests -o ${COV_INFO}.total
+ lcov -r ${COV_INFO}.total '/usr/*' '*/linktest/*' -o ${COV_INFO}.local
+ genhtml ${COV_INFO}.local -o ${BUILD}/coverage
+
+# Generate addtional coverage stats just for firmware subdir, because the
+# per-directory stats for the whole project don't include their own subdirs.
+ lcov -e ${COV_INFO}.local '${SRCDIR}/firmware/*' \
+ -o ${COV_INFO}.firmware
+
+.PHONY: coverage
+ifeq (${COV},)
+coverage:
+ $(error Build coverage like this: make clean && COV=1 make)
+else
+coverage: coverage_init runtests coverage_html
+endif
+
diff --git a/firmware/arch/i386/include/biosincludes.h b/firmware/arch/x86/include/biosincludes.h
index 5f6b1cc2..5f6b1cc2 100644
--- a/firmware/arch/i386/include/biosincludes.h
+++ b/firmware/arch/x86/include/biosincludes.h
diff --git a/firmware/lib/cgptlib/include/cgptlib.h b/firmware/lib/cgptlib/include/cgptlib.h
index b6b27c96..6633733e 100644
--- a/firmware/lib/cgptlib/include/cgptlib.h
+++ b/firmware/lib/cgptlib/include/cgptlib.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -21,6 +21,8 @@ enum {
GPT_ERROR_START_LBA_OVERLAP,
GPT_ERROR_END_LBA_OVERLAP,
GPT_ERROR_DUP_GUID,
+ /* Number of errors */
+ GPT_ERROR_COUNT
};
/* Bit masks for GptData.modified field. */
diff --git a/firmware/lib/cgptlib/include/cgptlib_internal.h b/firmware/lib/cgptlib/include/cgptlib_internal.h
index f899eab0..36e598c2 100644
--- a/firmware/lib/cgptlib/include/cgptlib_internal.h
+++ b/firmware/lib/cgptlib/include/cgptlib_internal.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -89,6 +89,15 @@ uint32_t HeaderCrc(GptHeader* h);
* Returns 0 if entries are valid, 1 if invalid. */
int CheckEntries(GptEntry* entries, GptHeader* h);
+/* Return 0 if the GptHeaders are the same for all fields which don't
+ * differ between the primary and secondary headers - that is, all
+ * fields other than:
+ *
+ * my_lba
+ * alternate_lba
+ * entries_lba */
+int HeaderFieldsSame(GptHeader *h1, GptHeader *h2);
+
/* Check GptData, headers, entries.
*
* If successful, sets gpt->valid_headers and gpt->valid_entries and returns
diff --git a/firmware/lib/include/vboot_common.h b/firmware/lib/include/vboot_common.h
index 76706bf6..fe886ce4 100644
--- a/firmware/lib/include/vboot_common.h
+++ b/firmware/lib/include/vboot_common.h
@@ -87,11 +87,6 @@ int VerifyData(const uint8_t* data, uint64_t size, const VbSignature* sig,
int VerifyDigest(const uint8_t* digest, const VbSignature *sig,
const RSAPublicKey* key);
-/* Uses [key] algorithm to hash [data], then compares that to the expected
- * [hash]. Returns 0 if they're equal, non-zero if error. */
-int EqualData(const uint8_t* data, uint64_t size, const VbSignature *hash,
- const RSAPublicKey* key);
-
/* Checks the sanity of a key block of size [size] bytes, using public
* key [key]. If hash_only is non-zero, uses only the block checksum
* to verify the key block. Header fields are also checked for
@@ -100,14 +95,6 @@ int KeyBlockVerify(const VbKeyBlockHeader* block, uint64_t size,
const VbPublicKey *key, int hash_only);
-/* Checks the sanity of an EC preamble of size [size] bytes,
- * using public key [key].
- *
- * Returns VBOOT_SUCCESS if successful. */
-int VerifyECPreamble(const VbECPreambleHeader* preamble,
- uint64_t size, const RSAPublicKey* key);
-
-
/* Checks the sanity of a firmware preamble of size [size] bytes,
* using public key [key].
*
diff --git a/firmware/lib/include/vboot_display.h b/firmware/lib/include/vboot_display.h
index 57688aed..b9ec04c0 100644
--- a/firmware/lib/include/vboot_display.h
+++ b/firmware/lib/include/vboot_display.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -19,5 +19,8 @@ VbError_t VbDisplayDebugInfo(VbCommonParams* cparams, VbNvContext *vncptr);
VbError_t VbCheckDisplayKey(VbCommonParams* cparams, uint32_t key,
VbNvContext *vncptr);
+/* Internal functions, for unit testing */
+const char *RecoveryReasonString(uint8_t code);
+
#endif /* VBOOT_REFERENCE_VBOOT_DISPLAY_H_ */
diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c
index ee89d7e6..82323235 100644
--- a/firmware/lib/rollback_index.c
+++ b/firmware/lib/rollback_index.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -39,246 +39,281 @@ __pragma(warning (disable: 4127))
} while (0)
-uint32_t TPMClearAndReenable(void) {
- VBDEBUG(("TPM: Clear and re-enable\n"));
- RETURN_ON_FAILURE(TlclForceClear());
- RETURN_ON_FAILURE(TlclSetEnable());
- RETURN_ON_FAILURE(TlclSetDeactivated(0));
+uint32_t TPMClearAndReenable(void)
+{
+ VBDEBUG(("TPM: Clear and re-enable\n"));
+ RETURN_ON_FAILURE(TlclForceClear());
+ RETURN_ON_FAILURE(TlclSetEnable());
+ RETURN_ON_FAILURE(TlclSetDeactivated(0));
- return TPM_SUCCESS;
+ return TPM_SUCCESS;
}
-
-uint32_t SafeWrite(uint32_t index, const void* data, uint32_t length) {
- uint32_t result = TlclWrite(index, data, length);
- if (result == TPM_E_MAXNVWRITES) {
- RETURN_ON_FAILURE(TPMClearAndReenable());
- return TlclWrite(index, data, length);
- } else {
- return result;
- }
+uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length)
+{
+ uint32_t result = TlclWrite(index, data, length);
+ if (result == TPM_E_MAXNVWRITES) {
+ RETURN_ON_FAILURE(TPMClearAndReenable());
+ return TlclWrite(index, data, length);
+ } else {
+ return result;
+ }
}
-
-uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size) {
- uint32_t result = TlclDefineSpace(index, perm, size);
- if (result == TPM_E_MAXNVWRITES) {
- RETURN_ON_FAILURE(TPMClearAndReenable());
- return TlclDefineSpace(index, perm, size);
- } else {
- return result;
- }
+uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
+{
+ uint32_t result = TlclDefineSpace(index, perm, size);
+ if (result == TPM_E_MAXNVWRITES) {
+ RETURN_ON_FAILURE(TPMClearAndReenable());
+ return TlclDefineSpace(index, perm, size);
+ } else {
+ return result;
+ }
}
-
/* Functions to read and write firmware and kernel spaces. */
-uint32_t ReadSpaceFirmware(RollbackSpaceFirmware* rsf) {
- uint32_t r;
- int attempts = 3;
-
- while (attempts--) {
- r = TlclRead(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware));
- if (r != TPM_SUCCESS)
- return r;
-
- /* No CRC in this version, so we'll create one when we write it. Note that
- * we're marking this as version 2, not ROLLBACK_SPACE_FIRMWARE_VERSION,
- * because version 2 just added the CRC. Later versions will need to
- * set default values for any extra fields explicitly (probably here). */
- if (rsf->struct_version < 2) {
- rsf->struct_version = 2; /* Danger Will Robinson! Danger! */
- return TPM_SUCCESS;
- }
-
- /* If the CRC is good, we're done. If it's bad, try a couple more times to
- * see if it gets better before we give up. It could just be noise. */
- if (rsf->crc8 == Crc8(rsf, offsetof(RollbackSpaceFirmware, crc8)))
- return TPM_SUCCESS;
-
- VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
- }
-
- VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
- return TPM_E_CORRUPTED_STATE;
+uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf)
+{
+ uint32_t r;
+ int attempts = 3;
+
+ while (attempts--) {
+ r = TlclRead(FIRMWARE_NV_INDEX, rsf,
+ sizeof(RollbackSpaceFirmware));
+ if (r != TPM_SUCCESS)
+ return r;
+
+ /*
+ * No CRC in this version, so we'll create one when we write
+ * it. Note that we're marking this as version 2, not
+ * ROLLBACK_SPACE_FIRMWARE_VERSION, because version 2 just
+ * added the CRC. Later versions will need to set default
+ * values for any extra fields explicitly (probably here).
+ */
+ if (rsf->struct_version < 2) {
+ /* Danger Will Robinson! Danger! */
+ rsf->struct_version = 2;
+ return TPM_SUCCESS;
+ }
+
+ /*
+ * If the CRC is good, we're done. If it's bad, try a couple
+ * more times to see if it gets better before we give up. It
+ * could just be noise.
+ */
+ if (rsf->crc8 == Crc8(rsf,
+ offsetof(RollbackSpaceFirmware, crc8)))
+ return TPM_SUCCESS;
+
+ VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
+ }
+
+ VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
+ return TPM_E_CORRUPTED_STATE;
}
-uint32_t WriteSpaceFirmware(RollbackSpaceFirmware* rsf) {
- RollbackSpaceFirmware rsf2;
- uint32_t r;
- int attempts = 3;
-
- /* All writes should use struct_version 2 or greater. */
- if (rsf->struct_version < 2)
- rsf->struct_version = 2;
- rsf->crc8 = Crc8(rsf, offsetof(RollbackSpaceFirmware, crc8));
-
- while (attempts--) {
- r = SafeWrite(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware));
- /* Can't write, not gonna try again */
- if (r != TPM_SUCCESS)
- return r;
-
- /* Read it back to be sure it got the right values. */
- r = ReadSpaceFirmware(&rsf2); /* This checks the CRC */
- if (r == TPM_SUCCESS)
- return r;
-
- VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
- /* Try writing it again. Maybe it was garbled on the way out. */
- }
-
- VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
- return TPM_E_CORRUPTED_STATE;
+uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf)
+{
+ RollbackSpaceFirmware rsf2;
+ uint32_t r;
+ int attempts = 3;
+
+ /* All writes should use struct_version 2 or greater. */
+ if (rsf->struct_version < 2)
+ rsf->struct_version = 2;
+ rsf->crc8 = Crc8(rsf, offsetof(RollbackSpaceFirmware, crc8));
+
+ while (attempts--) {
+ r = SafeWrite(FIRMWARE_NV_INDEX, rsf,
+ sizeof(RollbackSpaceFirmware));
+ /* Can't write, not gonna try again */
+ if (r != TPM_SUCCESS)
+ return r;
+
+ /* Read it back to be sure it got the right values. */
+ r = ReadSpaceFirmware(&rsf2); /* This checks the CRC */
+ if (r == TPM_SUCCESS)
+ return r;
+
+ VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
+ /* Try writing it again. Maybe it was garbled on the way out. */
+ }
+
+ VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
+ return TPM_E_CORRUPTED_STATE;
}
-uint32_t SetVirtualDevMode(int val) {
- RollbackSpaceFirmware rsf;
-
- VBDEBUG(("TPM: Entering %s()\n", __func__));
- if (TPM_SUCCESS != ReadSpaceFirmware(&rsf))
- return VBERROR_TPM_FIRMWARE_SETUP;
-
- VBDEBUG(("TPM: flags were 0x%02x\n", rsf.flags));
- if (val)
- rsf.flags |= FLAG_VIRTUAL_DEV_MODE_ON;
- else
- rsf.flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
- /* NOTE: This doesn't update the FLAG_LAST_BOOT_DEVELOPER bit */
- VBDEBUG(("TPM: flags are now 0x%02x\n", rsf.flags));
-
- if (TPM_SUCCESS != WriteSpaceFirmware(&rsf))
- return VBERROR_TPM_SET_BOOT_MODE_STATE;
-
- VBDEBUG(("TPM: Leaving %s()\n", __func__));
- return VBERROR_SUCCESS;
+uint32_t SetVirtualDevMode(int val)
+{
+ RollbackSpaceFirmware rsf;
+
+ VBDEBUG(("TPM: Entering %s()\n", __func__));
+ if (TPM_SUCCESS != ReadSpaceFirmware(&rsf))
+ return VBERROR_TPM_FIRMWARE_SETUP;
+
+ VBDEBUG(("TPM: flags were 0x%02x\n", rsf.flags));
+ if (val)
+ rsf.flags |= FLAG_VIRTUAL_DEV_MODE_ON;
+ else
+ rsf.flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
+ /*
+ * NOTE: This doesn't update the FLAG_LAST_BOOT_DEVELOPER bit. That
+ * will be done by SetupTPM() on the next boot.
+ */
+ VBDEBUG(("TPM: flags are now 0x%02x\n", rsf.flags));
+
+ if (TPM_SUCCESS != WriteSpaceFirmware(&rsf))
+ return VBERROR_TPM_SET_BOOT_MODE_STATE;
+
+ VBDEBUG(("TPM: Leaving %s()\n", __func__));
+ return VBERROR_SUCCESS;
}
-uint32_t ReadSpaceKernel(RollbackSpaceKernel* rsk) {
- uint32_t r;
- int attempts = 3;
-
- while (attempts--) {
- r = TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel));
- if (r != TPM_SUCCESS)
- return r;
-
- /* No CRC in this version, so we'll create one when we write it. Note that
- * we're marking this as version 2, not ROLLBACK_SPACE_KERNEL_VERSION,
- * because version 2 just added the CRC. Later versions will need to
- * set default values for any extra fields explicitly (probably here). */
- if (rsk->struct_version < 2) {
- rsk->struct_version = 2; /* Danger Will Robinson! Danger! */
- return TPM_SUCCESS;
- }
-
- /* If the CRC is good, we're done. If it's bad, try a couple more times to
- * see if it gets better before we give up. It could just be noise. */
- if (rsk->crc8 == Crc8(rsk, offsetof(RollbackSpaceKernel, crc8)))
- return TPM_SUCCESS;
-
- VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
- }
-
- VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
- return TPM_E_CORRUPTED_STATE;
+uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk)
+{
+ uint32_t r;
+ int attempts = 3;
+
+ while (attempts--) {
+ r = TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel));
+ if (r != TPM_SUCCESS)
+ return r;
+
+ /*
+ * No CRC in this version, so we'll create one when we write
+ * it. Note that we're marking this as version 2, not
+ * ROLLBACK_SPACE_KERNEL_VERSION, because version 2 just added
+ * the CRC. Later versions will need to set default values for
+ * any extra fields explicitly (probably here).
+ */
+ if (rsk->struct_version < 2) {
+ /* Danger Will Robinson! Danger! */
+ rsk->struct_version = 2;
+ return TPM_SUCCESS;
+ }
+
+ /*
+ * If the CRC is good, we're done. If it's bad, try a couple
+ * more times to see if it gets better before we give up. It
+ * could just be noise.
+ */
+ if (rsk->crc8 == Crc8(rsk, offsetof(RollbackSpaceKernel, crc8)))
+ return TPM_SUCCESS;
+
+ VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
+ }
+
+ VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
+ return TPM_E_CORRUPTED_STATE;
}
-uint32_t WriteSpaceKernel(RollbackSpaceKernel* rsk) {
- RollbackSpaceKernel rsk2;
- uint32_t r;
- int attempts = 3;
-
- /* All writes should use struct_version 2 or greater. */
- if (rsk->struct_version < 2)
- rsk->struct_version = 2;
- rsk->crc8 = Crc8(rsk, offsetof(RollbackSpaceKernel, crc8));
-
- while (attempts--) {
- r = SafeWrite(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel));
- /* Can't write, not gonna try again */
- if (r != TPM_SUCCESS)
- return r;
-
- /* Read it back to be sure it got the right values. */
- r = ReadSpaceKernel(&rsk2); /* This checks the CRC */
- if (r == TPM_SUCCESS)
- return r;
-
- VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
- /* Try writing it again. Maybe it was garbled on the way out. */
- }
-
- VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
- return TPM_E_CORRUPTED_STATE;
+uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk)
+{
+ RollbackSpaceKernel rsk2;
+ uint32_t r;
+ int attempts = 3;
+
+ /* All writes should use struct_version 2 or greater. */
+ if (rsk->struct_version < 2)
+ rsk->struct_version = 2;
+ rsk->crc8 = Crc8(rsk, offsetof(RollbackSpaceKernel, crc8));
+
+ while (attempts--) {
+ r = SafeWrite(KERNEL_NV_INDEX, rsk,
+ sizeof(RollbackSpaceKernel));
+ /* Can't write, not gonna try again */
+ if (r != TPM_SUCCESS)
+ return r;
+
+ /* Read it back to be sure it got the right values. */
+ r = ReadSpaceKernel(&rsk2); /* This checks the CRC */
+ if (r == TPM_SUCCESS)
+ return r;
+
+ VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
+ /* Try writing it again. Maybe it was garbled on the way out. */
+ }
+
+ VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
+ return TPM_E_CORRUPTED_STATE;
}
-
-uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware* rsf,
- RollbackSpaceKernel* rsk) {
- static const RollbackSpaceFirmware rsf_init = {
- .struct_version = ROLLBACK_SPACE_FIRMWARE_VERSION,
- };
- static const RollbackSpaceKernel rsk_init = {
- .struct_version = ROLLBACK_SPACE_KERNEL_VERSION,
- .uid = ROLLBACK_SPACE_KERNEL_UID,
- };
- TPM_PERMANENT_FLAGS pflags;
- uint32_t result;
-
- VBDEBUG(("TPM: One-time initialization\n"));
-
- /* Do a full test. This only happens the first time the device is turned on
- * in the factory, so performance is not an issue. This is almost certainly
- * not necessary, but it gives us more confidence about some code paths below
- * that are difficult to test---specifically the ones that set lifetime
- * flags, and are only executed once per physical TPM. */
- result = TlclSelfTestFull();
- if (result != TPM_SUCCESS)
- return result;
-
- result = TlclGetPermanentFlags(&pflags);
- if (result != TPM_SUCCESS)
- return result;
-
- /* TPM may come from the factory without physical presence finalized. Fix
- * if necessary. */
- VBDEBUG(("TPM: physicalPresenceLifetimeLock=%d\n",
- pflags.physicalPresenceLifetimeLock));
- if (!pflags.physicalPresenceLifetimeLock) {
- VBDEBUG(("TPM: Finalizing physical presence\n"));
- RETURN_ON_FAILURE(TlclFinalizePhysicalPresence());
- }
-
- /* The TPM will not enforce the NV authorization restrictions until the
- * execution of a TPM_NV_DefineSpace with the handle of TPM_NV_INDEX_LOCK.
- * Here we create that space if it doesn't already exist. */
- VBDEBUG(("TPM: nvLocked=%d\n", pflags.nvLocked));
- if (!pflags.nvLocked) {
- VBDEBUG(("TPM: Enabling NV locking\n"));
- RETURN_ON_FAILURE(TlclSetNvLocked());
- }
-
- /* Clear TPM owner, in case the TPM is already owned for some reason. */
- VBDEBUG(("TPM: Clearing owner\n"));
- RETURN_ON_FAILURE(TPMClearAndReenable());
-
- /* Initializes the firmware and kernel spaces */
- Memcpy(rsf, &rsf_init, sizeof(RollbackSpaceFirmware));
- Memcpy(rsk, &rsk_init, sizeof(RollbackSpaceKernel));
-
- /* Defines and sets firmware and kernel spaces */
- RETURN_ON_FAILURE(SafeDefineSpace(KERNEL_NV_INDEX, TPM_NV_PER_PPWRITE,
- sizeof(RollbackSpaceKernel)));
- RETURN_ON_FAILURE(WriteSpaceKernel(rsk));
- RETURN_ON_FAILURE(SafeDefineSpace(FIRMWARE_NV_INDEX,
- TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE,
- sizeof(RollbackSpaceFirmware)));
- RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
- return TPM_SUCCESS;
+uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf,
+ RollbackSpaceKernel *rsk)
+{
+ static const RollbackSpaceFirmware rsf_init = {
+ .struct_version = ROLLBACK_SPACE_FIRMWARE_VERSION,
+ };
+ static const RollbackSpaceKernel rsk_init = {
+ .struct_version = ROLLBACK_SPACE_KERNEL_VERSION,
+ .uid = ROLLBACK_SPACE_KERNEL_UID,
+ };
+ TPM_PERMANENT_FLAGS pflags;
+ uint32_t result;
+
+ VBDEBUG(("TPM: One-time initialization\n"));
+
+ /*
+ * Do a full test. This only happens the first time the device is
+ * turned on in the factory, so performance is not an issue. This is
+ * almost certainly not necessary, but it gives us more confidence
+ * about some code paths below that are difficult to
+ * test---specifically the ones that set lifetime flags, and are only
+ * executed once per physical TPM.
+ */
+ result = TlclSelfTestFull();
+ if (result != TPM_SUCCESS)
+ return result;
+
+ result = TlclGetPermanentFlags(&pflags);
+ if (result != TPM_SUCCESS)
+ return result;
+
+ /*
+ * TPM may come from the factory without physical presence finalized.
+ * Fix if necessary.
+ */
+ VBDEBUG(("TPM: physicalPresenceLifetimeLock=%d\n",
+ pflags.physicalPresenceLifetimeLock));
+ if (!pflags.physicalPresenceLifetimeLock) {
+ VBDEBUG(("TPM: Finalizing physical presence\n"));
+ RETURN_ON_FAILURE(TlclFinalizePhysicalPresence());
+ }
+
+ /*
+ * The TPM will not enforce the NV authorization restrictions until the
+ * execution of a TPM_NV_DefineSpace with the handle of
+ * TPM_NV_INDEX_LOCK. Here we create that space if it doesn't already
+ * exist. */
+ VBDEBUG(("TPM: nvLocked=%d\n", pflags.nvLocked));
+ if (!pflags.nvLocked) {
+ VBDEBUG(("TPM: Enabling NV locking\n"));
+ RETURN_ON_FAILURE(TlclSetNvLocked());
+ }
+
+ /* Clear TPM owner, in case the TPM is already owned for some reason. */
+ VBDEBUG(("TPM: Clearing owner\n"));
+ RETURN_ON_FAILURE(TPMClearAndReenable());
+
+ /* Initializes the firmware and kernel spaces */
+ Memcpy(rsf, &rsf_init, sizeof(RollbackSpaceFirmware));
+ Memcpy(rsk, &rsk_init, sizeof(RollbackSpaceKernel));
+
+ /* Defines and sets firmware and kernel spaces */
+ RETURN_ON_FAILURE(SafeDefineSpace(KERNEL_NV_INDEX, TPM_NV_PER_PPWRITE,
+ sizeof(RollbackSpaceKernel)));
+ RETURN_ON_FAILURE(WriteSpaceKernel(rsk));
+ RETURN_ON_FAILURE(SafeDefineSpace(
+ FIRMWARE_NV_INDEX,
+ TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE,
+ sizeof(RollbackSpaceFirmware)));
+ RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
+ return TPM_SUCCESS;
}
-/* SetupTPM starts the TPM and establishes the root of trust for the
+/*
+ * SetupTPM starts the TPM and establishes the root of trust for the
* anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a
* TPM hardware failure. 3 An unexpected TPM state due to some attack. In
* general we cannot easily distinguish the kind of failure, so our strategy is
@@ -299,38 +334,40 @@ uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware* rsf,
*/
uint32_t SetupTPM(int recovery_mode, int developer_mode,
int disable_dev_request, int clear_tpm_owner_request,
- RollbackSpaceFirmware* rsf) {
-
- uint8_t in_flags;
- uint8_t disable;
- uint8_t deactivated;
- uint32_t result;
+ RollbackSpaceFirmware* rsf)
+{
+ uint8_t in_flags;
+ uint8_t disable;
+ uint8_t deactivated;
+ uint32_t result;
- VBDEBUG(("TPM: SetupTPM(r%d, d%d)\n", recovery_mode, developer_mode));
+ VBDEBUG(("TPM: SetupTPM(r%d, d%d)\n", recovery_mode, developer_mode));
- if (recovery_mode)
- g_rollback_recovery_mode = 1; /* Global variables are usable in
- * recovery mode */
+ /* Global variables are usable in recovery mode */
+ if (recovery_mode)
+ g_rollback_recovery_mode = 1;
- RETURN_ON_FAILURE(TlclLibInit());
+ RETURN_ON_FAILURE(TlclLibInit());
#ifdef TEGRA_SOFT_REBOOT_WORKAROUND
- result = TlclStartup();
- if (result == TPM_E_INVALID_POSTINIT) {
- /* Some prototype hardware doesn't reset the TPM on a CPU reset. We do a
- * hard reset to get around this.
- */
- VBDEBUG(("TPM: soft reset detected\n", result));
- return TPM_E_MUST_REBOOT;
- } else if (result != TPM_SUCCESS) {
- VBDEBUG(("TPM: TlclStartup returned %08x\n", result));
- return result;
- }
+ result = TlclStartup();
+ if (result == TPM_E_INVALID_POSTINIT) {
+ /*
+ * Some prototype hardware doesn't reset the TPM on a CPU
+ * reset. We do a hard reset to get around this.
+ */
+ VBDEBUG(("TPM: soft reset detected\n", result));
+ return TPM_E_MUST_REBOOT;
+ } else if (result != TPM_SUCCESS) {
+ VBDEBUG(("TPM: TlclStartup returned %08x\n", result));
+ return result;
+ }
#else
- RETURN_ON_FAILURE(TlclStartup());
+ RETURN_ON_FAILURE(TlclStartup());
#endif
- /* Some TPMs start the self test automatically at power on. In that case we
+ /*
+ * Some TPMs start the self test automatically at power on. In that case we
* don't need to call ContinueSelfTest. On some (other) TPMs,
* ContinueSelfTest may block. In that case, we definitely don't want to
* call it here. For TPMs in the intersection of these two sets, we're
@@ -346,225 +383,249 @@ uint32_t SetupTPM(int recovery_mode, int developer_mode,
#ifdef TPM_BLOCKING_CONTINUESELFTEST
#warning "lousy TPM!"
#endif
- RETURN_ON_FAILURE(TlclContinueSelfTest());
+ RETURN_ON_FAILURE(TlclContinueSelfTest());
#endif
- result = TlclAssertPhysicalPresence();
- if (result != TPM_SUCCESS) {
- /* It is possible that the TPM was delivered with the physical presence
- * command disabled. This tries enabling it, then tries asserting PP
- * again.
- */
- RETURN_ON_FAILURE(TlclPhysicalPresenceCMDEnable());
- RETURN_ON_FAILURE(TlclAssertPhysicalPresence());
- }
-
- /* Checks that the TPM is enabled and activated. */
- RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated, NULL));
- if (disable || deactivated) {
- VBDEBUG(("TPM: disabled (%d) or deactivated (%d). Fixing...\n",
- disable, deactivated));
- RETURN_ON_FAILURE(TlclSetEnable());
- RETURN_ON_FAILURE(TlclSetDeactivated(0));
- VBDEBUG(("TPM: Must reboot to re-enable\n"));
- return TPM_E_MUST_REBOOT;
- }
-
- /* Reads the firmware space. */
- result = ReadSpaceFirmware(rsf);
- if (TPM_E_BADINDEX == result) {
- RollbackSpaceKernel rsk;
-
- /* This is the first time we've run, and the TPM has not been
- * initialized. This initializes it. */
- VBDEBUG(("TPM: Not initialized yet.\n"));
- RETURN_ON_FAILURE(OneTimeInitializeTPM(rsf, &rsk));
- } else if (TPM_SUCCESS != result) {
- VBDEBUG(("TPM: Firmware space in a bad state; giving up.\n"));
- return TPM_E_CORRUPTED_STATE;
- }
- VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n",
- rsf->struct_version, rsf->flags, rsf->fw_versions));
- in_flags = rsf->flags;
-
- /* If we've been asked to clear the virtual dev-mode flag, do so now */
- if (disable_dev_request) {
- rsf->flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
- VBDEBUG(("TPM: Clearing virt dev-switch: f%x\n", rsf->flags));
- }
-
- /* The developer_mode value that's passed in is only set by a hardware
- * dev-switch. We should OR it with the virtual switch, whether or not the
- * virtual switch is used. If it's not used, it shouldn't change, so it
- * doesn't matter. */
- if (rsf->flags & FLAG_VIRTUAL_DEV_MODE_ON)
- developer_mode = 1;
-
- /* Clears ownership if developer flag has toggled, or if an owner-clear has
- * been requested. */
- if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) !=
- (in_flags & FLAG_LAST_BOOT_DEVELOPER)) {
- VBDEBUG(("TPM: Developer flag changed; clearing owner.\n"));
- RETURN_ON_FAILURE(TPMClearAndReenable());
- } else if (clear_tpm_owner_request) {
- VBDEBUG(("TPM: Clearing owner as specifically requested.\n"));
- RETURN_ON_FAILURE(TPMClearAndReenable());
- }
-
- if (developer_mode)
- rsf->flags |= FLAG_LAST_BOOT_DEVELOPER;
- else
- rsf->flags &= ~FLAG_LAST_BOOT_DEVELOPER;
-
-
- /* If firmware space is dirty, this flushes it back to the TPM */
- if (rsf->flags != in_flags) {
- VBDEBUG(("TPM: Updating firmware space.\n"));
- RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
- }
-
- VBDEBUG(("TPM: SetupTPM() succeeded\n"));
- return TPM_SUCCESS;
+ result = TlclAssertPhysicalPresence();
+ if (result != TPM_SUCCESS) {
+ /*
+ * It is possible that the TPM was delivered with the physical
+ * presence command disabled. This tries enabling it, then
+ * tries asserting PP again.
+ */
+ RETURN_ON_FAILURE(TlclPhysicalPresenceCMDEnable());
+ RETURN_ON_FAILURE(TlclAssertPhysicalPresence());
+ }
+
+ /* Check that the TPM is enabled and activated. */
+ RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated, NULL));
+ if (disable || deactivated) {
+ VBDEBUG(("TPM: disabled (%d) or deactivated (%d). Fixing...\n",
+ disable, deactivated));
+ RETURN_ON_FAILURE(TlclSetEnable());
+ RETURN_ON_FAILURE(TlclSetDeactivated(0));
+ VBDEBUG(("TPM: Must reboot to re-enable\n"));
+ return TPM_E_MUST_REBOOT;
+ }
+
+ /* Read the firmware space. */
+ result = ReadSpaceFirmware(rsf);
+ if (TPM_E_BADINDEX == result) {
+ RollbackSpaceKernel rsk;
+
+ /*
+ * This is the first time we've run, and the TPM has not been
+ * initialized. Initialize it.
+ */
+ VBDEBUG(("TPM: Not initialized yet.\n"));
+ RETURN_ON_FAILURE(OneTimeInitializeTPM(rsf, &rsk));
+ } else if (TPM_SUCCESS != result) {
+ VBDEBUG(("TPM: Firmware space in a bad state; giving up.\n"));
+ return TPM_E_CORRUPTED_STATE;
+ }
+ VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n",
+ rsf->struct_version, rsf->flags, rsf->fw_versions));
+ in_flags = rsf->flags;
+
+ /* If we've been asked to clear the virtual dev-mode flag, do so now */
+ if (disable_dev_request) {
+ rsf->flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
+ VBDEBUG(("TPM: Clearing virt dev-switch: f%x\n", rsf->flags));
+ }
+
+ /*
+ * The developer_mode value that's passed in is only set by a hardware
+ * dev-switch. We should OR it with the virtual switch, whether or not
+ * the virtual switch is used. If it's not used, it shouldn't change,
+ * so it doesn't matter.
+ */
+ if (rsf->flags & FLAG_VIRTUAL_DEV_MODE_ON)
+ developer_mode = 1;
+
+ /*
+ * Clear ownership if developer flag has toggled, or if an owner-clear
+ * has been requested.
+ */
+ if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) !=
+ (in_flags & FLAG_LAST_BOOT_DEVELOPER)) {
+ VBDEBUG(("TPM: Developer flag changed; clearing owner.\n"));
+ RETURN_ON_FAILURE(TPMClearAndReenable());
+ } else if (clear_tpm_owner_request) {
+ VBDEBUG(("TPM: Clearing owner as specifically requested.\n"));
+ RETURN_ON_FAILURE(TPMClearAndReenable());
+ }
+
+ if (developer_mode)
+ rsf->flags |= FLAG_LAST_BOOT_DEVELOPER;
+ else
+ rsf->flags &= ~FLAG_LAST_BOOT_DEVELOPER;
+
+
+ /* If firmware space is dirty, flush it back to the TPM */
+ if (rsf->flags != in_flags) {
+ VBDEBUG(("TPM: Updating firmware space.\n"));
+ RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
+ }
+
+ VBDEBUG(("TPM: SetupTPM() succeeded\n"));
+ return TPM_SUCCESS;
}
-/* disable MSVC warnings on unused arguments */
+/* Disable MSVC warnings on unused arguments */
__pragma(warning (disable: 4100))
#ifdef DISABLE_ROLLBACK_TPM
-
/* Dummy implementations which don't support TPM rollback protection */
-uint32_t RollbackS3Resume(void) {
+uint32_t RollbackS3Resume(void)
+{
#ifndef CHROMEOS_ENVIRONMENT
- /* Initialize the TPM, but ignore return codes. In ChromeOS
- * environment, don't even talk to the TPM. */
- TlclLibInit();
- TlclResume();
+ /*
+ * Initialize the TPM, but ignore return codes. In ChromeOS
+ * environment, don't even talk to the TPM.
+ */
+ TlclLibInit();
+ TlclResume();
#endif
- return TPM_SUCCESS;
+ return TPM_SUCCESS;
}
uint32_t RollbackFirmwareSetup(int recovery_mode, int is_hw_dev,
int disable_dev_request,
int clear_tpm_owner_request,
- int *is_virt_dev, uint32_t *version) {
+ int *is_virt_dev, uint32_t *version)
+{
#ifndef CHROMEOS_ENVIRONMENT
- /* Initialize the TPM, but ignores return codes. In ChromeOS
- * environment, don't even talk to the TPM. */
- TlclLibInit();
- TlclStartup();
- TlclContinueSelfTest();
+ /*
+ * Initialize the TPM, but ignores return codes. In ChromeOS
+ * environment, don't even talk to the TPM.
+ */
+ TlclLibInit();
+ TlclStartup();
+ TlclContinueSelfTest();
#endif
- *version = 0;
- return TPM_SUCCESS;
-}
-
-uint32_t RollbackFirmwareRead(uint32_t* version) {
- *version = 0;
- return TPM_SUCCESS;
+ *is_virt_dev = 0;
+ *version = 0;
+ return TPM_SUCCESS;
}
-uint32_t RollbackFirmwareWrite(uint32_t version) {
- return TPM_SUCCESS;
+uint32_t RollbackFirmwareWrite(uint32_t version)
+{
+ return TPM_SUCCESS;
}
-uint32_t RollbackFirmwareLock(void) {
- return TPM_SUCCESS;
+uint32_t RollbackFirmwareLock(void)
+{
+ return TPM_SUCCESS;
}
-uint32_t RollbackKernelRead(uint32_t* version) {
- *version = 0;
- return TPM_SUCCESS;
+uint32_t RollbackKernelRead(uint32_t* version)
+{
+ *version = 0;
+ return TPM_SUCCESS;
}
-uint32_t RollbackKernelWrite(uint32_t version) {
- return TPM_SUCCESS;
+uint32_t RollbackKernelWrite(uint32_t version)
+{
+ return TPM_SUCCESS;
}
-uint32_t RollbackKernelLock(void) {
- return TPM_SUCCESS;
+uint32_t RollbackKernelLock(void)
+{
+ return TPM_SUCCESS;
}
#else
-uint32_t RollbackS3Resume(void) {
- uint32_t result;
- RETURN_ON_FAILURE(TlclLibInit());
- result = TlclResume();
- if (result == TPM_E_INVALID_POSTINIT) {
- /* We're on a platform where the TPM maintains power in S3, so
- it's already initialized. */
- return TPM_SUCCESS;
- }
- return result;
+uint32_t RollbackS3Resume(void)
+{
+ uint32_t result;
+ RETURN_ON_FAILURE(TlclLibInit());
+ result = TlclResume();
+ if (result == TPM_E_INVALID_POSTINIT) {
+ /*
+ * We're on a platform where the TPM maintains power in S3, so
+ * it's already initialized.
+ */
+ return TPM_SUCCESS;
+ }
+ return result;
}
uint32_t RollbackFirmwareSetup(int recovery_mode, int is_hw_dev,
int disable_dev_request,
int clear_tpm_owner_request,
- int *is_virt_dev, uint32_t *version) {
- RollbackSpaceFirmware rsf;
-
- /* Set version to 0 in case we fail */
- *version = 0;
-
- RETURN_ON_FAILURE(SetupTPM(recovery_mode, is_hw_dev, disable_dev_request,
- clear_tpm_owner_request, &rsf));
- *version = rsf.fw_versions;
- *is_virt_dev = (rsf.flags & FLAG_VIRTUAL_DEV_MODE_ON) ? 1 : 0;
- VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)rsf.fw_versions));
- return TPM_SUCCESS;
+ int *is_virt_dev, uint32_t *version)
+{
+ RollbackSpaceFirmware rsf;
+
+ /* Set version to 0 in case we fail */
+ *version = 0;
+
+ RETURN_ON_FAILURE(SetupTPM(recovery_mode, is_hw_dev,
+ disable_dev_request,
+ clear_tpm_owner_request, &rsf));
+ *version = rsf.fw_versions;
+ *is_virt_dev = (rsf.flags & FLAG_VIRTUAL_DEV_MODE_ON) ? 1 : 0;
+ VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)rsf.fw_versions));
+ return TPM_SUCCESS;
}
-uint32_t RollbackFirmwareWrite(uint32_t version) {
- RollbackSpaceFirmware rsf;
+uint32_t RollbackFirmwareWrite(uint32_t version)
+{
+ RollbackSpaceFirmware rsf;
- RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf));
- VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)rsf.fw_versions,
- (int)version));
- rsf.fw_versions = version;
- return WriteSpaceFirmware(&rsf);
+ RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf));
+ VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)rsf.fw_versions,
+ (int)version));
+ rsf.fw_versions = version;
+ return WriteSpaceFirmware(&rsf);
}
-uint32_t RollbackFirmwareLock(void) {
- return TlclSetGlobalLock();
+uint32_t RollbackFirmwareLock(void)
+{
+ return TlclSetGlobalLock();
}
-uint32_t RollbackKernelRead(uint32_t* version) {
- RollbackSpaceKernel rsk;
- uint32_t perms;
-
- /* Read the kernel space and verify its permissions. If the kernel
- * space has the wrong permission, or it doesn't contain the right
- * identifier, we give up. This will need to be fixed by the
- * recovery kernel. We have to worry about this because at any time
- * (even with PP turned off) the TPM owner can remove and redefine a
- * PP-protected space (but not write to it). */
- RETURN_ON_FAILURE(ReadSpaceKernel(&rsk));
- RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms));
- if (TPM_NV_PER_PPWRITE != perms || ROLLBACK_SPACE_KERNEL_UID != rsk.uid)
- return TPM_E_CORRUPTED_STATE;
-
- *version = rsk.kernel_versions;
- VBDEBUG(("TPM: RollbackKernelRead %x\n", (int)rsk.kernel_versions));
- return TPM_SUCCESS;
+uint32_t RollbackKernelRead(uint32_t* version)
+{
+ RollbackSpaceKernel rsk;
+ uint32_t perms;
+
+ /*
+ * Read the kernel space and verify its permissions. If the kernel
+ * space has the wrong permission, or it doesn't contain the right
+ * identifier, we give up. This will need to be fixed by the
+ * recovery kernel. We have to worry about this because at any time
+ * (even with PP turned off) the TPM owner can remove and redefine a
+ * PP-protected space (but not write to it).
+ */
+ RETURN_ON_FAILURE(ReadSpaceKernel(&rsk));
+ RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms));
+ if (TPM_NV_PER_PPWRITE != perms || ROLLBACK_SPACE_KERNEL_UID != rsk.uid)
+ return TPM_E_CORRUPTED_STATE;
+
+ *version = rsk.kernel_versions;
+ VBDEBUG(("TPM: RollbackKernelRead %x\n", (int)rsk.kernel_versions));
+ return TPM_SUCCESS;
}
-uint32_t RollbackKernelWrite(uint32_t version) {
- RollbackSpaceKernel rsk;
- RETURN_ON_FAILURE(ReadSpaceKernel(&rsk));
- VBDEBUG(("TPM: RollbackKernelWrite %x --> %x\n", (int)rsk.kernel_versions,
- (int)version));
- rsk.kernel_versions = version;
- return WriteSpaceKernel(&rsk);
+uint32_t RollbackKernelWrite(uint32_t version)
+{
+ RollbackSpaceKernel rsk;
+ RETURN_ON_FAILURE(ReadSpaceKernel(&rsk));
+ VBDEBUG(("TPM: RollbackKernelWrite %x --> %x\n",
+ (int)rsk.kernel_versions, (int)version));
+ rsk.kernel_versions = version;
+ return WriteSpaceKernel(&rsk);
}
-uint32_t RollbackKernelLock(void) {
- if (g_rollback_recovery_mode) {
- return TPM_SUCCESS;
- } else {
- return TlclLockPhysicalPresence();
- }
+uint32_t RollbackKernelLock(void)
+{
+ if (g_rollback_recovery_mode)
+ return TPM_SUCCESS;
+ else
+ return TlclLockPhysicalPresence();
}
-#endif // DISABLE_ROLLBACK_TPM
+#endif /* DISABLE_ROLLBACK_TPM */
diff --git a/firmware/lib/vboot_common.c b/firmware/lib/vboot_common.c
index 7878701f..bf79b81f 100644
--- a/firmware/lib/vboot_common.c
+++ b/firmware/lib/vboot_common.c
@@ -173,28 +173,6 @@ int VerifyDigest(const uint8_t* digest, const VbSignature *sig,
}
-int EqualData(const uint8_t* data, uint64_t size, const VbSignature *hash,
- const RSAPublicKey* key) {
- uint8_t* digest = NULL;
- int rv;
-
- if (hash->sig_size != hash_size_map[key->algorithm]) {
- VBDEBUG(("Wrong hash size for algorithm.\n"));
- return 1;
- }
- if (hash->data_size > size) {
- VBDEBUG(("Data buffer smaller than length of signed data.\n"));
- return 1;
- }
-
- digest = DigestBuf(data, hash->data_size, key->algorithm);
-
- rv = SafeMemcmp(digest, GetSignatureDataC(hash), hash->sig_size);
- VbExFree(digest);
- return rv;
-}
-
-
int KeyBlockVerify(const VbKeyBlockHeader* block, uint64_t size,
const VbPublicKey *key, int hash_only) {
@@ -313,63 +291,6 @@ int KeyBlockVerify(const VbKeyBlockHeader* block, uint64_t size,
return VBOOT_SUCCESS;
}
-
-int VerifyECPreamble(const VbECPreambleHeader* preamble,
- uint64_t size, const RSAPublicKey* key) {
-
- const VbSignature* sig = &preamble->preamble_signature;
-
- /* Sanity checks before attempting signature of data */
- if(size < EXPECTED_VB_EC_PREAMBLE_HEADER1_0_SIZE) {
- VBDEBUG(("Not enough data for EC preamble header.\n"));
- return VBOOT_PREAMBLE_INVALID;
- }
- if (preamble->header_version_major !=
- EC_PREAMBLE_HEADER_VERSION_MAJOR) {
- VBDEBUG(("Incompatible EC preamble header version (%d, not %d).\n",
- preamble->header_version_major,
- EC_PREAMBLE_HEADER_VERSION_MAJOR));
- return VBOOT_PREAMBLE_INVALID;
- }
- if (size < preamble->preamble_size) {
- VBDEBUG(("Not enough data for EC preamble.\n"));
- return VBOOT_PREAMBLE_INVALID;
- }
-
- /* Check signature */
- if (VerifySignatureInside(preamble, preamble->preamble_size, sig)) {
- VBDEBUG(("EC preamble signature off end of preamble\n"));
- return VBOOT_PREAMBLE_INVALID;
- }
-
- /* Make sure advertised signature data sizes are sane. */
- if (preamble->preamble_size < sig->data_size) {
- VBDEBUG(("EC signature calculated past end of the block\n"));
- return VBOOT_PREAMBLE_INVALID;
- }
-
- if (VerifyData((const uint8_t*)preamble, size, sig, key)) {
- VBDEBUG(("EC preamble signature validation failed\n"));
- return VBOOT_PREAMBLE_SIGNATURE;
- }
-
- /* Verify we signed enough data */
- if (sig->data_size < sizeof(VbFirmwarePreambleHeader)) {
- VBDEBUG(("Didn't sign enough data\n"));
- return VBOOT_PREAMBLE_INVALID;
- }
-
- /* Verify body digest is inside the signed data */
- if (VerifySignatureInside(preamble, sig->data_size,
- &preamble->body_digest)) {
- VBDEBUG(("EC body digest off end of preamble\n"));
- return VBOOT_PREAMBLE_INVALID;
- }
-
- /* Success */
- return VBOOT_SUCCESS;
-}
-
int VerifyFirmwarePreamble(const VbFirmwarePreambleHeader* preamble,
uint64_t size, const RSAPublicKey* key) {
diff --git a/firmware/lib/vboot_display.c b/firmware/lib/vboot_display.c
index d0250bf3..929cacc2 100644
--- a/firmware/lib/vboot_display.c
+++ b/firmware/lib/vboot_display.c
@@ -402,8 +402,7 @@ static void FillInSha1Sum(char *outbuf, VbPublicKey* key) {
VbExFree(digest);
}
-
-static const char *RecoveryReasonString(uint8_t code) {
+const char *RecoveryReasonString(uint8_t code) {
switch(code) {
case VBNV_RECOVERY_NOT_REQUESTED:
return "Recovery not requested";
diff --git a/futility/futility.c b/futility/futility.c
index a6a8aa39..483f4521 100644
--- a/futility/futility.c
+++ b/futility/futility.c
@@ -6,25 +6,24 @@
#define _GNU_SOURCE
#include <errno.h>
+#include <fcntl.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
#include <unistd.h>
#include "futility.h"
-/* #define DEBUG 1 */
-#ifdef DEBUG
-#define debug(args...) printf(args)
-#else
-#define debug(args...)
-#endif
-
#define MYNAME "futility"
#define SUBDIR "old_bins"
+#define LOGFILE "/tmp/futility.log"
+
+/******************************************************************************/
+
static const char * const usage= "\n\
Usage: " MYNAME " PROGRAM|COMMAND [args...]\n\
\n\
@@ -70,6 +69,81 @@ static int help(int argc, char *argv[])
DECLARE_FUTIL_COMMAND(help, help, "Show a bit of help");
+/******************************************************************************/
+/* Logging stuff */
+
+static int log_fd = -1;
+
+/* Write the string and a newline. Silently give up on errors */
+static void log_str(char *str)
+{
+ int len, done, n;
+
+ if (log_fd < 0)
+ return;
+
+ if (!str)
+ str = "(NULL)";
+
+ len = strlen(str);
+ if (len == 0) {
+ str = "(EMPTY)";
+ len = strlen(str);
+ }
+
+ for (done = 0; done < len; done += n) {
+ n = write(log_fd, str+done, len-done);
+ if (n < 0)
+ return;
+ }
+
+ write(log_fd, "\n", 1);
+}
+
+static void log_close(void)
+{
+ if (log_fd >= 0)
+ close(log_fd);
+ log_fd = -1;
+}
+
+static void log_open(void)
+{
+ struct flock lock;
+ int ret;
+
+ log_fd = open(LOGFILE, O_WRONLY|O_APPEND|O_CREAT, 0666);
+ if (log_fd < 0) {
+
+ if (errno != EACCES)
+ return;
+
+ /* Permission problems should improve shortly ... */
+ sleep(1);
+ log_fd = open(LOGFILE, O_WRONLY|O_APPEND|O_CREAT, 0666);
+ if (log_fd < 0) /* Nope, they didn't */
+ return;
+ }
+
+ /* Let anyone have a turn */
+ fchmod(log_fd, 0666);
+
+ /* But only one at a time */
+ memset(&lock, 0, sizeof(lock));
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_END;
+
+ ret = fcntl(log_fd, F_SETLKW, &lock); /* this blocks */
+ if (ret < 0)
+ log_close();
+
+ /* delimiter */
+ log_str("##### HEY #####");
+}
+
+/******************************************************************************/
+/* Here we go */
+
int main(int argc, char *argv[], char *envp[])
{
char *progname;
@@ -82,8 +156,9 @@ int main(int argc, char *argv[], char *envp[])
int i;
futil_cmd_t *cmd;
+ log_open();
for (i = 0; i < argc; i++)
- debug("argv[%d] = %s\n", i, argv[i]);
+ log_str(argv[i]);
/* How were we invoked? */
progname = strrchr(argv[0], '/');
@@ -91,7 +166,6 @@ int main(int argc, char *argv[], char *envp[])
progname++;
else
progname = argv[0];
- debug("progname is %s\n", progname);
/* Invoked directly by name */
if (0 == strcmp(progname, MYNAME)) {
@@ -110,7 +184,6 @@ int main(int argc, char *argv[], char *envp[])
progname++;
else
progname = argv[0];
- debug("now progname is %s\n", progname);
}
/* See if it's asking for something we know how to do ourselves */
@@ -129,7 +202,6 @@ int main(int argc, char *argv[], char *envp[])
buf, strerror(errno));
exit(1);
}
- debug("truename is %s\n", truename);
s = strrchr(truename, '/'); /* Find the true directory */
if (s) {
*s = '\0';
@@ -140,10 +212,6 @@ int main(int argc, char *argv[], char *envp[])
/* We've allocated PATH_MAX. If the old binary path doesn't fit, it can't be
* in the filesystem. */
snprintf(oldname, PATH_MAX, "%s/%s/%s", truename, SUBDIR, progname);
- debug("oldname is %s\n", oldname);
-
- for (i = 0; i < argc; i++)
- debug("argv[%d] = %s\n", i, argv[i]);
fflush(0);
execve(oldname, argv, envp);
diff --git a/host/arch/amd64/lib/crossystem_arch.c b/host/arch/x86_64/lib/crossystem_arch.c
index 1f5d6522..1f5d6522 120000
--- a/host/arch/amd64/lib/crossystem_arch.c
+++ b/host/arch/x86_64/lib/crossystem_arch.c
diff --git a/tests/cgptlib_test.c b/tests/cgptlib_test.c
index 3402ac85..b48543f3 100644
--- a/tests/cgptlib_test.c
+++ b/tests/cgptlib_test.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -13,7 +13,8 @@
#include "test_common.h"
#include "utility.h"
-/* Testing partition layout (sector_bytes=512)
+/*
+ * Testing partition layout (sector_bytes=512)
*
* LBA Size Usage
* ---------------------------------------------------------
@@ -44,1217 +45,1396 @@ static const Guid guid_zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
static const Guid guid_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
static const Guid guid_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
-/* Copy a random-for-this-program-only Guid into the dest. The num parameter
+/*
+ * Copy a random-for-this-program-only Guid into the dest. The num parameter
* completely determines the Guid.
*/
-static void SetGuid(void *dest, uint32_t num) {
- Guid g = {{{num,0xd450,0x44bc,0xa6,0x93,{0xb8,0xac,0x75,0x5f,0xcd,0x48}}}};
- Memcpy(dest, &g, sizeof(Guid));
+static void SetGuid(void *dest, uint32_t num)
+{
+ Guid g = {{{num,0xd450,0x44bc,0xa6,0x93,
+ {0xb8,0xac,0x75,0x5f,0xcd,0x48}}}};
+ Memcpy(dest, &g, sizeof(Guid));
}
-/* Given a GptData pointer, first re-calculate entries CRC32 value,
- * then reset header CRC32 value to 0, and calculate header CRC32 value.
- * Both primary and secondary are updated. */
-static void RefreshCrc32(GptData* gpt) {
- GptHeader *header, *header2;
- GptEntry *entries, *entries2;
-
- header = (GptHeader*)gpt->primary_header;
- entries = (GptEntry*)gpt->primary_entries;
- header2 = (GptHeader*)gpt->secondary_header;
- entries2 = (GptEntry*)gpt->secondary_entries;
-
- header->entries_crc32 =
- Crc32((uint8_t*)entries,
- header->number_of_entries * header->size_of_entry);
- header->header_crc32 = 0;
- header->header_crc32 = Crc32((uint8_t*)header, header->size);
- header2->entries_crc32 =
- Crc32((uint8_t*)entries2,
- header2->number_of_entries * header2->size_of_entry);
- header2->header_crc32 = 0;
- header2->header_crc32 = Crc32((uint8_t*)header2, header2->size);
+/*
+ * Given a GptData pointer, first re-calculate entries CRC32 value, then reset
+ * header CRC32 value to 0, and calculate header CRC32 value. Both primary and
+ * secondary are updated.
+ */
+static void RefreshCrc32(GptData *gpt)
+{
+ GptHeader *header, *header2;
+ GptEntry *entries, *entries2;
+
+ header = (GptHeader *)gpt->primary_header;
+ entries = (GptEntry *)gpt->primary_entries;
+ header2 = (GptHeader *)gpt->secondary_header;
+ entries2 = (GptEntry *)gpt->secondary_entries;
+
+ header->entries_crc32 =
+ Crc32((uint8_t *)entries,
+ header->number_of_entries * header->size_of_entry);
+ header->header_crc32 = 0;
+ header->header_crc32 = Crc32((uint8_t *)header, header->size);
+ header2->entries_crc32 =
+ Crc32((uint8_t *)entries2,
+ header2->number_of_entries * header2->size_of_entry);
+ header2->header_crc32 = 0;
+ header2->header_crc32 = Crc32((uint8_t *)header2, header2->size);
}
-
-static void ZeroHeaders(GptData* gpt) {
- Memset(gpt->primary_header, 0, MAX_SECTOR_SIZE);
- Memset(gpt->secondary_header, 0, MAX_SECTOR_SIZE);
+static void ZeroHeaders(GptData *gpt)
+{
+ Memset(gpt->primary_header, 0, MAX_SECTOR_SIZE);
+ Memset(gpt->secondary_header, 0, MAX_SECTOR_SIZE);
}
-
-static void ZeroEntries(GptData* gpt) {
- Memset(gpt->primary_entries, 0, PARTITION_ENTRIES_SIZE);
- Memset(gpt->secondary_entries, 0, PARTITION_ENTRIES_SIZE);
+static void ZeroEntries(GptData *gpt)
+{
+ Memset(gpt->primary_entries, 0, PARTITION_ENTRIES_SIZE);
+ Memset(gpt->secondary_entries, 0, PARTITION_ENTRIES_SIZE);
}
-
-static void ZeroHeadersEntries(GptData* gpt) {
- ZeroHeaders(gpt);
- ZeroEntries(gpt);
+static void ZeroHeadersEntries(GptData *gpt)
+{
+ ZeroHeaders(gpt);
+ ZeroEntries(gpt);
}
-
-/* Returns a pointer to a static GptData instance (no free is required).
+/*
+ * Return a pointer to a static GptData instance (no free is required).
* All fields are zero except 4 pointers linking to header and entries.
- * All content of headers and entries are zero. */
-static GptData* GetEmptyGptData() {
- static GptData gpt;
- static uint8_t primary_header[MAX_SECTOR_SIZE];
- static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
- static uint8_t secondary_header[MAX_SECTOR_SIZE];
- static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
-
- Memset(&gpt, 0, sizeof(gpt));
- gpt.primary_header = primary_header;
- gpt.primary_entries = primary_entries;
- gpt.secondary_header = secondary_header;
- gpt.secondary_entries = secondary_entries;
- ZeroHeadersEntries(&gpt);
-
- /* Initialize GptData internal states. */
- gpt.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
-
- return &gpt;
+ * All content of headers and entries are zero.
+ */
+static GptData *GetEmptyGptData(void)
+{
+ static GptData gpt;
+ static uint8_t primary_header[MAX_SECTOR_SIZE];
+ static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
+ static uint8_t secondary_header[MAX_SECTOR_SIZE];
+ static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
+
+ Memset(&gpt, 0, sizeof(gpt));
+ gpt.primary_header = primary_header;
+ gpt.primary_entries = primary_entries;
+ gpt.secondary_header = secondary_header;
+ gpt.secondary_entries = secondary_entries;
+ ZeroHeadersEntries(&gpt);
+
+ /* Initialize GptData internal states. */
+ gpt.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
+
+ return &gpt;
}
-
-/* Fills in most of fields and creates the layout described in the top of this
+/*
+ * Fill in most of fields and creates the layout described in the top of this
* file. Before calling this function, primary/secondary header/entries must
* have been pointed to the buffer, say, a gpt returned from GetEmptyGptData().
* This function returns a good (valid) copy of GPT layout described in top of
- * this file. */
-static void BuildTestGptData(GptData* gpt) {
- GptHeader *header, *header2;
- GptEntry *entries, *entries2;
- Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
- Guid chromeos_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
-
- gpt->sector_bytes = DEFAULT_SECTOR_SIZE;
- gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
- gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
- gpt->valid_headers = MASK_BOTH;
- gpt->valid_entries = MASK_BOTH;
- gpt->modified = 0;
-
- /* build primary */
- header = (GptHeader*)gpt->primary_header;
- entries = (GptEntry*)gpt->primary_entries;
- Memcpy(header->signature, GPT_HEADER_SIGNATURE,
- sizeof(GPT_HEADER_SIGNATURE));
- header->revision = GPT_HEADER_REVISION;
- header->size = sizeof(GptHeader);
- header->reserved_zero = 0;
- header->my_lba = 1;
- header->alternate_lba = DEFAULT_DRIVE_SECTORS - 1;
- header->first_usable_lba = 34;
- header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
- header->entries_lba = 2;
- header->number_of_entries = 128; /* 512B / 128B * 32sectors = 128 entries */
- header->size_of_entry = 128; /* bytes */
- Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
- SetGuid(&entries[0].unique, 0);
- entries[0].starting_lba = 34;
- entries[0].ending_lba = 133;
- Memcpy(&entries[1].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
- SetGuid(&entries[1].unique, 1);
- entries[1].starting_lba = 134;
- entries[1].ending_lba = 232;
- Memcpy(&entries[2].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
- SetGuid(&entries[2].unique, 2);
- entries[2].starting_lba = 234;
- entries[2].ending_lba = 331;
- Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
- SetGuid(&entries[3].unique, 3);
- entries[3].starting_lba = 334;
- entries[3].ending_lba = 430;
-
- /* build secondary */
- header2 = (GptHeader*)gpt->secondary_header;
- entries2 = (GptEntry*)gpt->secondary_entries;
- Memcpy(header2, header, sizeof(GptHeader));
- Memcpy(entries2, entries, PARTITION_ENTRIES_SIZE);
- header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
- header2->alternate_lba = 1;
- header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
-
- RefreshCrc32(gpt);
+ * this file.
+ */
+static void BuildTestGptData(GptData *gpt)
+{
+ GptHeader *header, *header2;
+ GptEntry *entries, *entries2;
+ Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
+ Guid chromeos_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
+
+ gpt->sector_bytes = DEFAULT_SECTOR_SIZE;
+ gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
+ gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
+ gpt->valid_headers = MASK_BOTH;
+ gpt->valid_entries = MASK_BOTH;
+ gpt->modified = 0;
+
+ /* Build primary */
+ header = (GptHeader *)gpt->primary_header;
+ entries = (GptEntry *)gpt->primary_entries;
+ Memcpy(header->signature, GPT_HEADER_SIGNATURE,
+ sizeof(GPT_HEADER_SIGNATURE));
+ header->revision = GPT_HEADER_REVISION;
+ header->size = sizeof(GptHeader);
+ header->reserved_zero = 0;
+ header->my_lba = 1;
+ header->alternate_lba = DEFAULT_DRIVE_SECTORS - 1;
+ header->first_usable_lba = 34;
+ header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
+ header->entries_lba = 2;
+ /* 512B / 128B * 32sectors = 128 entries */
+ header->number_of_entries = 128;
+ header->size_of_entry = 128; /* bytes */
+ Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
+ SetGuid(&entries[0].unique, 0);
+ entries[0].starting_lba = 34;
+ entries[0].ending_lba = 133;
+ Memcpy(&entries[1].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
+ SetGuid(&entries[1].unique, 1);
+ entries[1].starting_lba = 134;
+ entries[1].ending_lba = 232;
+ Memcpy(&entries[2].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
+ SetGuid(&entries[2].unique, 2);
+ entries[2].starting_lba = 234;
+ entries[2].ending_lba = 331;
+ Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
+ SetGuid(&entries[3].unique, 3);
+ entries[3].starting_lba = 334;
+ entries[3].ending_lba = 430;
+
+ /* Build secondary */
+ header2 = (GptHeader *)gpt->secondary_header;
+ entries2 = (GptEntry *)gpt->secondary_entries;
+ Memcpy(header2, header, sizeof(GptHeader));
+ Memcpy(entries2, entries, PARTITION_ENTRIES_SIZE);
+ header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
+ header2->alternate_lba = 1;
+ header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
+
+ RefreshCrc32(gpt);
}
-/* Tests if the structures are the expected size; if this fails,
- * struct packing is not working properly. */
-static int StructSizeTest() {
-
- EXPECT(GUID_EXPECTED_SIZE == sizeof(Guid));
- EXPECT(GPTHEADER_EXPECTED_SIZE == sizeof(GptHeader));
- EXPECT(GPTENTRY_EXPECTED_SIZE == sizeof(GptEntry));
+/*
+ * Test if the structures are the expected size; if this fails, struct packing
+ * is not working properly.
+ */
+static int StructSizeTest(void)
+{
- return TEST_OK;
+ EXPECT(GUID_EXPECTED_SIZE == sizeof(Guid));
+ EXPECT(GPTHEADER_EXPECTED_SIZE == sizeof(GptHeader));
+ EXPECT(GPTENTRY_EXPECTED_SIZE == sizeof(GptEntry));
+ return TEST_OK;
}
-/* Tests if the default structure returned by BuildTestGptData() is good. */
-static int TestBuildTestGptData() {
- GptData* gpt;
+/* Test if the default structure returned by BuildTestGptData() is good. */
+static int TestBuildTestGptData(void)
+{
+ GptData *gpt;
- gpt = GetEmptyGptData();
- BuildTestGptData(gpt);
- EXPECT(GPT_SUCCESS == GptInit(gpt));
- return TEST_OK;
+ gpt = GetEmptyGptData();
+ BuildTestGptData(gpt);
+ EXPECT(GPT_SUCCESS == GptInit(gpt));
+ gpt->sector_bytes = 0;
+ EXPECT(GPT_ERROR_INVALID_SECTOR_SIZE == GptInit(gpt));
+ return TEST_OK;
}
-
-/* Tests if wrong sector_bytes or drive_sectors is detected by GptInit().
- * Currently we only support 512 bytes per sector.
- * In the future, we may support other sizes.
- * A too small drive_sectors should be rejected by GptInit(). */
-static int ParameterTests() {
- GptData* gpt;
- struct {
- uint32_t sector_bytes;
- uint64_t drive_sectors;
- int expected_retval;
- } cases[] = {
- {512, DEFAULT_DRIVE_SECTORS, GPT_SUCCESS},
- {520, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
- {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER},
- {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER},
- {512, GPT_PMBR_SECTOR + GPT_HEADER_SECTOR * 2 + GPT_ENTRIES_SECTORS * 2,
- GPT_SUCCESS},
- {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
- };
- int i;
-
- gpt = GetEmptyGptData();
- for (i = 0; i < ARRAY_SIZE(cases); ++i) {
- BuildTestGptData(gpt);
- gpt->sector_bytes = cases[i].sector_bytes;
- gpt->drive_sectors = cases[i].drive_sectors;
- EXPECT(cases[i].expected_retval == CheckParameters(gpt));
- }
-
- return TEST_OK;
+/*
+ * Test if wrong sector_bytes or drive_sectors is detected by GptInit().
+ * Currently we only support 512 bytes per sector. In the future, we may
+ * support other sizes. A too small drive_sectors should be rejected by
+ * GptInit().
+ */
+static int ParameterTests(void)
+{
+ GptData *gpt;
+ struct {
+ uint32_t sector_bytes;
+ uint64_t drive_sectors;
+ int expected_retval;
+ } cases[] = {
+ {512, DEFAULT_DRIVE_SECTORS, GPT_SUCCESS},
+ {520, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
+ {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER},
+ {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER},
+ {512, GPT_PMBR_SECTOR + GPT_HEADER_SECTOR * 2 +
+ GPT_ENTRIES_SECTORS * 2, GPT_SUCCESS},
+ {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
+ };
+ int i;
+
+ gpt = GetEmptyGptData();
+ for (i = 0; i < ARRAY_SIZE(cases); ++i) {
+ BuildTestGptData(gpt);
+ gpt->sector_bytes = cases[i].sector_bytes;
+ gpt->drive_sectors = cases[i].drive_sectors;
+ EXPECT(cases[i].expected_retval == CheckParameters(gpt));
+ }
+
+ return TEST_OK;
}
+/* Test if header CRC in two copies are calculated. */
+static int HeaderCrcTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
-/* Tests if header CRC in two copies are calculated. */
-static int HeaderCrcTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
+ BuildTestGptData(gpt);
+ EXPECT(HeaderCrc(h1) == h1->header_crc32);
- BuildTestGptData(gpt);
- EXPECT(HeaderCrc(h1) == h1->header_crc32);
+ /* CRC covers first byte of header */
+ BuildTestGptData(gpt);
+ gpt->primary_header[0] ^= 0xa5;
+ EXPECT(HeaderCrc(h1) != h1->header_crc32);
- /* CRC covers first byte of header */
- BuildTestGptData(gpt);
- gpt->primary_header[0] ^= 0xa5;
- EXPECT(HeaderCrc(h1) != h1->header_crc32);
+ /* CRC covers last byte of header */
+ BuildTestGptData(gpt);
+ gpt->primary_header[h1->size - 1] ^= 0x5a;
+ EXPECT(HeaderCrc(h1) != h1->header_crc32);
- /* CRC covers last byte of header */
- BuildTestGptData(gpt);
- gpt->primary_header[h1->size - 1] ^= 0x5a;
- EXPECT(HeaderCrc(h1) != h1->header_crc32);
+ /* CRC only covers header */
+ BuildTestGptData(gpt);
+ gpt->primary_header[h1->size] ^= 0x5a;
+ EXPECT(HeaderCrc(h1) == h1->header_crc32);
- /* CRC only covers header */
- BuildTestGptData(gpt);
- gpt->primary_header[h1->size] ^= 0x5a;
- EXPECT(HeaderCrc(h1) == h1->header_crc32);
-
- return TEST_OK;
+ return TEST_OK;
}
+/* Test if header-same comparison works. */
+static int HeaderSameTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptHeader *h2 = (GptHeader *)gpt->secondary_header;
+ GptHeader h3;
-/* Tests if signature ("EFI PART") is checked. */
-static int SignatureTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
- GptHeader* h2 = (GptHeader*)gpt->secondary_header;
- int i;
+ EXPECT(0 == HeaderFieldsSame(h1, h2));
- for (i = 0; i < 8; ++i) {
- BuildTestGptData(gpt);
- h1->signature[i] ^= 0xff;
- h2->signature[i] ^= 0xff;
- RefreshCrc32(gpt);
- EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
- EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
- }
+ Memcpy(&h3, h2, sizeof(h3));
+ h3.signature[0] ^= 0xba;
+ EXPECT(1 == HeaderFieldsSame(h1, &h3));
- return TEST_OK;
-}
+ Memcpy(&h3, h2, sizeof(h3));
+ h3.revision++;
+ EXPECT(1 == HeaderFieldsSame(h1, &h3));
+ Memcpy(&h3, h2, sizeof(h3));
+ h3.size++;
+ EXPECT(1 == HeaderFieldsSame(h1, &h3));
-/* The revision we currently support is GPT_HEADER_REVISION.
- * If the revision in header is not that, we expect the header is invalid. */
-static int RevisionTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
- GptHeader* h2 = (GptHeader*)gpt->secondary_header;
- int i;
-
- struct {
- uint32_t value_to_test;
- int expect_rv;
- } cases[] = {
- {0x01000000, 1},
- {0x00010000, 0}, /* GPT_HEADER_REVISION */
- {0x00000100, 1},
- {0x00000001, 1},
- {0x23010456, 1},
- };
-
- for (i = 0; i < ARRAY_SIZE(cases); ++i) {
- BuildTestGptData(gpt);
- h1->revision = cases[i].value_to_test;
- h2->revision = cases[i].value_to_test;
- RefreshCrc32(gpt);
-
- EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) == cases[i].expect_rv);
- EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) == cases[i].expect_rv);
- }
- return TEST_OK;
-}
+ Memcpy(&h3, h2, sizeof(h3));
+ h3.reserved_zero++;
+ EXPECT(1 == HeaderFieldsSame(h1, &h3));
+ Memcpy(&h3, h2, sizeof(h3));
+ h3.first_usable_lba++;
+ EXPECT(1 == HeaderFieldsSame(h1, &h3));
-static int SizeTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
- GptHeader* h2 = (GptHeader*)gpt->secondary_header;
- int i;
-
- struct {
- uint32_t value_to_test;
- int expect_rv;
- } cases[] = {
- {91, 1},
- {92, 0},
- {93, 0},
- {511, 0},
- {512, 0},
- {513, 1},
- };
-
- for (i = 0; i < ARRAY_SIZE(cases); ++i) {
- BuildTestGptData(gpt);
- h1->size = cases[i].value_to_test;
- h2->size = cases[i].value_to_test;
- RefreshCrc32(gpt);
-
- EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) == cases[i].expect_rv);
- EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) == cases[i].expect_rv);
- }
- return TEST_OK;
-}
+ Memcpy(&h3, h2, sizeof(h3));
+ h3.last_usable_lba++;
+ EXPECT(1 == HeaderFieldsSame(h1, &h3));
+ Memcpy(&h3, h2, sizeof(h3));
+ h3.disk_uuid.u.raw[0] ^= 0xba;
+ EXPECT(1 == HeaderFieldsSame(h1, &h3));
-/* Tests if CRC is checked. */
-static int CrcFieldTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
- GptHeader* h2 = (GptHeader*)gpt->secondary_header;
-
- BuildTestGptData(gpt);
- /* Modify a field that the header verification doesn't care about */
- h1->entries_crc32++;
- h2->entries_crc32++;
- EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
- EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
- /* Refresh the CRC; should pass now */
- RefreshCrc32(gpt);
- EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
- EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
-
- return TEST_OK;
-}
+ Memcpy(&h3, h2, sizeof(h3));
+ h3.number_of_entries++;
+ EXPECT(1 == HeaderFieldsSame(h1, &h3));
+ Memcpy(&h3, h2, sizeof(h3));
+ h3.size_of_entry++;
+ EXPECT(1 == HeaderFieldsSame(h1, &h3));
-/* Tests if reserved fields are checked.
- * We'll try non-zero values to test. */
-static int ReservedFieldsTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
- GptHeader* h2 = (GptHeader*)gpt->secondary_header;
+ Memcpy(&h3, h2, sizeof(h3));
+ h3.entries_crc32++;
+ EXPECT(1 == HeaderFieldsSame(h1, &h3));
- BuildTestGptData(gpt);
- h1->reserved_zero ^= 0x12345678; /* whatever random */
- h2->reserved_zero ^= 0x12345678; /* whatever random */
- RefreshCrc32(gpt);
- EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
- EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
+ return TEST_OK;
+}
-#ifdef PADDING_CHECKED
- /* TODO: padding check is currently disabled */
- BuildTestGptData(gpt);
- h1->padding[12] ^= 0x34; /* whatever random */
- h2->padding[56] ^= 0x78; /* whatever random */
- RefreshCrc32(gpt);
- EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
- EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
-#endif
+/* Test if signature ("EFI PART") is checked. */
+static int SignatureTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptHeader *h2 = (GptHeader *)gpt->secondary_header;
+ int i;
+
+ EXPECT(1 == CheckHeader(NULL, 0, gpt->drive_sectors));
+
+ for (i = 0; i < 8; ++i) {
+ BuildTestGptData(gpt);
+ h1->signature[i] ^= 0xff;
+ h2->signature[i] ^= 0xff;
+ RefreshCrc32(gpt);
+ EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
+ EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
+ }
+
+ return TEST_OK;
+}
- return TEST_OK;
+/*
+ * The revision we currently support is GPT_HEADER_REVISION. If the revision
+ * in header is not that, we expect the header is invalid.
+ */
+static int RevisionTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptHeader *h2 = (GptHeader *)gpt->secondary_header;
+ int i;
+
+ struct {
+ uint32_t value_to_test;
+ int expect_rv;
+ } cases[] = {
+ {0x01000000, 1},
+ {0x00010000, 0}, /* GPT_HEADER_REVISION */
+ {0x00000100, 1},
+ {0x00000001, 1},
+ {0x23010456, 1},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(cases); ++i) {
+ BuildTestGptData(gpt);
+ h1->revision = cases[i].value_to_test;
+ h2->revision = cases[i].value_to_test;
+ RefreshCrc32(gpt);
+
+ EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
+ cases[i].expect_rv);
+ EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
+ cases[i].expect_rv);
+ }
+ return TEST_OK;
}
+static int SizeTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptHeader *h2 = (GptHeader *)gpt->secondary_header;
+ int i;
+
+ struct {
+ uint32_t value_to_test;
+ int expect_rv;
+ } cases[] = {
+ {91, 1},
+ {92, 0},
+ {93, 0},
+ {511, 0},
+ {512, 0},
+ {513, 1},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(cases); ++i) {
+ BuildTestGptData(gpt);
+ h1->size = cases[i].value_to_test;
+ h2->size = cases[i].value_to_test;
+ RefreshCrc32(gpt);
+
+ EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
+ cases[i].expect_rv);
+ EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
+ cases[i].expect_rv);
+ }
+ return TEST_OK;
+}
-/* Technically, any size which is 2^N where N > 6 should work, but our
- * library only supports one size. */
-static int SizeOfPartitionEntryTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
- GptHeader* h2 = (GptHeader*)gpt->secondary_header;
- int i;
-
- struct {
- uint32_t value_to_test;
- int expect_rv;
- } cases[] = {
- {127, 1},
- {128, 0},
- {129, 1},
- {256, 1},
- {512, 1},
- };
-
- /* Check size of entryes */
- for (i = 0; i < ARRAY_SIZE(cases); ++i) {
- BuildTestGptData(gpt);
- h1->size_of_entry = cases[i].value_to_test;
- h2->size_of_entry = cases[i].value_to_test;
- h1->number_of_entries = TOTAL_ENTRIES_SIZE / cases[i].value_to_test;
- h2->number_of_entries = TOTAL_ENTRIES_SIZE / cases[i].value_to_test;
- RefreshCrc32(gpt);
-
- EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) == cases[i].expect_rv);
- EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) == cases[i].expect_rv);
- }
-
- return TEST_OK;
+/* Test if CRC is checked. */
+static int CrcFieldTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptHeader *h2 = (GptHeader *)gpt->secondary_header;
+
+ BuildTestGptData(gpt);
+ /* Modify a field that the header verification doesn't care about */
+ h1->entries_crc32++;
+ h2->entries_crc32++;
+ EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
+ EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
+ /* Refresh the CRC; should pass now */
+ RefreshCrc32(gpt);
+ EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
+ EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
+
+ return TEST_OK;
}
+/* Test if reserved fields are checked. We'll try non-zero values to test. */
+static int ReservedFieldsTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptHeader *h2 = (GptHeader *)gpt->secondary_header;
-/* Technically, any size which is 2^N where N > 6 should work, but our
- * library only supports one size. */
-static int NumberOfPartitionEntriesTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
- GptHeader* h2 = (GptHeader*)gpt->secondary_header;
+ BuildTestGptData(gpt);
+ h1->reserved_zero ^= 0x12345678; /* whatever random */
+ h2->reserved_zero ^= 0x12345678; /* whatever random */
+ RefreshCrc32(gpt);
+ EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
+ EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
- BuildTestGptData(gpt);
- h1->number_of_entries--;
- h2->number_of_entries /= 2;
- RefreshCrc32(gpt);
- EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
- EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
+#ifdef PADDING_CHECKED
+ /* TODO: padding check is currently disabled */
+ BuildTestGptData(gpt);
+ h1->padding[12] ^= 0x34; /* whatever random */
+ h2->padding[56] ^= 0x78; /* whatever random */
+ RefreshCrc32(gpt);
+ EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
+ EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
+#endif
- return TEST_OK;
+ return TEST_OK;
}
+/*
+ * Technically, any size which is 2^N where N > 6 should work, but our
+ * library only supports one size.
+ */
+static int SizeOfPartitionEntryTest(void) {
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptHeader *h2 = (GptHeader *)gpt->secondary_header;
+ int i;
+
+ struct {
+ uint32_t value_to_test;
+ int expect_rv;
+ } cases[] = {
+ {127, 1},
+ {128, 0},
+ {129, 1},
+ {256, 1},
+ {512, 1},
+ };
+
+ /* Check size of entryes */
+ for (i = 0; i < ARRAY_SIZE(cases); ++i) {
+ BuildTestGptData(gpt);
+ h1->size_of_entry = cases[i].value_to_test;
+ h2->size_of_entry = cases[i].value_to_test;
+ h1->number_of_entries = TOTAL_ENTRIES_SIZE /
+ cases[i].value_to_test;
+ h2->number_of_entries = TOTAL_ENTRIES_SIZE /
+ cases[i].value_to_test;
+ RefreshCrc32(gpt);
+
+ EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
+ cases[i].expect_rv);
+ EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
+ cases[i].expect_rv);
+ }
+
+ return TEST_OK;
+}
-/* Tests if myLBA field is checked (1 for primary, last for secondary). */
-static int MyLbaTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
- GptHeader* h2 = (GptHeader*)gpt->secondary_header;
-
- /* myLBA depends on primary vs secondary flag */
- BuildTestGptData(gpt);
- EXPECT(1 == CheckHeader(h1, 1, gpt->drive_sectors));
- EXPECT(1 == CheckHeader(h2, 0, gpt->drive_sectors));
-
- BuildTestGptData(gpt);
- h1->my_lba--;
- h2->my_lba--;
- RefreshCrc32(gpt);
- EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
- EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
-
- BuildTestGptData(gpt);
- h1->my_lba = 2;
- h2->my_lba--;
- RefreshCrc32(gpt);
- EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
- EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
-
- /* We should ignore the alternate_lba field entirely */
- BuildTestGptData(gpt);
- h1->alternate_lba++;
- h2->alternate_lba++;
- RefreshCrc32(gpt);
- EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
- EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
-
- BuildTestGptData(gpt);
- h1->alternate_lba--;
- h2->alternate_lba--;
- RefreshCrc32(gpt);
- EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
- EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
-
- BuildTestGptData(gpt);
- h1->entries_lba++;
- h2->entries_lba++;
- RefreshCrc32(gpt);
- EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
- EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
-
- BuildTestGptData(gpt);
- h1->entries_lba--;
- h2->entries_lba--;
- RefreshCrc32(gpt);
- EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
- EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
-
- return TEST_OK;
+/*
+ * Technically, any size which is 2^N where N > 6 should work, but our library
+ * only supports one size.
+ */
+static int NumberOfPartitionEntriesTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptHeader *h2 = (GptHeader *)gpt->secondary_header;
+
+ BuildTestGptData(gpt);
+ h1->number_of_entries--;
+ h2->number_of_entries /= 2;
+ RefreshCrc32(gpt);
+ EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
+ EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
+
+ return TEST_OK;
}
-/* Tests if FirstUsableLBA and LastUsableLBA are checked.
+/* Test if myLBA field is checked (1 for primary, last for secondary). */
+static int MyLbaTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptHeader *h2 = (GptHeader *)gpt->secondary_header;
+
+ /* myLBA depends on primary vs secondary flag */
+ BuildTestGptData(gpt);
+ EXPECT(1 == CheckHeader(h1, 1, gpt->drive_sectors));
+ EXPECT(1 == CheckHeader(h2, 0, gpt->drive_sectors));
+
+ BuildTestGptData(gpt);
+ h1->my_lba--;
+ h2->my_lba--;
+ RefreshCrc32(gpt);
+ EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
+ EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
+
+ BuildTestGptData(gpt);
+ h1->my_lba = 2;
+ h2->my_lba--;
+ RefreshCrc32(gpt);
+ EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
+ EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
+
+ /* We should ignore the alternate_lba field entirely */
+ BuildTestGptData(gpt);
+ h1->alternate_lba++;
+ h2->alternate_lba++;
+ RefreshCrc32(gpt);
+ EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
+ EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
+
+ BuildTestGptData(gpt);
+ h1->alternate_lba--;
+ h2->alternate_lba--;
+ RefreshCrc32(gpt);
+ EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
+ EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
+
+ BuildTestGptData(gpt);
+ h1->entries_lba++;
+ h2->entries_lba++;
+ RefreshCrc32(gpt);
+ EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
+ EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
+
+ BuildTestGptData(gpt);
+ h1->entries_lba--;
+ h2->entries_lba--;
+ RefreshCrc32(gpt);
+ EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
+ EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
+
+ return TEST_OK;
+}
+
+/* Test if FirstUsableLBA and LastUsableLBA are checked.
* FirstUsableLBA must be after the end of the primary GPT table array.
* LastUsableLBA must be before the start of the secondary GPT table array.
* FirstUsableLBA <= LastUsableLBA. */
-static int FirstUsableLbaAndLastUsableLbaTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
- GptHeader* h2 = (GptHeader*)gpt->secondary_header;
- int i;
-
- struct {
- uint64_t primary_entries_lba;
- uint64_t primary_first_usable_lba;
- uint64_t primary_last_usable_lba;
- uint64_t secondary_first_usable_lba;
- uint64_t secondary_last_usable_lba;
- uint64_t secondary_entries_lba;
- int primary_rv;
- int secondary_rv;
- } cases[] = {
- {2, 34, 433, 34, 433, 434, 0, 0},
- {2, 34, 432, 34, 430, 434, 0, 0},
- {2, 33, 433, 33, 433, 434, 1, 1},
- {2, 34, 434, 34, 433, 434, 1, 0},
- {2, 34, 433, 34, 434, 434, 0, 1},
- {2, 35, 433, 35, 433, 434, 0, 0},
- {2, 433, 433, 433, 433, 434, 0, 0},
- {2, 434, 433, 434, 434, 434, 1, 1},
- {2, 433, 34, 34, 433, 434, 1, 0},
- {2, 34, 433, 433, 34, 434, 0, 1},
- };
-
- for (i = 0; i < ARRAY_SIZE(cases); ++i) {
- BuildTestGptData(gpt);
- h1->entries_lba = cases[i].primary_entries_lba;
- h1->first_usable_lba = cases[i].primary_first_usable_lba;
- h1->last_usable_lba = cases[i].primary_last_usable_lba;
- h2->entries_lba = cases[i].secondary_entries_lba;
- h2->first_usable_lba = cases[i].secondary_first_usable_lba;
- h2->last_usable_lba = cases[i].secondary_last_usable_lba;
- RefreshCrc32(gpt);
-
- EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) == cases[i].primary_rv);
- EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) == cases[i].secondary_rv);
- }
-
- return TEST_OK;
+static int FirstUsableLbaAndLastUsableLbaTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptHeader *h2 = (GptHeader *)gpt->secondary_header;
+ int i;
+
+ struct {
+ uint64_t primary_entries_lba;
+ uint64_t primary_first_usable_lba;
+ uint64_t primary_last_usable_lba;
+ uint64_t secondary_first_usable_lba;
+ uint64_t secondary_last_usable_lba;
+ uint64_t secondary_entries_lba;
+ int primary_rv;
+ int secondary_rv;
+ } cases[] = {
+ {2, 34, 433, 34, 433, 434, 0, 0},
+ {2, 34, 432, 34, 430, 434, 0, 0},
+ {2, 33, 433, 33, 433, 434, 1, 1},
+ {2, 34, 434, 34, 433, 434, 1, 0},
+ {2, 34, 433, 34, 434, 434, 0, 1},
+ {2, 35, 433, 35, 433, 434, 0, 0},
+ {2, 433, 433, 433, 433, 434, 0, 0},
+ {2, 434, 433, 434, 434, 434, 1, 1},
+ {2, 433, 34, 34, 433, 434, 1, 0},
+ {2, 34, 433, 433, 34, 434, 0, 1},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(cases); ++i) {
+ BuildTestGptData(gpt);
+ h1->entries_lba = cases[i].primary_entries_lba;
+ h1->first_usable_lba = cases[i].primary_first_usable_lba;
+ h1->last_usable_lba = cases[i].primary_last_usable_lba;
+ h2->entries_lba = cases[i].secondary_entries_lba;
+ h2->first_usable_lba = cases[i].secondary_first_usable_lba;
+ h2->last_usable_lba = cases[i].secondary_last_usable_lba;
+ RefreshCrc32(gpt);
+
+ EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
+ cases[i].primary_rv);
+ EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
+ cases[i].secondary_rv);
+ }
+
+ return TEST_OK;
}
-
-/* Tests if PartitionEntryArrayCRC32 is checked.
- * PartitionEntryArrayCRC32 must be calculated over SizeOfPartitionEntry *
- * NumberOfPartitionEntries bytes.
+/*
+ * Test if PartitionEntryArrayCRC32 is checked. PartitionEntryArrayCRC32 must
+ * be calculated over SizeOfPartitionEntry * NumberOfPartitionEntries bytes.
*/
-static int EntriesCrcTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
- GptEntry* e1 = (GptEntry*)(gpt->primary_entries);
- GptEntry* e2 = (GptEntry*)(gpt->secondary_entries);
-
- /* Modify the first byte of primary entries, and expect the CRC is wrong. */
- BuildTestGptData(gpt);
- EXPECT(0 == CheckEntries(e1, h1));
- EXPECT(0 == CheckEntries(e2, h1));
- gpt->primary_entries[0] ^= 0xa5; /* just XOR a non-zero value */
- gpt->secondary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0x5a;
- EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e1, h1));
- EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e2, h1));
-
- return TEST_OK;
+static int EntriesCrcTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
+ GptEntry *e2 = (GptEntry *)(gpt->secondary_entries);
+
+ /* Modify first byte of primary entries, and expect the CRC is wrong. */
+ BuildTestGptData(gpt);
+ EXPECT(0 == CheckEntries(e1, h1));
+ EXPECT(0 == CheckEntries(e2, h1));
+ gpt->primary_entries[0] ^= 0xa5; /* just XOR a non-zero value */
+ gpt->secondary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0x5a;
+ EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e1, h1));
+ EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e2, h1));
+
+ return TEST_OK;
}
-
-/* Tests if partition geometry is checked.
+/*
+ * Test if partition geometry is checked.
* All active (non-zero PartitionTypeGUID) partition entries should have:
* entry.StartingLBA >= header.FirstUsableLBA
* entry.EndingLBA <= header.LastUsableLBA
* entry.StartingLBA <= entry.EndingLBA
*/
-static int ValidEntryTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
- GptEntry* e1 = (GptEntry*)(gpt->primary_entries);
-
- /* error case: entry.StartingLBA < header.FirstUsableLBA */
- BuildTestGptData(gpt);
- e1[0].starting_lba = h1->first_usable_lba - 1;
- RefreshCrc32(gpt);
- EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
-
- /* error case: entry.EndingLBA > header.LastUsableLBA */
- BuildTestGptData(gpt);
- e1[2].ending_lba = h1->last_usable_lba + 1;
- RefreshCrc32(gpt);
- EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
-
- /* error case: entry.StartingLBA > entry.EndingLBA */
- BuildTestGptData(gpt);
- e1[3].starting_lba = e1[3].ending_lba + 1;
- RefreshCrc32(gpt);
- EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
-
- /* case: non active entry should be ignored. */
- BuildTestGptData(gpt);
- Memset(&e1[1].type, 0, sizeof(e1[1].type));
- e1[1].starting_lba = e1[1].ending_lba + 1;
- RefreshCrc32(gpt);
- EXPECT(0 == CheckEntries(e1, h1));
-
- return TEST_OK;
+static int ValidEntryTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
+
+ /* error case: entry.StartingLBA < header.FirstUsableLBA */
+ BuildTestGptData(gpt);
+ e1[0].starting_lba = h1->first_usable_lba - 1;
+ RefreshCrc32(gpt);
+ EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
+
+ /* error case: entry.EndingLBA > header.LastUsableLBA */
+ BuildTestGptData(gpt);
+ e1[2].ending_lba = h1->last_usable_lba + 1;
+ RefreshCrc32(gpt);
+ EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
+
+ /* error case: entry.StartingLBA > entry.EndingLBA */
+ BuildTestGptData(gpt);
+ e1[3].starting_lba = e1[3].ending_lba + 1;
+ RefreshCrc32(gpt);
+ EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
+
+ /* case: non active entry should be ignored. */
+ BuildTestGptData(gpt);
+ Memset(&e1[1].type, 0, sizeof(e1[1].type));
+ e1[1].starting_lba = e1[1].ending_lba + 1;
+ RefreshCrc32(gpt);
+ EXPECT(0 == CheckEntries(e1, h1));
+
+ return TEST_OK;
}
-
-/* Tests if overlapped partition tables can be detected. */
-static int OverlappedPartitionTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h = (GptHeader*)gpt->primary_header;
- GptEntry* e = (GptEntry*)gpt->primary_entries;
- int i, j;
-
- struct {
- int overlapped;
- struct {
- int active;
- uint64_t starting_lba;
- uint64_t ending_lba;
- } entries[16]; /* enough for testing. */
- } cases[] = {
- {GPT_SUCCESS, {{0, 100, 199}}},
- {GPT_SUCCESS, {{1, 100, 199}}},
- {GPT_SUCCESS, {{1, 100, 150}, {1, 200, 250}, {1, 300, 350}}},
- {GPT_ERROR_START_LBA_OVERLAP,
- {{1, 200, 299}, {1, 100, 199}, {1, 100, 100}}},
- {GPT_ERROR_END_LBA_OVERLAP, {{1, 200, 299}, {1, 100, 199}, {1, 299, 299}}},
- {GPT_SUCCESS, {{1, 300, 399}, {1, 200, 299}, {1, 100, 199}}},
- {GPT_ERROR_END_LBA_OVERLAP, {{1, 100, 199}, {1, 199, 299}, {1, 299, 399}}},
- {GPT_ERROR_START_LBA_OVERLAP, {{1, 100, 199}, {1, 200, 299}, {1, 75, 399}}},
- {GPT_ERROR_START_LBA_OVERLAP, {{1, 100, 199}, {1, 75, 250}, {1, 200, 299}}},
- {GPT_ERROR_END_LBA_OVERLAP, {{1, 75, 150}, {1, 100, 199}, {1, 200, 299}}},
- {GPT_ERROR_START_LBA_OVERLAP,
- {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {1, 100, 399}}},
- {GPT_SUCCESS, {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {0, 100, 399}}},
- {GPT_ERROR_START_LBA_OVERLAP,
- {{1, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
- {GPT_ERROR_START_LBA_OVERLAP,
- {{0, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
- {GPT_SUCCESS, {{1, 200, 300}, {1, 100, 199}, {0, 100, 400}, {0, 300, 400}}},
- {GPT_ERROR_END_LBA_OVERLAP,
- {{1, 200, 299}, {1, 100, 199}, {1, 199, 199}}},
- {GPT_SUCCESS, {{1, 200, 299}, {0, 100, 199}, {1, 199, 199}}},
- {GPT_SUCCESS, {{1, 200, 299}, {1, 100, 199}, {0, 199, 199}}},
- {GPT_ERROR_START_LBA_OVERLAP,
- {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
- {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
- {1, 207, 207}, {1, 208, 208}, {1, 199, 199}}},
- {GPT_SUCCESS, {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
- {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
- {1, 207, 207}, {1, 208, 208}, {0, 199, 199}}},
- };
-
-
- for (i = 0; i < ARRAY_SIZE(cases); ++i) {
- BuildTestGptData(gpt);
- ZeroEntries(gpt);
- for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
- if (!cases[i].entries[j].starting_lba)
- break;
-
- if (cases[i].entries[j].active)
- Memcpy(&e[j].type, &guid_kernel, sizeof(Guid));
- SetGuid(&e[j].unique, j);
- e[j].starting_lba = cases[i].entries[j].starting_lba;
- e[j].ending_lba = cases[i].entries[j].ending_lba;
- }
- RefreshCrc32(gpt);
-
- EXPECT(cases[i].overlapped == CheckEntries(e, h));
- }
- return TEST_OK;
+/* Test if overlapped partition tables can be detected. */
+static int OverlappedPartitionTest(void) {
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h = (GptHeader *)gpt->primary_header;
+ GptEntry *e = (GptEntry *)gpt->primary_entries;
+ int i, j;
+
+ struct {
+ int overlapped;
+ struct {
+ int active;
+ uint64_t starting_lba;
+ uint64_t ending_lba;
+ } entries[16]; /* enough for testing. */
+ } cases[] = {
+ {GPT_SUCCESS, {{0, 100, 199}}},
+ {GPT_SUCCESS, {{1, 100, 199}}},
+ {GPT_SUCCESS, {{1, 100, 150}, {1, 200, 250}, {1, 300, 350}}},
+ {GPT_ERROR_START_LBA_OVERLAP,
+ {{1, 200, 299}, {1, 100, 199}, {1, 100, 100}}},
+ {GPT_ERROR_END_LBA_OVERLAP,
+ {{1, 200, 299}, {1, 100, 199}, {1, 299, 299}}},
+ {GPT_SUCCESS, {{1, 300, 399}, {1, 200, 299}, {1, 100, 199}}},
+ {GPT_ERROR_END_LBA_OVERLAP,
+ {{1, 100, 199}, {1, 199, 299}, {1, 299, 399}}},
+ {GPT_ERROR_START_LBA_OVERLAP,
+ {{1, 100, 199}, {1, 200, 299}, {1, 75, 399}}},
+ {GPT_ERROR_START_LBA_OVERLAP,
+ {{1, 100, 199}, {1, 75, 250}, {1, 200, 299}}},
+ {GPT_ERROR_END_LBA_OVERLAP,
+ {{1, 75, 150}, {1, 100, 199}, {1, 200, 299}}},
+ {GPT_ERROR_START_LBA_OVERLAP,
+ {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {1, 100, 399}}},
+ {GPT_SUCCESS,
+ {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {0, 100, 399}}},
+ {GPT_ERROR_START_LBA_OVERLAP,
+ {{1, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
+ {GPT_ERROR_START_LBA_OVERLAP,
+ {{0, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
+ {GPT_SUCCESS,
+ {{1, 200, 300}, {1, 100, 199}, {0, 100, 400}, {0, 300, 400}}},
+ {GPT_ERROR_END_LBA_OVERLAP,
+ {{1, 200, 299}, {1, 100, 199}, {1, 199, 199}}},
+ {GPT_SUCCESS, {{1, 200, 299}, {0, 100, 199}, {1, 199, 199}}},
+ {GPT_SUCCESS, {{1, 200, 299}, {1, 100, 199}, {0, 199, 199}}},
+ {GPT_ERROR_START_LBA_OVERLAP,
+ {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
+ {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
+ {1, 207, 207}, {1, 208, 208}, {1, 199, 199}}},
+ {GPT_SUCCESS,
+ {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
+ {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
+ {1, 207, 207}, {1, 208, 208}, {0, 199, 199}}},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(cases); ++i) {
+ BuildTestGptData(gpt);
+ ZeroEntries(gpt);
+ for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
+ if (!cases[i].entries[j].starting_lba)
+ break;
+
+ if (cases[i].entries[j].active)
+ Memcpy(&e[j].type, &guid_kernel, sizeof(Guid));
+ SetGuid(&e[j].unique, j);
+ e[j].starting_lba = cases[i].entries[j].starting_lba;
+ e[j].ending_lba = cases[i].entries[j].ending_lba;
+ }
+ RefreshCrc32(gpt);
+
+ EXPECT(cases[i].overlapped == CheckEntries(e, h));
+ }
+ return TEST_OK;
}
-
/* Test both sanity checking and repair. */
-static int SanityCheckTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h1 = (GptHeader*)gpt->primary_header;
-
- /* Unmodified test data is completely sane */
- BuildTestGptData(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- /* Repair doesn't damage it */
- GptRepair(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- EXPECT(0 == gpt->modified);
-
- /* Modify headers */
- BuildTestGptData(gpt);
- gpt->primary_header[0]++;
- gpt->secondary_header[0]++;
- EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
- EXPECT(0 == gpt->valid_headers);
- EXPECT(0 == gpt->valid_entries);
- /* Repair can't fix completely busted headers */
- GptRepair(gpt);
- EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
- EXPECT(0 == gpt->valid_headers);
- EXPECT(0 == gpt->valid_entries);
- EXPECT(0 == gpt->modified);
-
- BuildTestGptData(gpt);
- gpt->primary_header[0]++;
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_SECONDARY == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- GptRepair(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- EXPECT(GPT_MODIFIED_HEADER1 == gpt->modified);
-
- BuildTestGptData(gpt);
- gpt->secondary_header[0]++;
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_PRIMARY == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- GptRepair(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
-
- /* Modify header1 and update its CRC. Since header2 is now different than
- * header1, it'll be the one considered invalid. */
- BuildTestGptData(gpt);
- h1->size++;
- RefreshCrc32(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_PRIMARY == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- GptRepair(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
-
- /* Modify entries */
- BuildTestGptData(gpt);
- gpt->primary_entries[0]++;
- gpt->secondary_entries[0]++;
- EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_NONE == gpt->valid_entries);
- /* Repair can't fix both copies of entries being bad, either. */
- GptRepair(gpt);
- EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_NONE == gpt->valid_entries);
- EXPECT(0 == gpt->modified);
-
- BuildTestGptData(gpt);
- gpt->primary_entries[0]++;
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_SECONDARY == gpt->valid_entries);
- GptRepair(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- EXPECT(GPT_MODIFIED_ENTRIES1 == gpt->modified);
-
- BuildTestGptData(gpt);
- gpt->secondary_entries[0]++;
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_PRIMARY == gpt->valid_entries);
- GptRepair(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- EXPECT(GPT_MODIFIED_ENTRIES2 == gpt->modified);
-
- /* Modify both header and entries */
- BuildTestGptData(gpt);
- gpt->primary_header[0]++;
- gpt->primary_entries[0]++;
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_SECONDARY == gpt->valid_headers);
- EXPECT(MASK_SECONDARY == gpt->valid_entries);
- GptRepair(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
-
- BuildTestGptData(gpt);
- gpt->secondary_header[0]++;
- gpt->secondary_entries[0]++;
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_PRIMARY == gpt->valid_headers);
- EXPECT(MASK_PRIMARY == gpt->valid_entries);
- GptRepair(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
-
- /* Test cross-correction (h1+e2, h2+e1) */
- BuildTestGptData(gpt);
- gpt->primary_header[0]++;
- gpt->secondary_entries[0]++;
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_SECONDARY == gpt->valid_headers);
- EXPECT(MASK_PRIMARY == gpt->valid_entries);
- GptRepair(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
-
- BuildTestGptData(gpt);
- gpt->secondary_header[0]++;
- gpt->primary_entries[0]++;
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_PRIMARY == gpt->valid_headers);
- EXPECT(MASK_SECONDARY == gpt->valid_entries);
- GptRepair(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
-
- /* Test mismatched pairs (h1+e1 valid, h2+e2 valid but different.
- * This simulates a partial update of the drive. */
- BuildTestGptData(gpt);
- gpt->secondary_entries[0]++;
- RefreshCrc32(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_PRIMARY == gpt->valid_headers);
- EXPECT(MASK_PRIMARY == gpt->valid_entries);
- GptRepair(gpt);
- EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
- EXPECT(MASK_BOTH == gpt->valid_headers);
- EXPECT(MASK_BOTH == gpt->valid_entries);
- EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
-
- return TEST_OK;
+static int SanityCheckTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h1 = (GptHeader *)gpt->primary_header;
+ GptEntry *e1 = (GptEntry *)gpt->primary_entries;
+ uint8_t *tempptr;
+
+ /* Unmodified test data is completely sane */
+ BuildTestGptData(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ /* Repair doesn't damage it */
+ GptRepair(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ EXPECT(0 == gpt->modified);
+
+ /* Invalid sector size should fail */
+ BuildTestGptData(gpt);
+ gpt->sector_bytes = 1024;
+ EXPECT(GPT_ERROR_INVALID_SECTOR_SIZE == GptSanityCheck(gpt));
+
+ /* Modify headers */
+ BuildTestGptData(gpt);
+ gpt->primary_header[0]++;
+ gpt->secondary_header[0]++;
+ EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
+ EXPECT(0 == gpt->valid_headers);
+ EXPECT(0 == gpt->valid_entries);
+ /* Repair can't fix completely busted headers */
+ GptRepair(gpt);
+ EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
+ EXPECT(0 == gpt->valid_headers);
+ EXPECT(0 == gpt->valid_entries);
+ EXPECT(0 == gpt->modified);
+
+ BuildTestGptData(gpt);
+ gpt->primary_header[0]++;
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_SECONDARY == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ GptRepair(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ EXPECT(GPT_MODIFIED_HEADER1 == gpt->modified);
+
+ BuildTestGptData(gpt);
+ gpt->secondary_header[0]++;
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_PRIMARY == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ GptRepair(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
+
+ /*
+ * Modify header1 and update its CRC. Since header2 is now different
+ * than header1, it'll be the one considered invalid.
+ */
+ BuildTestGptData(gpt);
+ h1->size++;
+ RefreshCrc32(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_PRIMARY == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ GptRepair(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
+
+ /* Modify entries */
+ BuildTestGptData(gpt);
+ gpt->primary_entries[0]++;
+ gpt->secondary_entries[0]++;
+ EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_NONE == gpt->valid_entries);
+ /* Repair can't fix both copies of entries being bad, either. */
+ GptRepair(gpt);
+ EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_NONE == gpt->valid_entries);
+ EXPECT(0 == gpt->modified);
+
+ BuildTestGptData(gpt);
+ gpt->primary_entries[0]++;
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_SECONDARY == gpt->valid_entries);
+ GptRepair(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ EXPECT(GPT_MODIFIED_ENTRIES1 == gpt->modified);
+
+ BuildTestGptData(gpt);
+ gpt->secondary_entries[0]++;
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_PRIMARY == gpt->valid_entries);
+ GptRepair(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ EXPECT(GPT_MODIFIED_ENTRIES2 == gpt->modified);
+
+ /*
+ * Modify entries and recompute CRCs, then make both primary and
+ * secondary entry pointers use the secondary data. The primary
+ * header will have the wrong entries CRC, so we should fall back
+ * to the secondary header.
+ */
+ BuildTestGptData(gpt);
+ e1->starting_lba++;
+ RefreshCrc32(gpt);
+ tempptr = gpt->primary_entries;
+ gpt->primary_entries = gpt->secondary_entries;
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_SECONDARY == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ gpt->primary_entries = tempptr;
+
+ /* Modify both header and entries */
+ BuildTestGptData(gpt);
+ gpt->primary_header[0]++;
+ gpt->primary_entries[0]++;
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_SECONDARY == gpt->valid_headers);
+ EXPECT(MASK_SECONDARY == gpt->valid_entries);
+ GptRepair(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
+
+ BuildTestGptData(gpt);
+ gpt->secondary_header[0]++;
+ gpt->secondary_entries[0]++;
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_PRIMARY == gpt->valid_headers);
+ EXPECT(MASK_PRIMARY == gpt->valid_entries);
+ GptRepair(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
+
+ /* Test cross-correction (h1+e2, h2+e1) */
+ BuildTestGptData(gpt);
+ gpt->primary_header[0]++;
+ gpt->secondary_entries[0]++;
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_SECONDARY == gpt->valid_headers);
+ EXPECT(MASK_PRIMARY == gpt->valid_entries);
+ GptRepair(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
+
+ BuildTestGptData(gpt);
+ gpt->secondary_header[0]++;
+ gpt->primary_entries[0]++;
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_PRIMARY == gpt->valid_headers);
+ EXPECT(MASK_SECONDARY == gpt->valid_entries);
+ GptRepair(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
+
+ /*
+ * Test mismatched pairs (h1+e1 valid, h2+e2 valid but different. This
+ * simulates a partial update of the drive.
+ */
+ BuildTestGptData(gpt);
+ gpt->secondary_entries[0]++;
+ RefreshCrc32(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_PRIMARY == gpt->valid_headers);
+ EXPECT(MASK_PRIMARY == gpt->valid_entries);
+ GptRepair(gpt);
+ EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
+ EXPECT(MASK_BOTH == gpt->valid_headers);
+ EXPECT(MASK_BOTH == gpt->valid_entries);
+ EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
+
+ return TEST_OK;
}
-
-static int EntryAttributeGetSetTest() {
- GptData* gpt = GetEmptyGptData();
- GptEntry* e = (GptEntry*)(gpt->primary_entries);
-
- e->attrs.whole = 0x0000000000000000ULL;
- SetEntrySuccessful(e, 1);
- EXPECT(0x0100000000000000ULL == e->attrs.whole);
- EXPECT(1 == GetEntrySuccessful(e));
- e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
- SetEntrySuccessful(e, 0);
- EXPECT(0xFEFFFFFFFFFFFFFFULL == e->attrs.whole);
- EXPECT(0 == GetEntrySuccessful(e));
-
- e->attrs.whole = 0x0000000000000000ULL;
- SetEntryTries(e, 15);
- EXPECT(15 == GetEntryTries(e));
- EXPECT(0x00F0000000000000ULL == e->attrs.whole);
- e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
- SetEntryTries(e, 0);
- EXPECT(0xFF0FFFFFFFFFFFFFULL == e->attrs.whole);
- EXPECT(0 == GetEntryTries(e));
-
- e->attrs.whole = 0x0000000000000000ULL;
- SetEntryPriority(e, 15);
- EXPECT(0x000F000000000000ULL == e->attrs.whole);
- EXPECT(15 == GetEntryPriority(e));
- e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
- SetEntryPriority(e, 0);
- EXPECT(0xFFF0FFFFFFFFFFFFULL == e->attrs.whole);
- EXPECT(0 == GetEntryPriority(e));
-
- e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
- EXPECT(1 == GetEntrySuccessful(e));
- EXPECT(15 == GetEntryPriority(e));
- EXPECT(15 == GetEntryTries(e));
-
- e->attrs.whole = 0x0123000000000000ULL;
- EXPECT(1 == GetEntrySuccessful(e));
- EXPECT(2 == GetEntryTries(e));
- EXPECT(3 == GetEntryPriority(e));
-
- return TEST_OK;
+static int EntryAttributeGetSetTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptEntry *e = (GptEntry *)(gpt->primary_entries);
+
+ e->attrs.whole = 0x0000000000000000ULL;
+ SetEntrySuccessful(e, 1);
+ EXPECT(0x0100000000000000ULL == e->attrs.whole);
+ EXPECT(1 == GetEntrySuccessful(e));
+ e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
+ SetEntrySuccessful(e, 0);
+ EXPECT(0xFEFFFFFFFFFFFFFFULL == e->attrs.whole);
+ EXPECT(0 == GetEntrySuccessful(e));
+
+ e->attrs.whole = 0x0000000000000000ULL;
+ SetEntryTries(e, 15);
+ EXPECT(15 == GetEntryTries(e));
+ EXPECT(0x00F0000000000000ULL == e->attrs.whole);
+ e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
+ SetEntryTries(e, 0);
+ EXPECT(0xFF0FFFFFFFFFFFFFULL == e->attrs.whole);
+ EXPECT(0 == GetEntryTries(e));
+
+ e->attrs.whole = 0x0000000000000000ULL;
+ SetEntryPriority(e, 15);
+ EXPECT(0x000F000000000000ULL == e->attrs.whole);
+ EXPECT(15 == GetEntryPriority(e));
+ e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
+ SetEntryPriority(e, 0);
+ EXPECT(0xFFF0FFFFFFFFFFFFULL == e->attrs.whole);
+ EXPECT(0 == GetEntryPriority(e));
+
+ e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
+ EXPECT(1 == GetEntrySuccessful(e));
+ EXPECT(15 == GetEntryPriority(e));
+ EXPECT(15 == GetEntryTries(e));
+
+ e->attrs.whole = 0x0123000000000000ULL;
+ EXPECT(1 == GetEntrySuccessful(e));
+ EXPECT(2 == GetEntryTries(e));
+ EXPECT(3 == GetEntryPriority(e));
+
+ return TEST_OK;
}
+static int EntryTypeTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptEntry *e = (GptEntry *)(gpt->primary_entries);
-static int EntryTypeTest() {
- GptData* gpt = GetEmptyGptData();
- GptEntry* e = (GptEntry*)(gpt->primary_entries);
-
- Memcpy(&e->type, &guid_zero, sizeof(Guid));
- EXPECT(1 == IsUnusedEntry(e));
- EXPECT(0 == IsKernelEntry(e));
+ Memcpy(&e->type, &guid_zero, sizeof(Guid));
+ EXPECT(1 == IsUnusedEntry(e));
+ EXPECT(0 == IsKernelEntry(e));
- Memcpy(&e->type, &guid_kernel, sizeof(Guid));
- EXPECT(0 == IsUnusedEntry(e));
- EXPECT(1 == IsKernelEntry(e));
+ Memcpy(&e->type, &guid_kernel, sizeof(Guid));
+ EXPECT(0 == IsUnusedEntry(e));
+ EXPECT(1 == IsKernelEntry(e));
- Memcpy(&e->type, &guid_rootfs, sizeof(Guid));
- EXPECT(0 == IsUnusedEntry(e));
- EXPECT(0 == IsKernelEntry(e));
+ Memcpy(&e->type, &guid_rootfs, sizeof(Guid));
+ EXPECT(0 == IsUnusedEntry(e));
+ EXPECT(0 == IsKernelEntry(e));
- return TEST_OK;
+ return TEST_OK;
}
-
/* Make an entry unused by clearing its type. */
-static void FreeEntry(GptEntry* e) {
- Memset(&e->type, 0, sizeof(Guid));
+static void FreeEntry(GptEntry *e)
+{
+ Memset(&e->type, 0, sizeof(Guid));
}
-
/* Set up an entry. */
-static void FillEntry(GptEntry* e, int is_kernel,
- int priority, int successful, int tries) {
- Memcpy(&e->type, (is_kernel ? &guid_kernel : &guid_zero), sizeof(Guid));
- SetEntryPriority(e, priority);
- SetEntrySuccessful(e, successful);
- SetEntryTries(e, tries);
+static void FillEntry(GptEntry *e, int is_kernel,
+ int priority, int successful, int tries)
+{
+ Memcpy(&e->type, (is_kernel ? &guid_kernel : &guid_zero), sizeof(Guid));
+ SetEntryPriority(e, priority);
+ SetEntrySuccessful(e, successful);
+ SetEntryTries(e, tries);
}
-
-/* Invalidate all kernel entries and expect GptNextKernelEntry() cannot find
+/*
+ * Invalidate all kernel entries and expect GptNextKernelEntry() cannot find
* any usable kernel entry.
*/
-static int NoValidKernelEntryTest() {
- GptData* gpt = GetEmptyGptData();
- GptEntry* e1 = (GptEntry*)(gpt->primary_entries);
-
- BuildTestGptData(gpt);
- SetEntryPriority(e1 + KERNEL_A, 0);
- FreeEntry(e1 + KERNEL_B);
- RefreshCrc32(gpt);
- EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, NULL, NULL));
-
- return TEST_OK;
+static int NoValidKernelEntryTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
+
+ BuildTestGptData(gpt);
+ SetEntryPriority(e1 + KERNEL_A, 0);
+ FreeEntry(e1 + KERNEL_B);
+ RefreshCrc32(gpt);
+ EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
+ GptNextKernelEntry(gpt, NULL, NULL));
+
+ return TEST_OK;
}
-
-static int GetNextNormalTest() {
- GptData* gpt = GetEmptyGptData();
- GptEntry* e1 = (GptEntry*)(gpt->primary_entries);
- uint64_t start, size;
-
- /* Normal case - both kernels successful */
- BuildTestGptData(gpt);
- FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
- FillEntry(e1 + KERNEL_B, 1, 2, 1, 0);
- RefreshCrc32(gpt);
- GptInit(gpt);
-
- EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
- EXPECT(KERNEL_A == gpt->current_kernel);
- EXPECT(34 == start);
- EXPECT(100 == size);
-
- EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
- EXPECT(KERNEL_B == gpt->current_kernel);
- EXPECT(134 == start);
- EXPECT(99 == size);
-
- EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, &start, &size));
- EXPECT(-1 == gpt->current_kernel);
-
- /* Call as many times as you want; you won't get another kernel... */
- EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, &start, &size));
- EXPECT(-1 == gpt->current_kernel);
-
- return TEST_OK;
+static int GetNextNormalTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
+ uint64_t start, size;
+
+ /* Normal case - both kernels successful */
+ BuildTestGptData(gpt);
+ FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
+ FillEntry(e1 + KERNEL_B, 1, 2, 1, 0);
+ RefreshCrc32(gpt);
+ GptInit(gpt);
+
+ EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
+ EXPECT(KERNEL_A == gpt->current_kernel);
+ EXPECT(34 == start);
+ EXPECT(100 == size);
+
+ EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
+ EXPECT(KERNEL_B == gpt->current_kernel);
+ EXPECT(134 == start);
+ EXPECT(99 == size);
+
+ EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
+ GptNextKernelEntry(gpt, &start, &size));
+ EXPECT(-1 == gpt->current_kernel);
+
+ /* Call as many times as you want; you won't get another kernel... */
+ EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
+ GptNextKernelEntry(gpt, &start, &size));
+ EXPECT(-1 == gpt->current_kernel);
+
+ return TEST_OK;
}
-
-static int GetNextPrioTest() {
- GptData* gpt = GetEmptyGptData();
- GptEntry* e1 = (GptEntry*)(gpt->primary_entries);
- uint64_t start, size;
-
- /* Priority 3, 4, 0, 4 - should boot order B, Y, A */
- BuildTestGptData(gpt);
- FillEntry(e1 + KERNEL_A, 1, 3, 1, 0);
- FillEntry(e1 + KERNEL_B, 1, 4, 1, 0);
- FillEntry(e1 + KERNEL_X, 1, 0, 1, 0);
- FillEntry(e1 + KERNEL_Y, 1, 4, 1, 0);
- RefreshCrc32(gpt);
- GptInit(gpt);
-
- EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
- EXPECT(KERNEL_B == gpt->current_kernel);
- EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
- EXPECT(KERNEL_Y == gpt->current_kernel);
- EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
- EXPECT(KERNEL_A == gpt->current_kernel);
- EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, &start, &size));
-
- return TEST_OK;
+static int GetNextPrioTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
+ uint64_t start, size;
+
+ /* Priority 3, 4, 0, 4 - should boot order B, Y, A */
+ BuildTestGptData(gpt);
+ FillEntry(e1 + KERNEL_A, 1, 3, 1, 0);
+ FillEntry(e1 + KERNEL_B, 1, 4, 1, 0);
+ FillEntry(e1 + KERNEL_X, 1, 0, 1, 0);
+ FillEntry(e1 + KERNEL_Y, 1, 4, 1, 0);
+ RefreshCrc32(gpt);
+ GptInit(gpt);
+
+ EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
+ EXPECT(KERNEL_B == gpt->current_kernel);
+ EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
+ EXPECT(KERNEL_Y == gpt->current_kernel);
+ EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
+ EXPECT(KERNEL_A == gpt->current_kernel);
+ EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
+ GptNextKernelEntry(gpt, &start, &size));
+
+ return TEST_OK;
}
-
-static int GetNextTriesTest() {
- GptData* gpt = GetEmptyGptData();
- GptEntry* e1 = (GptEntry*)(gpt->primary_entries);
- uint64_t start, size;
-
- /* Tries=nonzero is attempted just like success, but tries=0 isn't */
- BuildTestGptData(gpt);
- FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
- FillEntry(e1 + KERNEL_B, 1, 3, 0, 0);
- FillEntry(e1 + KERNEL_X, 1, 4, 0, 1);
- FillEntry(e1 + KERNEL_Y, 1, 0, 0, 5);
- RefreshCrc32(gpt);
- GptInit(gpt);
-
- EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
- EXPECT(KERNEL_X == gpt->current_kernel);
- EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
- EXPECT(KERNEL_A == gpt->current_kernel);
- EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, &start, &size));
-
- return TEST_OK;
+static int GetNextTriesTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
+ uint64_t start, size;
+
+ /* Tries=nonzero is attempted just like success, but tries=0 isn't */
+ BuildTestGptData(gpt);
+ FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
+ FillEntry(e1 + KERNEL_B, 1, 3, 0, 0);
+ FillEntry(e1 + KERNEL_X, 1, 4, 0, 1);
+ FillEntry(e1 + KERNEL_Y, 1, 0, 0, 5);
+ RefreshCrc32(gpt);
+ GptInit(gpt);
+
+ EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
+ EXPECT(KERNEL_X == gpt->current_kernel);
+ EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
+ EXPECT(KERNEL_A == gpt->current_kernel);
+ EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
+ GptNextKernelEntry(gpt, &start, &size));
+
+ return TEST_OK;
}
-
-static int GptUpdateTest() {
- GptData* gpt = GetEmptyGptData();
- GptEntry* e = (GptEntry*)(gpt->primary_entries);
- GptEntry* e2 = (GptEntry*)(gpt->secondary_entries);
- uint64_t start, size;
-
- /* Tries=nonzero is attempted just like success, but tries=0 isn't */
- BuildTestGptData(gpt);
- FillEntry(e + KERNEL_A, 1, 4, 1, 0);
- FillEntry(e + KERNEL_B, 1, 3, 0, 2);
- FillEntry(e + KERNEL_X, 1, 2, 0, 2);
- RefreshCrc32(gpt);
- GptInit(gpt);
- gpt->modified = 0; /* Nothing modified yet */
-
- /* Successful kernel */
- EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
- EXPECT(KERNEL_A == gpt->current_kernel);
- EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
- EXPECT(4 == GetEntryPriority(e + KERNEL_A));
- EXPECT(0 == GetEntryTries(e + KERNEL_A));
- EXPECT(1 == GetEntrySuccessful(e2 + KERNEL_A));
- EXPECT(4 == GetEntryPriority(e2 + KERNEL_A));
- EXPECT(0 == GetEntryTries(e2 + KERNEL_A));
- /* Trying successful kernel changes nothing */
- EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
- EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
- EXPECT(4 == GetEntryPriority(e + KERNEL_A));
- EXPECT(0 == GetEntryTries(e + KERNEL_A));
- EXPECT(0 == gpt->modified);
- /* Marking it bad also does not update it. */
- EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
- EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
- EXPECT(4 == GetEntryPriority(e + KERNEL_A));
- EXPECT(0 == GetEntryTries(e + KERNEL_A));
- EXPECT(0 == gpt->modified);
-
- /* Kernel with tries */
- EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
- EXPECT(KERNEL_B == gpt->current_kernel);
- EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
- EXPECT(3 == GetEntryPriority(e + KERNEL_B));
- EXPECT(2 == GetEntryTries(e + KERNEL_B));
- /* Marking it bad clears it */
- EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
- EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
- EXPECT(0 == GetEntryPriority(e + KERNEL_B));
- EXPECT(0 == GetEntryTries(e + KERNEL_B));
- /* Which affects both copies of the partition entries */
- EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_B));
- EXPECT(0 == GetEntryPriority(e2 + KERNEL_B));
- EXPECT(0 == GetEntryTries(e2 + KERNEL_B));
- /* And that's caused the GPT to need updating */
- EXPECT(0x0F == gpt->modified);
-
- /* Another kernel with tries */
- EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
- EXPECT(KERNEL_X == gpt->current_kernel);
- EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
- EXPECT(2 == GetEntryPriority(e + KERNEL_X));
- EXPECT(2 == GetEntryTries(e + KERNEL_X));
- /* Trying it uses up a try */
- EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
- EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
- EXPECT(2 == GetEntryPriority(e + KERNEL_X));
- EXPECT(1 == GetEntryTries(e + KERNEL_X));
- EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_X));
- EXPECT(2 == GetEntryPriority(e2 + KERNEL_X));
- EXPECT(1 == GetEntryTries(e2 + KERNEL_X));
- /* Trying it again marks it inactive */
- EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
- EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
- EXPECT(0 == GetEntryPriority(e + KERNEL_X));
- EXPECT(0 == GetEntryTries(e + KERNEL_X));
-
- return TEST_OK;
+static int GptUpdateTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptEntry *e = (GptEntry *)(gpt->primary_entries);
+ GptEntry *e2 = (GptEntry *)(gpt->secondary_entries);
+ uint64_t start, size;
+
+ /* Tries=nonzero is attempted just like success, but tries=0 isn't */
+ BuildTestGptData(gpt);
+ FillEntry(e + KERNEL_A, 1, 4, 1, 0);
+ FillEntry(e + KERNEL_B, 1, 3, 0, 2);
+ FillEntry(e + KERNEL_X, 1, 2, 0, 2);
+ RefreshCrc32(gpt);
+ GptInit(gpt);
+ gpt->modified = 0; /* Nothing modified yet */
+
+ /* Successful kernel */
+ EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
+ EXPECT(KERNEL_A == gpt->current_kernel);
+ EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
+ EXPECT(4 == GetEntryPriority(e + KERNEL_A));
+ EXPECT(0 == GetEntryTries(e + KERNEL_A));
+ EXPECT(1 == GetEntrySuccessful(e2 + KERNEL_A));
+ EXPECT(4 == GetEntryPriority(e2 + KERNEL_A));
+ EXPECT(0 == GetEntryTries(e2 + KERNEL_A));
+ /* Trying successful kernel changes nothing */
+ EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
+ EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
+ EXPECT(4 == GetEntryPriority(e + KERNEL_A));
+ EXPECT(0 == GetEntryTries(e + KERNEL_A));
+ EXPECT(0 == gpt->modified);
+ /* Marking it bad also does not update it. */
+ EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
+ EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
+ EXPECT(4 == GetEntryPriority(e + KERNEL_A));
+ EXPECT(0 == GetEntryTries(e + KERNEL_A));
+ EXPECT(0 == gpt->modified);
+
+ /* Kernel with tries */
+ EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
+ EXPECT(KERNEL_B == gpt->current_kernel);
+ EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
+ EXPECT(3 == GetEntryPriority(e + KERNEL_B));
+ EXPECT(2 == GetEntryTries(e + KERNEL_B));
+ /* Marking it bad clears it */
+ EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
+ EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
+ EXPECT(0 == GetEntryPriority(e + KERNEL_B));
+ EXPECT(0 == GetEntryTries(e + KERNEL_B));
+ /* Which affects both copies of the partition entries */
+ EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_B));
+ EXPECT(0 == GetEntryPriority(e2 + KERNEL_B));
+ EXPECT(0 == GetEntryTries(e2 + KERNEL_B));
+ /* And that's caused the GPT to need updating */
+ EXPECT(0x0F == gpt->modified);
+
+ /* Another kernel with tries */
+ EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
+ EXPECT(KERNEL_X == gpt->current_kernel);
+ EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
+ EXPECT(2 == GetEntryPriority(e + KERNEL_X));
+ EXPECT(2 == GetEntryTries(e + KERNEL_X));
+ /* Trying it uses up a try */
+ EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
+ EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
+ EXPECT(2 == GetEntryPriority(e + KERNEL_X));
+ EXPECT(1 == GetEntryTries(e + KERNEL_X));
+ EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_X));
+ EXPECT(2 == GetEntryPriority(e2 + KERNEL_X));
+ EXPECT(1 == GetEntryTries(e2 + KERNEL_X));
+ /* Trying it again marks it inactive */
+ EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
+ EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
+ EXPECT(0 == GetEntryPriority(e + KERNEL_X));
+ EXPECT(0 == GetEntryTries(e + KERNEL_X));
+
+ /* Can't update if entry isn't a kernel, or there isn't an entry */
+ Memcpy(&e[KERNEL_X].type, &guid_rootfs, sizeof(guid_rootfs));
+ EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
+ GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
+ gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
+ EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
+ GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
+
+
+ return TEST_OK;
}
+/*
+ * Give an invalid kernel type, and expect GptUpdateKernelEntry() returns
+ * GPT_ERROR_INVALID_UPDATE_TYPE.
+ */
+static int UpdateInvalidKernelTypeTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+
+ BuildTestGptData(gpt);
+ /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
+ gpt->current_kernel = 0;
+ /* any invalid update_type value */
+ EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
+ GptUpdateKernelEntry(gpt, 99));
+
+ return TEST_OK;
+}
-/* Given an invalid kernel type, and expect GptUpdateKernelEntry() returns
- * GPT_ERROR_INVALID_UPDATE_TYPE. */
-static int UpdateInvalidKernelTypeTest() {
- GptData* gpt = GetEmptyGptData();
-
- BuildTestGptData(gpt);
- gpt->current_kernel = 0; /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
- EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
- GptUpdateKernelEntry(gpt, 99)); /* any invalid update_type value */
+/* Test duplicate UniqueGuids can be detected. */
+static int DuplicateUniqueGuidTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptHeader *h = (GptHeader *)gpt->primary_header;
+ GptEntry *e = (GptEntry *)gpt->primary_entries;
+ int i, j;
+
+ struct {
+ int duplicate;
+ struct {
+ uint64_t starting_lba;
+ uint64_t ending_lba;
+ uint32_t type_guid;
+ uint32_t unique_guid;
+ } entries[16]; /* enough for testing. */
+ } cases[] = {
+ {GPT_SUCCESS, {{100, 109, 1, 1},
+ {110, 119, 2, 2},
+ {120, 129, 3, 3},
+ {130, 139, 4, 4},
+ }},
+ {GPT_SUCCESS, {{100, 109, 1, 1},
+ {110, 119, 1, 2},
+ {120, 129, 2, 3},
+ {130, 139, 2, 4},
+ }},
+ {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
+ {110, 119, 2, 2},
+ {120, 129, 3, 1},
+ {130, 139, 4, 4},
+ }},
+ {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
+ {110, 119, 1, 2},
+ {120, 129, 2, 3},
+ {130, 139, 2, 2},
+ }},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(cases); ++i) {
+ BuildTestGptData(gpt);
+ ZeroEntries(gpt);
+ for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
+ if (!cases[i].entries[j].starting_lba)
+ break;
+
+ e[j].starting_lba = cases[i].entries[j].starting_lba;
+ e[j].ending_lba = cases[i].entries[j].ending_lba;
+ SetGuid(&e[j].type, cases[i].entries[j].type_guid);
+ SetGuid(&e[j].unique, cases[i].entries[j].unique_guid);
+ }
+ RefreshCrc32(gpt);
+
+ EXPECT(cases[i].duplicate == CheckEntries(e, h));
+ }
+
+ return TEST_OK;
+}
- return TEST_OK;
+/* Test getting the current kernel GUID */
+static int GetKernelGuidTest(void)
+{
+ GptData *gpt = GetEmptyGptData();
+ GptEntry *e = (GptEntry *)gpt->primary_entries;
+ Guid g;
+
+ BuildTestGptData(gpt);
+ gpt->current_kernel = 0;
+ GetCurrentKernelUniqueGuid(gpt, &g);
+ EXPECT(!Memcmp(&g, &e[0].unique, sizeof(Guid)));
+ gpt->current_kernel = 1;
+ GetCurrentKernelUniqueGuid(gpt, &g);
+ EXPECT(!Memcmp(&g, &e[1].unique, sizeof(Guid)));
+
+ return TEST_OK;
}
+/* Test getting GPT error text strings */
+static int ErrorTextTest(void)
+{
+ int i;
-/* Tests duplicate UniqueGuids can be detected. */
-static int DuplicateUniqueGuidTest() {
- GptData* gpt = GetEmptyGptData();
- GptHeader* h = (GptHeader*)gpt->primary_header;
- GptEntry* e = (GptEntry*)gpt->primary_entries;
- int i, j;
-
- struct {
- int duplicate;
- struct {
- uint64_t starting_lba;
- uint64_t ending_lba;
- uint32_t type_guid;
- uint32_t unique_guid;
- } entries[16]; /* enough for testing. */
- } cases[] = {
- {GPT_SUCCESS, {{100, 109, 1, 1},
- {110, 119, 2, 2},
- {120, 129, 3, 3},
- {130, 139, 4, 4},
- }},
- {GPT_SUCCESS, {{100, 109, 1, 1},
- {110, 119, 1, 2},
- {120, 129, 2, 3},
- {130, 139, 2, 4},
- }},
- {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
- {110, 119, 2, 2},
- {120, 129, 3, 1},
- {130, 139, 4, 4},
- }},
- {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
- {110, 119, 1, 2},
- {120, 129, 2, 3},
- {130, 139, 2, 2},
- }},
- };
-
- for (i = 0; i < ARRAY_SIZE(cases); ++i) {
- BuildTestGptData(gpt);
- ZeroEntries(gpt);
- for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
- if (!cases[i].entries[j].starting_lba)
- break;
-
- e[j].starting_lba = cases[i].entries[j].starting_lba;
- e[j].ending_lba = cases[i].entries[j].ending_lba;
- SetGuid(&e[j].type, cases[i].entries[j].type_guid);
- SetGuid(&e[j].unique, cases[i].entries[j].unique_guid);
- }
- RefreshCrc32(gpt);
-
- EXPECT(cases[i].duplicate == CheckEntries(e, h));
- }
- return TEST_OK;
-}
+ /* Known errors are not unknown */
+ for (i = 0; i < GPT_ERROR_COUNT; i++) {
+ EXPECT(GptErrorText(i));
+ EXPECT(strcmp(GptErrorText(i), "Unknown"));
+ }
+ /* But other error values are */
+ EXPECT(!strcmp(GptErrorText(GPT_ERROR_COUNT), "Unknown"));
+ return TEST_OK;
+}
/* disable MSVC warnings on unused arguments */
__pragma(warning (disable: 4100))
-int main(int argc, char *argv[]) {
- int i;
- int error_count = 0;
- struct {
- char *name;
- test_func fp;
- int retval;
- } test_cases[] = {
- { TEST_CASE(StructSizeTest), },
- { TEST_CASE(TestBuildTestGptData), },
- { TEST_CASE(ParameterTests), },
- { TEST_CASE(HeaderCrcTest), },
- { TEST_CASE(SignatureTest), },
- { TEST_CASE(RevisionTest), },
- { TEST_CASE(SizeTest), },
- { TEST_CASE(CrcFieldTest), },
- { TEST_CASE(ReservedFieldsTest), },
- { TEST_CASE(SizeOfPartitionEntryTest), },
- { TEST_CASE(NumberOfPartitionEntriesTest), },
- { TEST_CASE(MyLbaTest), },
- { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
- { TEST_CASE(EntriesCrcTest), },
- { TEST_CASE(ValidEntryTest), },
- { TEST_CASE(OverlappedPartitionTest), },
- { TEST_CASE(SanityCheckTest), },
- { TEST_CASE(NoValidKernelEntryTest), },
- { TEST_CASE(EntryAttributeGetSetTest), },
- { TEST_CASE(EntryTypeTest), },
- { TEST_CASE(GetNextNormalTest), },
- { TEST_CASE(GetNextPrioTest), },
- { TEST_CASE(GetNextTriesTest), },
- { TEST_CASE(GptUpdateTest), },
- { TEST_CASE(UpdateInvalidKernelTypeTest), },
- { TEST_CASE(DuplicateUniqueGuidTest), },
- { TEST_CASE(TestCrc32TestVectors), },
- };
-
- for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
- printf("Running %s() ...\n", test_cases[i].name);
- test_cases[i].retval = test_cases[i].fp();
- if (test_cases[i].retval) {
- printf(COL_RED "[ERROR]\n\n" COL_STOP);
- ++error_count;
- } else {
- printf(COL_GREEN "[PASS]\n\n" COL_STOP);
- }
- }
-
- if (error_count) {
- printf("\n--------------------------------------------------\n");
- printf(COL_RED "The following %d test cases are failed:\n" COL_STOP,
- error_count);
- for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
- if (test_cases[i].retval)
- printf(" %s()\n", test_cases[i].name);
- }
- }
-
- return (error_count) ? 1 : 0;
+int main(int argc, char *argv[])
+{
+ int i;
+ int error_count = 0;
+ struct {
+ char *name;
+ test_func fp;
+ int retval;
+ } test_cases[] = {
+ { TEST_CASE(StructSizeTest), },
+ { TEST_CASE(TestBuildTestGptData), },
+ { TEST_CASE(ParameterTests), },
+ { TEST_CASE(HeaderCrcTest), },
+ { TEST_CASE(HeaderSameTest), },
+ { TEST_CASE(SignatureTest), },
+ { TEST_CASE(RevisionTest), },
+ { TEST_CASE(SizeTest), },
+ { TEST_CASE(CrcFieldTest), },
+ { TEST_CASE(ReservedFieldsTest), },
+ { TEST_CASE(SizeOfPartitionEntryTest), },
+ { TEST_CASE(NumberOfPartitionEntriesTest), },
+ { TEST_CASE(MyLbaTest), },
+ { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
+ { TEST_CASE(EntriesCrcTest), },
+ { TEST_CASE(ValidEntryTest), },
+ { TEST_CASE(OverlappedPartitionTest), },
+ { TEST_CASE(SanityCheckTest), },
+ { TEST_CASE(NoValidKernelEntryTest), },
+ { TEST_CASE(EntryAttributeGetSetTest), },
+ { TEST_CASE(EntryTypeTest), },
+ { TEST_CASE(GetNextNormalTest), },
+ { TEST_CASE(GetNextPrioTest), },
+ { TEST_CASE(GetNextTriesTest), },
+ { TEST_CASE(GptUpdateTest), },
+ { TEST_CASE(UpdateInvalidKernelTypeTest), },
+ { TEST_CASE(DuplicateUniqueGuidTest), },
+ { TEST_CASE(TestCrc32TestVectors), },
+ { TEST_CASE(GetKernelGuidTest), },
+ { TEST_CASE(ErrorTextTest), },
+ };
+
+ for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
+ printf("Running %s() ...\n", test_cases[i].name);
+ test_cases[i].retval = test_cases[i].fp();
+ if (test_cases[i].retval) {
+ printf(COL_RED "[ERROR]\n\n" COL_STOP);
+ ++error_count;
+ } else {
+ printf(COL_GREEN "[PASS]\n\n" COL_STOP);
+ }
+ }
+
+ if (error_count) {
+ printf("\n------------------------------------------------\n");
+ printf(COL_RED "The following %d test cases are failed:\n"
+ COL_STOP, error_count);
+ for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
+ if (test_cases[i].retval)
+ printf(" %s()\n", test_cases[i].name);
+ }
+ }
+
+ return error_count ? 1 : 0;
}
diff --git a/tests/rollback_index2_tests.c b/tests/rollback_index2_tests.c
index 4a12a6e2..b670812d 100644
--- a/tests/rollback_index2_tests.c
+++ b/tests/rollback_index2_tests.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -18,7 +18,8 @@
#include "utility.h"
#include "vboot_common.h"
-/* Buffer to hold accumulated list of calls to mocked Tlcl functions.
+/*
+ * Buffer to hold accumulated list of calls to mocked Tlcl functions.
* Each function appends itself to the buffer and updates mock_cnext.
*
* Size of mock_calls[] should be big enough to handle all expected
@@ -28,13 +29,16 @@
* making all the mock implementations bigger. If this were code used
* outside of unit tests we'd want to do that, but here if we did
* overrun the buffer the worst that's likely to happen is we'll crash
- * the test, and crash = failure anyway. */
+ * the test, and crash = failure anyway.
+ */
static char mock_calls[16384];
static char *mock_cnext = mock_calls;
-/* Variables to support mocked error values from Tlcl functions. Each
+/*
+ * Variables to support mocked error values from Tlcl functions. Each
* call, mock_count is incremented. If mock_count==fail_at_count, return
- * fail_with_error instead of the normal return value. */
+ * fail_with_error instead of the normal return value.
+ */
static int mock_count = 0;
static int fail_at_count = 0;
static uint32_t fail_with_error = TPM_SUCCESS;
@@ -44,7 +48,6 @@ static uint32_t fail_with_error = TPM_SUCCESS;
static int noise_count = 0; /* read/write attempt (zero-based) */
static int noise_on[MAX_NOISE_COUNT]; /* calls to inject noise on */
-
/* Params / backing store for mocked Tlcl functions. */
static TPM_PERMANENT_FLAGS mock_pflags;
static RollbackSpaceFirmware mock_rsf;
@@ -52,858 +55,937 @@ static RollbackSpaceKernel mock_rsk;
static uint32_t mock_permissions;
/* Reset the variables for the Tlcl mock functions. */
-static void ResetMocks(int fail_on_call, uint32_t fail_with_err) {
- *mock_calls = 0;
- mock_cnext = mock_calls;
- mock_count = 0;
- fail_at_count = fail_on_call;
- fail_with_error = fail_with_err;
- noise_count = 0;
- Memset(&noise_on, 0, sizeof(noise_on));
-
- Memset(&mock_pflags, 0, sizeof(mock_pflags));
- Memset(&mock_rsf, 0, sizeof(mock_rsf));
- Memset(&mock_rsk, 0, sizeof(mock_rsk));
- mock_permissions = 0;
+static void ResetMocks(int fail_on_call, uint32_t fail_with_err)
+{
+ *mock_calls = 0;
+ mock_cnext = mock_calls;
+ mock_count = 0;
+ fail_at_count = fail_on_call;
+ fail_with_error = fail_with_err;
+ noise_count = 0;
+ Memset(&noise_on, 0, sizeof(noise_on));
+
+ Memset(&mock_pflags, 0, sizeof(mock_pflags));
+ Memset(&mock_rsf, 0, sizeof(mock_rsf));
+ Memset(&mock_rsk, 0, sizeof(mock_rsk));
+ mock_permissions = 0;
}
/****************************************************************************/
/* Function to garble data on its way to or from the TPM */
-static void MaybeInjectNoise(void* data, uint32_t length) {
- if (noise_count < MAX_NOISE_COUNT && noise_on[noise_count]) {
- uint8_t *val = data;
- val[length-1]++;
- }
- noise_count++;
+static void MaybeInjectNoise(void *data, uint32_t length)
+{
+ if (noise_count < MAX_NOISE_COUNT && noise_on[noise_count]) {
+ uint8_t *val = data;
+ val[length - 1]++;
+ }
+ noise_count++;
}
/****************************************************************************/
/* Mocks for tlcl functions which log the calls made to mock_calls[]. */
-uint32_t TlclLibInit(void) {
- mock_cnext += sprintf(mock_cnext, "TlclLibInit()\n");
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclLibInit(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclLibInit()\n");
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclStartup(void) {
- mock_cnext += sprintf(mock_cnext, "TlclStartup()\n");
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclStartup(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclStartup()\n");
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclResume(void) {
- mock_cnext += sprintf(mock_cnext, "TlclResume()\n");
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclResume(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclResume()\n");
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclForceClear(void) {
- mock_cnext += sprintf(mock_cnext, "TlclForceClear()\n");
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclForceClear(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclForceClear()\n");
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclSetEnable(void) {
- mock_cnext += sprintf(mock_cnext, "TlclSetEnable()\n");
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclSetEnable(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclSetEnable()\n");
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclSetDeactivated(uint8_t flag) {
- mock_cnext += sprintf(mock_cnext, "TlclSetDeactivated(%d)\n", flag);
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclSetDeactivated(uint8_t flag)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclSetDeactivated(%d)\n", flag);
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclRead(uint32_t index, void* data, uint32_t length) {
- mock_cnext += sprintf(mock_cnext, "TlclRead(0x%x, %d)\n", index, length);
-
- if (FIRMWARE_NV_INDEX == index) {
- TEST_EQ(length, sizeof(mock_rsf), "TlclRead rsf size");
- Memcpy(data, &mock_rsf, length);
- MaybeInjectNoise(data, length);
- } else if (KERNEL_NV_INDEX == index) {
- TEST_EQ(length, sizeof(mock_rsk), "TlclRead rsk size");
- Memcpy(data, &mock_rsk, length);
- MaybeInjectNoise(data, length);
- } else {
- Memset(data, 0, length);
- }
-
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclRead(uint32_t index, void* data, uint32_t length)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclRead(0x%x, %d)\n",
+ index, length);
+
+ if (FIRMWARE_NV_INDEX == index) {
+ TEST_EQ(length, sizeof(mock_rsf), "TlclRead rsf size");
+ Memcpy(data, &mock_rsf, length);
+ MaybeInjectNoise(data, length);
+ } else if (KERNEL_NV_INDEX == index) {
+ TEST_EQ(length, sizeof(mock_rsk), "TlclRead rsk size");
+ Memcpy(data, &mock_rsk, length);
+ MaybeInjectNoise(data, length);
+ } else {
+ Memset(data, 0, length);
+ }
+
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclWrite(uint32_t index, const void* data, uint32_t length) {
- mock_cnext += sprintf(mock_cnext, "TlclWrite(0x%x, %d)\n", index, length);
-
- if (FIRMWARE_NV_INDEX == index) {
- TEST_EQ(length, sizeof(mock_rsf), "TlclWrite rsf size");
- Memcpy(&mock_rsf, data, length);
- MaybeInjectNoise(&mock_rsf, length);
- } else if (KERNEL_NV_INDEX == index) {
- TEST_EQ(length, sizeof(mock_rsk), "TlclWrite rsk size");
- Memcpy(&mock_rsk, data, length);
- MaybeInjectNoise(&mock_rsk, length);
- }
-
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclWrite(uint32_t index, const void *data, uint32_t length)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclWrite(0x%x, %d)\n",
+ index, length);
+
+ if (FIRMWARE_NV_INDEX == index) {
+ TEST_EQ(length, sizeof(mock_rsf), "TlclWrite rsf size");
+ Memcpy(&mock_rsf, data, length);
+ MaybeInjectNoise(&mock_rsf, length);
+ } else if (KERNEL_NV_INDEX == index) {
+ TEST_EQ(length, sizeof(mock_rsk), "TlclWrite rsk size");
+ Memcpy(&mock_rsk, data, length);
+ MaybeInjectNoise(&mock_rsk, length);
+ }
+
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size) {
- mock_cnext += sprintf(mock_cnext, "TlclDefineSpace(0x%x, 0x%x, %d)\n",
- index, perm, size);
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclDefineSpace(0x%x, 0x%x, %d)\n",
+ index, perm, size);
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclSelfTestFull(void) {
- mock_cnext += sprintf(mock_cnext, "TlclSelfTestFull()\n");
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclSelfTestFull(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclSelfTestFull()\n");
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclContinueSelfTest(void) {
- mock_cnext += sprintf(mock_cnext, "TlclContinueSelfTest()\n");
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclContinueSelfTest(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclContinueSelfTest()\n");
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS* pflags) {
- mock_cnext += sprintf(mock_cnext, "TlclGetPermanentFlags()\n");
- Memcpy(pflags, &mock_pflags, sizeof(mock_pflags));
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS *pflags)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclGetPermanentFlags()\n");
+ Memcpy(pflags, &mock_pflags, sizeof(mock_pflags));
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
/* TlclGetFlags() doesn't need mocking; it calls TlclGetPermanentFlags() */
-uint32_t TlclAssertPhysicalPresence(void) {
- mock_cnext += sprintf(mock_cnext, "TlclAssertPhysicalPresence()\n");
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclAssertPhysicalPresence(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclAssertPhysicalPresence()\n");
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclFinalizePhysicalPresence(void) {
- mock_cnext += sprintf(mock_cnext, "TlclFinalizePhysicalPresence()\n");
- mock_pflags.physicalPresenceLifetimeLock = 1;
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclFinalizePhysicalPresence(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclFinalizePhysicalPresence()\n");
+ mock_pflags.physicalPresenceLifetimeLock = 1;
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclPhysicalPresenceCMDEnable(void) {
- mock_cnext += sprintf(mock_cnext, "TlclPhysicalPresenceCMDEnable()\n");
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclPhysicalPresenceCMDEnable(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclPhysicalPresenceCMDEnable()\n");
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclSetNvLocked(void) {
- mock_cnext += sprintf(mock_cnext, "TlclSetNvLocked()\n");
- mock_pflags.nvLocked = 1;
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclSetNvLocked(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclSetNvLocked()\n");
+ mock_pflags.nvLocked = 1;
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclSetGlobalLock(void) {
- mock_cnext += sprintf(mock_cnext, "TlclSetGlobalLock()\n");
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclSetGlobalLock(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclSetGlobalLock()\n");
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclLockPhysicalPresence(void) {
- mock_cnext += sprintf(mock_cnext, "TlclLockPhysicalPresence()\n");
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclLockPhysicalPresence(void)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclLockPhysicalPresence()\n");
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-uint32_t TlclGetPermissions(uint32_t index, uint32_t* permissions) {
- mock_cnext += sprintf(mock_cnext, "TlclGetPermissions(0x%x)\n", index);
- *permissions = mock_permissions;
- return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
+uint32_t TlclGetPermissions(uint32_t index, uint32_t* permissions)
+{
+ mock_cnext += sprintf(mock_cnext, "TlclGetPermissions(0x%x)\n", index);
+ *permissions = mock_permissions;
+ return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
-
/****************************************************************************/
/* Tests for CRC errors */
-extern uint32_t ReadSpaceFirmware(RollbackSpaceFirmware* rsf);
-extern uint32_t WriteSpaceFirmware(RollbackSpaceFirmware* rsf);
-
-static void CrcTestFirmware(void) {
- RollbackSpaceFirmware rsf;
-
- /* noise on reading, shouldn't matter here because version == 0 */
- ResetMocks(0, 0);
- noise_on[0] = 1;
- TEST_EQ(ReadSpaceFirmware(&rsf), 0, "ReadSpaceFirmware(), v0");
- TEST_STR_EQ(mock_calls,
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- /* But if the version >= 2, it will try three times and fail because the CRC
- * is no good. */
- ResetMocks(0, 0);
- mock_rsf.struct_version = 2;
- TEST_EQ(ReadSpaceFirmware(&rsf), TPM_E_CORRUPTED_STATE,
- "ReadSpaceFirmware(), v2, bad CRC");
- TEST_STR_EQ(mock_calls,
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- /* OTOH, if the CRC is good and some noise happens, it should recover. */
- ResetMocks(0, 0);
- mock_rsf.struct_version = 2;
- mock_rsf.crc8 = Crc8(&mock_rsf, offsetof(RollbackSpaceFirmware, crc8));
- noise_on[0] = 1;
- TEST_EQ(ReadSpaceFirmware(&rsf), 0, "ReadSpaceFirmware(), v2, good CRC");
- TEST_STR_EQ(mock_calls,
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- /* A write with version < 2 should convert to v2 and create the CRC */
- ResetMocks(0, 0);
- Memset(&rsf, 0, sizeof(rsf));
- TEST_EQ(WriteSpaceFirmware(&rsf), 0, "WriteSpaceFirmware(), v0");
- TEST_EQ(mock_rsf.struct_version, 2, "WriteSpaceFirmware(), check v2");
- TEST_STR_EQ(mock_calls,
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- /* Same as above, but with some noise during the readback */
- ResetMocks(0, 0);
- Memset(&rsf, 0, sizeof(rsf));
- noise_on[1] = 1;
- noise_on[2] = 1;
- TEST_EQ(WriteSpaceFirmware(&rsf), 0, "WriteSpaceFirmware(), read noise");
- TEST_STR_EQ(mock_calls,
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- /* With noise during the write, we'll try the write again */
- ResetMocks(0, 0);
- Memset(&rsf, 0, sizeof(rsf));
- noise_on[0] = 1;
- TEST_EQ(WriteSpaceFirmware(&rsf), 0, "WriteSpaceFirmware(), write noise");
- TEST_EQ(mock_rsf.struct_version, 2, "WriteSpaceFirmware(), check v2");
- TEST_STR_EQ(mock_calls,
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- /* Only if it just keeps on failing forever do we eventually give up */
- ResetMocks(0, 0);
- Memset(&rsf, 0, sizeof(rsf));
- Memset(noise_on, 1, sizeof(noise_on));
- TEST_EQ(WriteSpaceFirmware(&rsf), TPM_E_CORRUPTED_STATE,
- "WriteSpaceFirmware(), always noise");
- TEST_STR_EQ(mock_calls,
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
+extern uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf);
+extern uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf);
+
+static void CrcTestFirmware(void)
+{
+ RollbackSpaceFirmware rsf;
+
+ /* Noise on reading, shouldn't matter here because version == 0 */
+ ResetMocks(0, 0);
+ noise_on[0] = 1;
+ TEST_EQ(ReadSpaceFirmware(&rsf), 0, "ReadSpaceFirmware(), v0");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /*
+ * But if the version >= 2, it will try three times and fail because
+ * the CRC is no good.
+ */
+ ResetMocks(0, 0);
+ mock_rsf.struct_version = 2;
+ TEST_EQ(ReadSpaceFirmware(&rsf), TPM_E_CORRUPTED_STATE,
+ "ReadSpaceFirmware(), v2, bad CRC");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* If the CRC is good and some noise happens, it should recover. */
+ ResetMocks(0, 0);
+ mock_rsf.struct_version = 2;
+ mock_rsf.crc8 = Crc8(&mock_rsf, offsetof(RollbackSpaceFirmware, crc8));
+ noise_on[0] = 1;
+ TEST_EQ(ReadSpaceFirmware(&rsf), 0,
+ "ReadSpaceFirmware(), v2, good CRC");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* A write with version < 2 should convert to v2 and create the CRC */
+ ResetMocks(0, 0);
+ Memset(&rsf, 0, sizeof(rsf));
+ TEST_EQ(WriteSpaceFirmware(&rsf), 0, "WriteSpaceFirmware(), v0");
+ TEST_EQ(mock_rsf.struct_version, 2, "WriteSpaceFirmware(), check v2");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* Same as above, but with some noise during the readback */
+ ResetMocks(0, 0);
+ Memset(&rsf, 0, sizeof(rsf));
+ noise_on[1] = 1;
+ noise_on[2] = 1;
+ TEST_EQ(WriteSpaceFirmware(&rsf), 0,
+ "WriteSpaceFirmware(), read noise");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* With noise during the write, we'll try the write again */
+ ResetMocks(0, 0);
+ Memset(&rsf, 0, sizeof(rsf));
+ noise_on[0] = 1;
+ TEST_EQ(WriteSpaceFirmware(&rsf), 0,
+ "WriteSpaceFirmware(), write noise");
+ TEST_EQ(mock_rsf.struct_version, 2, "WriteSpaceFirmware(), check v2");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* Only if it just keeps on failing forever do we eventually give up */
+ ResetMocks(0, 0);
+ Memset(&rsf, 0, sizeof(rsf));
+ Memset(noise_on, 1, sizeof(noise_on));
+ TEST_EQ(WriteSpaceFirmware(&rsf), TPM_E_CORRUPTED_STATE,
+ "WriteSpaceFirmware(), always noise");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
}
-extern uint32_t ReadSpaceKernel(RollbackSpaceKernel* rsk);
-extern uint32_t WriteSpaceKernel(RollbackSpaceKernel* rsk);
-
-static void CrcTestKernel(void) {
- RollbackSpaceKernel rsk;
-
- /* noise on reading, shouldn't matter here because version == 0 */
- ResetMocks(0, 0);
- noise_on[0] = 1;
- TEST_EQ(ReadSpaceKernel(&rsk), 0, "ReadSpaceKernel(), v0");
- TEST_STR_EQ(mock_calls,
- "TlclRead(0x1008, 13)\n",
- "tlcl calls");
-
- /* But if the version >= 2, it will try three times and fail because the CRC
- * is no good. */
- ResetMocks(0, 0);
- mock_rsk.struct_version = 2;
- TEST_EQ(ReadSpaceKernel(&rsk), TPM_E_CORRUPTED_STATE,
- "ReadSpaceKernel(), v2, bad CRC");
- TEST_STR_EQ(mock_calls,
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n",
- "tlcl calls");
-
- /* OTOH, if the CRC is good and some noise happens, it should recover. */
- ResetMocks(0, 0);
- mock_rsk.struct_version = 2;
- mock_rsk.crc8 = Crc8(&mock_rsk, offsetof(RollbackSpaceKernel, crc8));
- noise_on[0] = 1;
- TEST_EQ(ReadSpaceKernel(&rsk), 0, "ReadSpaceKernel(), v2, good CRC");
- TEST_STR_EQ(mock_calls,
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n",
- "tlcl calls");
-
- /* A write with version < 2 should convert to v2 and create the CRC */
- ResetMocks(0, 0);
- Memset(&rsk, 0, sizeof(rsk));
- TEST_EQ(WriteSpaceKernel(&rsk), 0, "WriteSpaceKernel(), v0");
- TEST_EQ(mock_rsk.struct_version, 2, "WriteSpaceKernel(), check v2");
- TEST_STR_EQ(mock_calls,
- "TlclWrite(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n",
- "tlcl calls");
-
- /* Same as above, but with some noise during the readback */
- ResetMocks(0, 0);
- Memset(&rsk, 0, sizeof(rsk));
- noise_on[1] = 1;
- noise_on[2] = 1;
- TEST_EQ(WriteSpaceKernel(&rsk), 0, "WriteSpaceKernel(), read noise");
- TEST_STR_EQ(mock_calls,
- "TlclWrite(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n",
- "tlcl calls");
-
- /* With noise during the write, we'll try the write again */
- ResetMocks(0, 0);
- Memset(&rsk, 0, sizeof(rsk));
- noise_on[0] = 1;
- TEST_EQ(WriteSpaceKernel(&rsk), 0, "WriteSpaceKernel(), write noise");
- TEST_EQ(mock_rsk.struct_version, 2, "WriteSpaceKernel(), check v2");
- TEST_STR_EQ(mock_calls,
- "TlclWrite(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclWrite(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n",
- "tlcl calls");
-
- /* Only if it just keeps on failing forever do we eventually give up */
- ResetMocks(0, 0);
- Memset(&rsk, 0, sizeof(rsk));
- Memset(noise_on, 1, sizeof(noise_on));
- TEST_EQ(WriteSpaceKernel(&rsk), TPM_E_CORRUPTED_STATE,
- "WriteSpaceKernel(), always noise");
- TEST_STR_EQ(mock_calls,
- "TlclWrite(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclWrite(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclWrite(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n",
- "tlcl calls");
+extern uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk);
+extern uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk);
+
+static void CrcTestKernel(void)
+{
+ RollbackSpaceKernel rsk;
+
+ /* Noise on reading shouldn't matter here because version == 0 */
+ ResetMocks(0, 0);
+ noise_on[0] = 1;
+ TEST_EQ(ReadSpaceKernel(&rsk), 0, "ReadSpaceKernel(), v0");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /*
+ * But if the version >= 2, it will try three times and fail because
+ * the CRC is no good.
+ */
+ ResetMocks(0, 0);
+ mock_rsk.struct_version = 2;
+ TEST_EQ(ReadSpaceKernel(&rsk), TPM_E_CORRUPTED_STATE,
+ "ReadSpaceKernel(), v2, bad CRC");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /* If the CRC is good and some noise happens, it should recover. */
+ ResetMocks(0, 0);
+ mock_rsk.struct_version = 2;
+ mock_rsk.crc8 = Crc8(&mock_rsk, offsetof(RollbackSpaceKernel, crc8));
+ noise_on[0] = 1;
+ TEST_EQ(ReadSpaceKernel(&rsk), 0, "ReadSpaceKernel(), v2, good CRC");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /* A write with version < 2 should convert to v2 and create the CRC */
+ ResetMocks(0, 0);
+ Memset(&rsk, 0, sizeof(rsk));
+ TEST_EQ(WriteSpaceKernel(&rsk), 0, "WriteSpaceKernel(), v0");
+ TEST_EQ(mock_rsk.struct_version, 2, "WriteSpaceKernel(), check v2");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /* Same as above, but with some noise during the readback */
+ ResetMocks(0, 0);
+ Memset(&rsk, 0, sizeof(rsk));
+ noise_on[1] = 1;
+ noise_on[2] = 1;
+ TEST_EQ(WriteSpaceKernel(&rsk), 0, "WriteSpaceKernel(), read noise");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /* With noise during the write, we'll try the write again */
+ ResetMocks(0, 0);
+ Memset(&rsk, 0, sizeof(rsk));
+ noise_on[0] = 1;
+ TEST_EQ(WriteSpaceKernel(&rsk), 0, "WriteSpaceKernel(), write noise");
+ TEST_EQ(mock_rsk.struct_version, 2, "WriteSpaceKernel(), check v2");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /* Only if it just keeps on failing forever do we eventually give up */
+ ResetMocks(0, 0);
+ Memset(&rsk, 0, sizeof(rsk));
+ Memset(noise_on, 1, sizeof(noise_on));
+ TEST_EQ(WriteSpaceKernel(&rsk), TPM_E_CORRUPTED_STATE,
+ "WriteSpaceKernel(), always noise");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
}
/****************************************************************************/
/* Tests for misc helper functions */
-static void MiscTest(void) {
- uint8_t buf[8];
-
- ResetMocks(0, 0);
- TEST_EQ(TPMClearAndReenable(), 0, "TPMClearAndReenable()");
- TEST_STR_EQ(mock_calls,
- "TlclForceClear()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n",
- "tlcl calls");
-
- ResetMocks(0, 0);
- TEST_EQ(SafeWrite(0x123, buf, 8), 0, "SafeWrite()");
- TEST_STR_EQ(mock_calls,
- "TlclWrite(0x123, 8)\n",
- "tlcl calls");
-
- ResetMocks(1, TPM_E_BADINDEX);
- TEST_EQ(SafeWrite(0x123, buf, 8), TPM_E_BADINDEX, "SafeWrite() bad");
- TEST_STR_EQ(mock_calls,
- "TlclWrite(0x123, 8)\n",
- "tlcl calls");
-
- ResetMocks(1, TPM_E_MAXNVWRITES);
- TEST_EQ(SafeWrite(0x123, buf, 8), 0, "SafeWrite() retry max writes");
- TEST_STR_EQ(mock_calls,
- "TlclWrite(0x123, 8)\n"
- "TlclForceClear()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n"
- "TlclWrite(0x123, 8)\n",
- "tlcl calls");
-
- ResetMocks(0, 0);
- TEST_EQ(SafeDefineSpace(0x123, 6, 8), 0, "SafeDefineSpace()");
- TEST_STR_EQ(mock_calls,
- "TlclDefineSpace(0x123, 0x6, 8)\n",
- "tlcl calls");
-
- ResetMocks(1, TPM_E_BADINDEX);
- TEST_EQ(SafeDefineSpace(0x123, 6, 8), TPM_E_BADINDEX,
- "SafeDefineSpace() bad");
- TEST_STR_EQ(mock_calls,
- "TlclDefineSpace(0x123, 0x6, 8)\n",
- "tlcl calls");
-
- ResetMocks(1, TPM_E_MAXNVWRITES);
- TEST_EQ(SafeDefineSpace(0x123, 6, 8), 0,
- "SafeDefineSpace() retry max writes");
- TEST_STR_EQ(mock_calls,
- "TlclDefineSpace(0x123, 0x6, 8)\n"
- "TlclForceClear()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n"
- "TlclDefineSpace(0x123, 0x6, 8)\n",
- "tlcl calls");
+static void MiscTest(void)
+{
+ uint8_t buf[8];
+
+ ResetMocks(0, 0);
+ TEST_EQ(TPMClearAndReenable(), 0, "TPMClearAndReenable()");
+ TEST_STR_EQ(mock_calls,
+ "TlclForceClear()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n",
+ "tlcl calls");
+
+ ResetMocks(0, 0);
+ TEST_EQ(SafeWrite(0x123, buf, 8), 0, "SafeWrite()");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x123, 8)\n",
+ "tlcl calls");
+
+ ResetMocks(1, TPM_E_BADINDEX);
+ TEST_EQ(SafeWrite(0x123, buf, 8), TPM_E_BADINDEX, "SafeWrite() bad");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x123, 8)\n",
+ "tlcl calls");
+
+ ResetMocks(1, TPM_E_MAXNVWRITES);
+ TEST_EQ(SafeWrite(0x123, buf, 8), 0, "SafeWrite() retry max writes");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x123, 8)\n"
+ "TlclForceClear()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n"
+ "TlclWrite(0x123, 8)\n",
+ "tlcl calls");
+
+ ResetMocks(0, 0);
+ TEST_EQ(SafeDefineSpace(0x123, 6, 8), 0, "SafeDefineSpace()");
+ TEST_STR_EQ(mock_calls,
+ "TlclDefineSpace(0x123, 0x6, 8)\n",
+ "tlcl calls");
+
+ ResetMocks(1, TPM_E_BADINDEX);
+ TEST_EQ(SafeDefineSpace(0x123, 6, 8), TPM_E_BADINDEX,
+ "SafeDefineSpace() bad");
+ TEST_STR_EQ(mock_calls,
+ "TlclDefineSpace(0x123, 0x6, 8)\n",
+ "tlcl calls");
+
+ ResetMocks(1, TPM_E_MAXNVWRITES);
+ TEST_EQ(SafeDefineSpace(0x123, 6, 8), 0,
+ "SafeDefineSpace() retry max writes");
+ TEST_STR_EQ(mock_calls,
+ "TlclDefineSpace(0x123, 0x6, 8)\n"
+ "TlclForceClear()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n"
+ "TlclDefineSpace(0x123, 0x6, 8)\n",
+ "tlcl calls");
}
/****************************************************************************/
/* Tests for one-time initialization */
-static void OneTimeInitTest(void) {
- RollbackSpaceFirmware rsf;
- RollbackSpaceKernel rsk;
-
- /* Complete initialization */
- ResetMocks(0, 0);
- TEST_EQ(OneTimeInitializeTPM(&rsf, &rsk), 0, "OneTimeInitializeTPM()");
- TEST_STR_EQ(mock_calls,
- "TlclSelfTestFull()\n"
- "TlclGetPermanentFlags()\n"
- "TlclFinalizePhysicalPresence()\n"
- "TlclSetNvLocked()\n"
- "TlclForceClear()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n"
- /* kernel space */
- "TlclDefineSpace(0x1008, 0x1, 13)\n"
- "TlclWrite(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- /* firmware space */
- "TlclDefineSpace(0x1007, 0x8001, 10)\n"
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
- TEST_EQ(mock_rsf.struct_version, ROLLBACK_SPACE_FIRMWARE_VERSION, "rsf ver");
- TEST_EQ(mock_rsf.flags, 0, "rsf flags");
- TEST_EQ(mock_rsf.fw_versions, 0, "rsf fw_versions");
- TEST_EQ(mock_rsk.struct_version, ROLLBACK_SPACE_KERNEL_VERSION, "rsk ver");
- TEST_EQ(mock_rsk.uid, ROLLBACK_SPACE_KERNEL_UID, "rsk uid");
- TEST_EQ(mock_rsk.kernel_versions, 0, "rsk kernel_versions");
-
- /* Physical presence already initialized */
- ResetMocks(0, 0);
- mock_pflags.physicalPresenceLifetimeLock = 1;
- TEST_EQ(OneTimeInitializeTPM(&rsf, &rsk), 0, "OneTimeInitializeTPM()");
- TEST_STR_EQ(mock_calls,
- "TlclSelfTestFull()\n"
- "TlclGetPermanentFlags()\n"
- "TlclSetNvLocked()\n"
- "TlclForceClear()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n"
- /* kernel space */
- "TlclDefineSpace(0x1008, 0x1, 13)\n"
- "TlclWrite(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- /* firmware space */
- "TlclDefineSpace(0x1007, 0x8001, 10)\n"
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- /* NV locking already initialized */
- ResetMocks(0, 0);
- mock_pflags.nvLocked = 1;
- TEST_EQ(OneTimeInitializeTPM(&rsf, &rsk), 0, "OneTimeInitializeTPM()");
- TEST_STR_EQ(mock_calls,
- "TlclSelfTestFull()\n"
- "TlclGetPermanentFlags()\n"
- "TlclFinalizePhysicalPresence()\n"
- "TlclForceClear()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n"
- /* kernel space */
- "TlclDefineSpace(0x1008, 0x1, 13)\n"
- "TlclWrite(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- /* firmware space */
- "TlclDefineSpace(0x1007, 0x8001, 10)\n"
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- /* Self test error */
- ResetMocks(1, TPM_E_IOERROR);
- TEST_EQ(OneTimeInitializeTPM(&rsf, &rsk), TPM_E_IOERROR,
- "OneTimeInitializeTPM() selftest");
- TEST_STR_EQ(mock_calls,
- "TlclSelfTestFull()\n",
- "tlcl calls");
+static void OneTimeInitTest(void)
+{
+ RollbackSpaceFirmware rsf;
+ RollbackSpaceKernel rsk;
+
+ /* Complete initialization */
+ ResetMocks(0, 0);
+ TEST_EQ(OneTimeInitializeTPM(&rsf, &rsk), 0, "OneTimeInitializeTPM()");
+ TEST_STR_EQ(mock_calls,
+ "TlclSelfTestFull()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclFinalizePhysicalPresence()\n"
+ "TlclSetNvLocked()\n"
+ "TlclForceClear()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n"
+ /* kernel space */
+ "TlclDefineSpace(0x1008, 0x1, 13)\n"
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ /* firmware space */
+ "TlclDefineSpace(0x1007, 0x8001, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+ TEST_EQ(mock_rsf.struct_version, ROLLBACK_SPACE_FIRMWARE_VERSION,
+ "rsf ver");
+ TEST_EQ(mock_rsf.flags, 0, "rsf flags");
+ TEST_EQ(mock_rsf.fw_versions, 0, "rsf fw_versions");
+ TEST_EQ(mock_rsk.struct_version, ROLLBACK_SPACE_KERNEL_VERSION,
+ "rsk ver");
+ TEST_EQ(mock_rsk.uid, ROLLBACK_SPACE_KERNEL_UID, "rsk uid");
+ TEST_EQ(mock_rsk.kernel_versions, 0, "rsk kernel_versions");
+
+ /* Physical presence already initialized */
+ ResetMocks(0, 0);
+ mock_pflags.physicalPresenceLifetimeLock = 1;
+ TEST_EQ(OneTimeInitializeTPM(&rsf, &rsk), 0, "OneTimeInitializeTPM()");
+ TEST_STR_EQ(mock_calls,
+ "TlclSelfTestFull()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclSetNvLocked()\n"
+ "TlclForceClear()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n"
+ /* kernel space */
+ "TlclDefineSpace(0x1008, 0x1, 13)\n"
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ /* firmware space */
+ "TlclDefineSpace(0x1007, 0x8001, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* NV locking already initialized */
+ ResetMocks(0, 0);
+ mock_pflags.nvLocked = 1;
+ TEST_EQ(OneTimeInitializeTPM(&rsf, &rsk), 0, "OneTimeInitializeTPM()");
+ TEST_STR_EQ(mock_calls,
+ "TlclSelfTestFull()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclFinalizePhysicalPresence()\n"
+ "TlclForceClear()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n"
+ /* kernel space */
+ "TlclDefineSpace(0x1008, 0x1, 13)\n"
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ /* firmware space */
+ "TlclDefineSpace(0x1007, 0x8001, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* Self test error */
+ ResetMocks(1, TPM_E_IOERROR);
+ TEST_EQ(OneTimeInitializeTPM(&rsf, &rsk), TPM_E_IOERROR,
+ "OneTimeInitializeTPM() selftest");
+ TEST_STR_EQ(mock_calls,
+ "TlclSelfTestFull()\n",
+ "tlcl calls");
}
/****************************************************************************/
/* Tests for TPM setup */
-static void SetupTpmTest(void) {
- RollbackSpaceFirmware rsf;
-
- /* Complete setup */
- ResetMocks(0, 0);
- TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), 0, "SetupTPM()");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclStartup()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclGetPermanentFlags()\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- /* If TPM is disabled or deactivated, must enable it */
- ResetMocks(0, 0);
- mock_pflags.disable = 1;
- TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), TPM_E_MUST_REBOOT, "SetupTPM() disabled");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclStartup()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclGetPermanentFlags()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n",
- "tlcl calls");
-
- ResetMocks(0, 0);
- mock_pflags.deactivated = 1;
- TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), TPM_E_MUST_REBOOT,
- "SetupTPM() deactivated");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclStartup()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclGetPermanentFlags()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n",
- "tlcl calls");
-
- /* If physical presence command isn't enabled, should try to enable it */
- ResetMocks(3, TPM_E_IOERROR);
- TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), 0, "SetupTPM() pp cmd");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclStartup()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclPhysicalPresenceCMDEnable()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclGetPermanentFlags()\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- /* If firmware space is missing, do one-time init */
- ResetMocks(5, TPM_E_BADINDEX);
- mock_pflags.physicalPresenceLifetimeLock = 1;
- mock_pflags.nvLocked = 1;
- TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), 0, "SetupTPM() no firmware space");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclStartup()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclGetPermanentFlags()\n"
- "TlclRead(0x1007, 10)\n"
- /* Calls from one-time init */
- "TlclSelfTestFull()\n"
- "TlclGetPermanentFlags()\n"
- "TlclForceClear()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n"
- "TlclDefineSpace(0x1008, 0x1, 13)\n"
- "TlclWrite(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n"
- "TlclDefineSpace(0x1007, 0x8001, 10)\n"
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- /* Other firmware space error is passed through */
- ResetMocks(5, TPM_E_IOERROR);
- TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), TPM_E_CORRUPTED_STATE,
- "SetupTPM() bad firmware space");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclStartup()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclGetPermanentFlags()\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- /* If developer flag has toggled, clear ownership and write new flag */
- ResetMocks(0, 0);
- TEST_EQ(SetupTPM(0, 1, 0, 0, &rsf), 0, "SetupTPM() to dev");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclStartup()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclGetPermanentFlags()\n"
- "TlclRead(0x1007, 10)\n"
- "TlclForceClear()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n"
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
- TEST_EQ(mock_rsf.flags, FLAG_LAST_BOOT_DEVELOPER, "fw space flags to dev 1");
-
- ResetMocks(0, 0);
- mock_rsf.flags = FLAG_LAST_BOOT_DEVELOPER;
- TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), 0, "SetupTPM() from dev");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclStartup()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclGetPermanentFlags()\n"
- "TlclRead(0x1007, 10)\n"
- "TlclForceClear()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n"
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
- TEST_EQ(mock_rsf.flags, 0, "fw space flags from dev 1");
-
- /* If TPM clear request, clear ownership also */
- ResetMocks(0, 0);
- TEST_EQ(SetupTPM(0, 0, 0, 1, &rsf), 0, "SetupTPM() clear owner");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclStartup()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclGetPermanentFlags()\n"
- "TlclRead(0x1007, 10)\n"
- "TlclForceClear()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n",
- "tlcl calls");
-
- /* Note: SetupTPM() recovery_mode parameter sets a global flag in
- * rollback_index.c; this is tested along with RollbackKernelLock() below. */
+static void SetupTpmTest(void)
+{
+ RollbackSpaceFirmware rsf;
+
+ /* Complete setup */
+ ResetMocks(0, 0);
+ TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), 0, "SetupTPM()");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclStartup()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* If TPM is disabled or deactivated, must enable it */
+ ResetMocks(0, 0);
+ mock_pflags.disable = 1;
+ TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), TPM_E_MUST_REBOOT,
+ "SetupTPM() disabled");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclStartup()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n",
+ "tlcl calls");
+
+ ResetMocks(0, 0);
+ mock_pflags.deactivated = 1;
+ TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), TPM_E_MUST_REBOOT,
+ "SetupTPM() deactivated");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclStartup()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n",
+ "tlcl calls");
+
+ /* If physical presence command isn't enabled, try to enable it */
+ ResetMocks(3, TPM_E_IOERROR);
+ TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), 0, "SetupTPM() pp cmd");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclStartup()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclPhysicalPresenceCMDEnable()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* If firmware space is missing, do one-time init */
+ ResetMocks(5, TPM_E_BADINDEX);
+ mock_pflags.physicalPresenceLifetimeLock = 1;
+ mock_pflags.nvLocked = 1;
+ TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), 0, "SetupTPM() no firmware space");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclStartup()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclRead(0x1007, 10)\n"
+ /* Calls from one-time init */
+ "TlclSelfTestFull()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclForceClear()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n"
+ "TlclDefineSpace(0x1008, 0x1, 13)\n"
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclDefineSpace(0x1007, 0x8001, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* Other firmware space error is passed through */
+ ResetMocks(5, TPM_E_IOERROR);
+ TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), TPM_E_CORRUPTED_STATE,
+ "SetupTPM() bad firmware space");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclStartup()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* If developer flag has toggled, clear ownership and write new flag */
+ ResetMocks(0, 0);
+ TEST_EQ(SetupTPM(0, 1, 0, 0, &rsf), 0, "SetupTPM() to dev");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclStartup()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclForceClear()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+ TEST_EQ(mock_rsf.flags, FLAG_LAST_BOOT_DEVELOPER,
+ "fw space flags to dev 1");
+
+ ResetMocks(0, 0);
+ mock_rsf.flags = FLAG_LAST_BOOT_DEVELOPER;
+ TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), 0, "SetupTPM() from dev");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclStartup()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclForceClear()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+ TEST_EQ(mock_rsf.flags, 0, "fw space flags from dev 1");
+
+ /* If TPM clear request, clear ownership also */
+ ResetMocks(0, 0);
+ TEST_EQ(SetupTPM(0, 0, 0, 1, &rsf), 0, "SetupTPM() clear owner");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclStartup()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclForceClear()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n",
+ "tlcl calls");
+
+ /* Handle request to clear virtual dev switch */
+ ResetMocks(0, 0);
+ mock_rsf.flags = FLAG_VIRTUAL_DEV_MODE_ON | FLAG_LAST_BOOT_DEVELOPER;
+ TEST_EQ(SetupTPM(0, 0, 1, 0, &rsf), 0, "SetupTPM() clear virtual dev");
+ TEST_EQ(mock_rsf.flags, 0, "Clear virtual dev");
+
+ /* If virtual dev switch is on, that should set last boot developer */
+ ResetMocks(0, 0);
+ mock_rsf.flags = FLAG_VIRTUAL_DEV_MODE_ON;
+ SetupTPM(0, 0, 0, 0, &rsf);
+ TEST_EQ(mock_rsf.flags,
+ FLAG_VIRTUAL_DEV_MODE_ON | FLAG_LAST_BOOT_DEVELOPER,
+ "virtual dev sets last boot");
+
+ /*
+ * Note: SetupTPM() recovery_mode parameter sets a global flag in
+ * rollback_index.c; this is tested along with RollbackKernelLock()
+ * below.
+ */
}
/****************************************************************************/
/* Tests for RollbackFirmware() calls */
-static void RollbackFirmwareTest(void) {
- uint32_t version;
- int dev_mode;
-
- /* Normal setup */
- ResetMocks(0, 0);
- dev_mode = 0;
- version = 123;
- mock_rsf.fw_versions = 0x12345678;
- TEST_EQ(RollbackFirmwareSetup(0, 0, dev_mode, 0, &dev_mode, &version), 0,
- "RollbackFirmwareSetup()");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclStartup()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclGetPermanentFlags()\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
- TEST_EQ(version, 0x12345678, "RollbackFirmwareSetup() version");
-
- /* Error during setup should clear version */
- ResetMocks(1, TPM_E_IOERROR);
- dev_mode = 0;
- version = 123;
- mock_rsf.fw_versions = 0x12345678;
- TEST_EQ(RollbackFirmwareSetup(0, 0, dev_mode, 0, &dev_mode, &version),
- TPM_E_IOERROR,
- "RollbackFirmwareSetup() error");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n",
- "tlcl calls");
- TEST_EQ(version, 0, "RollbackFirmwareSetup() version on error");
-
- /* Developer mode flag gets passed properly */
- ResetMocks(0, 0);
- dev_mode = 1;
- TEST_EQ(RollbackFirmwareSetup(0, dev_mode, 0, 0, &dev_mode, &version), 0,
- "RollbackFirmwareSetup() to dev");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclStartup()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclGetPermanentFlags()\n"
- "TlclRead(0x1007, 10)\n"
- "TlclForceClear()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n"
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
- TEST_EQ(mock_rsf.flags, FLAG_LAST_BOOT_DEVELOPER, "fw space flags to dev 2");
-
- /* So does clear-TPM request */
- ResetMocks(0, 0);
- dev_mode = 0;
- TEST_EQ(RollbackFirmwareSetup(0, dev_mode, 0, 1, &dev_mode, &version), 0,
- "RollbackFirmwareSetup() clear owner");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclStartup()\n"
- "TlclAssertPhysicalPresence()\n"
- "TlclGetPermanentFlags()\n"
- "TlclRead(0x1007, 10)\n"
- "TlclForceClear()\n"
- "TlclSetEnable()\n"
- "TlclSetDeactivated(0)\n",
- "tlcl calls");
-
- /* Test write */
- ResetMocks(0, 0);
- TEST_EQ(RollbackFirmwareWrite(0xBEAD1234), 0, "RollbackFirmwareWrite()");
- TEST_EQ(mock_rsf.fw_versions, 0xBEAD1234, "RollbackFirmwareWrite() version");
- TEST_STR_EQ(mock_calls,
- "TlclRead(0x1007, 10)\n"
- "TlclWrite(0x1007, 10)\n"
- "TlclRead(0x1007, 10)\n",
- "tlcl calls");
-
- ResetMocks(1, TPM_E_IOERROR);
- TEST_EQ(RollbackFirmwareWrite(123), TPM_E_IOERROR,
- "RollbackFirmwareWrite() error");
-
- /* Test lock */
- ResetMocks(0, 0);
- TEST_EQ(RollbackFirmwareLock(), 0, "RollbackFirmwareLock()");
- TEST_STR_EQ(mock_calls,
- "TlclSetGlobalLock()\n",
- "tlcl calls");
-
- ResetMocks(1, TPM_E_IOERROR);
- TEST_EQ(RollbackFirmwareLock(), TPM_E_IOERROR,
- "RollbackFirmwareLock() error");
+
+static void RollbackFirmwareTest(void)
+{
+ uint32_t version;
+ int dev_mode;
+
+ /* Normal setup */
+ ResetMocks(0, 0);
+ dev_mode = 0;
+ version = 123;
+ mock_rsf.fw_versions = 0x12345678;
+ TEST_EQ(RollbackFirmwareSetup(0, 0, dev_mode, 0, &dev_mode, &version),
+ 0, "RollbackFirmwareSetup()");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclStartup()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+ TEST_EQ(version, 0x12345678, "RollbackFirmwareSetup() version");
+
+ /* Error during setup should clear version */
+ ResetMocks(1, TPM_E_IOERROR);
+ dev_mode = 0;
+ version = 123;
+ mock_rsf.fw_versions = 0x12345678;
+ TEST_EQ(RollbackFirmwareSetup(0, 0, dev_mode, 0, &dev_mode, &version),
+ TPM_E_IOERROR,
+ "RollbackFirmwareSetup() error");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n",
+ "tlcl calls");
+ TEST_EQ(version, 0, "RollbackFirmwareSetup() version on error");
+
+ /* Developer mode flag gets passed properly */
+ ResetMocks(0, 0);
+ dev_mode = 1;
+ TEST_EQ(RollbackFirmwareSetup(0, dev_mode, 0, 0, &dev_mode, &version),
+ 0, "RollbackFirmwareSetup() to dev");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclStartup()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclForceClear()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+ TEST_EQ(mock_rsf.flags, FLAG_LAST_BOOT_DEVELOPER,
+ "fw space flags to dev 2");
+
+ /* So does clear-TPM request */
+ ResetMocks(0, 0);
+ dev_mode = 0;
+ TEST_EQ(RollbackFirmwareSetup(0, dev_mode, 0, 1, &dev_mode, &version),
+ 0, "RollbackFirmwareSetup() clear owner");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclStartup()\n"
+ "TlclAssertPhysicalPresence()\n"
+ "TlclGetPermanentFlags()\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclForceClear()\n"
+ "TlclSetEnable()\n"
+ "TlclSetDeactivated(0)\n",
+ "tlcl calls");
+
+ /* Test write */
+ ResetMocks(0, 0);
+ TEST_EQ(RollbackFirmwareWrite(0xBEAD1234), 0,
+ "RollbackFirmwareWrite()");
+ TEST_EQ(mock_rsf.fw_versions, 0xBEAD1234,
+ "RollbackFirmwareWrite() version");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1007, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ ResetMocks(1, TPM_E_IOERROR);
+ TEST_EQ(RollbackFirmwareWrite(123), TPM_E_IOERROR,
+ "RollbackFirmwareWrite() error");
+
+ /* Test setting virtual dev mode */
+ ResetMocks(0, 0);
+ TEST_EQ(SetVirtualDevMode(1), 0, "SetVirtualDevMode(1)");
+ TEST_EQ(mock_rsf.flags, FLAG_VIRTUAL_DEV_MODE_ON, "Virtual dev on");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1007, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+ ResetMocks(0, 0);
+ TEST_EQ(SetVirtualDevMode(0), 0, "SetVirtualDevMode(0)");
+ TEST_EQ(mock_rsf.flags, 0, "Virtual dev off");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1007, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* Test lock */
+ ResetMocks(0, 0);
+ TEST_EQ(RollbackFirmwareLock(), 0, "RollbackFirmwareLock()");
+ TEST_STR_EQ(mock_calls,
+ "TlclSetGlobalLock()\n",
+ "tlcl calls");
+
+ ResetMocks(1, TPM_E_IOERROR);
+ TEST_EQ(RollbackFirmwareLock(), TPM_E_IOERROR,
+ "RollbackFirmwareLock() error");
}
/****************************************************************************/
/* Tests for RollbackKernel() calls */
-static void RollbackKernelTest(void) {
- RollbackSpaceFirmware rsf;
- uint32_t version = 0;
-
- /* RollbackKernel*() functions use a global flag inside
- * rollback_index.c based on recovery mode, which is set by
- * SetupTPM(). Clear the flag for the first set of tests. */
- TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), 0, "SetupTPM()");
-
- /* Normal read */
- ResetMocks(0, 0);
- mock_rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
- mock_permissions = TPM_NV_PER_PPWRITE;
- mock_rsk.kernel_versions = 0x87654321;
- TEST_EQ(RollbackKernelRead(&version), 0, "RollbackKernelRead()");
- TEST_STR_EQ(mock_calls,
- "TlclRead(0x1008, 13)\n"
- "TlclGetPermissions(0x1008)\n",
- "tlcl calls");
- TEST_EQ(version, 0x87654321, "RollbackKernelRead() version");
-
- /* Read error */
- ResetMocks(1, TPM_E_IOERROR);
- TEST_EQ(RollbackKernelRead(&version), TPM_E_IOERROR,
- "RollbackKernelRead() error");
- TEST_STR_EQ(mock_calls,
- "TlclRead(0x1008, 13)\n",
- "tlcl calls");
-
- /* Wrong permission or UID will return error */
- ResetMocks(0, 0);
- mock_rsk.uid = ROLLBACK_SPACE_KERNEL_UID + 1;
- mock_permissions = TPM_NV_PER_PPWRITE;
- TEST_EQ(RollbackKernelRead(&version), TPM_E_CORRUPTED_STATE,
- "RollbackKernelRead() bad uid");
-
- ResetMocks(0, 0);
- mock_rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
- mock_permissions = TPM_NV_PER_PPWRITE + 1;
- TEST_EQ(RollbackKernelRead(&version), TPM_E_CORRUPTED_STATE,
- "RollbackKernelRead() bad permissions");
-
- /* Test write */
- ResetMocks(0, 0);
- TEST_EQ(RollbackKernelWrite(0xBEAD4321), 0, "RollbackKernelWrite()");
- TEST_EQ(mock_rsk.kernel_versions, 0xBEAD4321,
- "RollbackKernelWrite() version");
- TEST_STR_EQ(mock_calls,
- "TlclRead(0x1008, 13)\n"
- "TlclWrite(0x1008, 13)\n"
- "TlclRead(0x1008, 13)\n",
- "tlcl calls");
-
- ResetMocks(1, TPM_E_IOERROR);
- TEST_EQ(RollbackKernelWrite(123), TPM_E_IOERROR,
- "RollbackKernelWrite() error");
-
- /* Test lock (recovery off) */
- ResetMocks(0, 0);
- TEST_EQ(RollbackKernelLock(), 0, "RollbackKernelLock()");
- TEST_STR_EQ(mock_calls,
- "TlclLockPhysicalPresence()\n",
- "tlcl calls");
-
- ResetMocks(1, TPM_E_IOERROR);
- TEST_EQ(RollbackKernelLock(), TPM_E_IOERROR, "RollbackKernelLock() error");
-
- /* Test lock with recovery on; shouldn't lock PP */
- SetupTPM(1, 0, 0, 0, &rsf);
- ResetMocks(0, 0);
- TEST_EQ(RollbackKernelLock(), 0, "RollbackKernelLock() in recovery");
- TEST_STR_EQ(mock_calls, "", "no tlcl calls");
+static void RollbackKernelTest(void)
+{
+ RollbackSpaceFirmware rsf;
+ uint32_t version = 0;
+
+ /*
+ * RollbackKernel*() functions use a global flag inside
+ * rollback_index.c based on recovery mode, which is set by SetupTPM().
+ * Clear the flag for the first set of tests.
+ */
+ TEST_EQ(SetupTPM(0, 0, 0, 0, &rsf), 0, "SetupTPM()");
+
+ /* Normal read */
+ ResetMocks(0, 0);
+ mock_rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
+ mock_permissions = TPM_NV_PER_PPWRITE;
+ mock_rsk.kernel_versions = 0x87654321;
+ TEST_EQ(RollbackKernelRead(&version), 0, "RollbackKernelRead()");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1008, 13)\n"
+ "TlclGetPermissions(0x1008)\n",
+ "tlcl calls");
+ TEST_EQ(version, 0x87654321, "RollbackKernelRead() version");
+
+ /* Read error */
+ ResetMocks(1, TPM_E_IOERROR);
+ TEST_EQ(RollbackKernelRead(&version), TPM_E_IOERROR,
+ "RollbackKernelRead() error");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /* Wrong permission or UID will return error */
+ ResetMocks(0, 0);
+ mock_rsk.uid = ROLLBACK_SPACE_KERNEL_UID + 1;
+ mock_permissions = TPM_NV_PER_PPWRITE;
+ TEST_EQ(RollbackKernelRead(&version), TPM_E_CORRUPTED_STATE,
+ "RollbackKernelRead() bad uid");
+
+ ResetMocks(0, 0);
+ mock_rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
+ mock_permissions = TPM_NV_PER_PPWRITE + 1;
+ TEST_EQ(RollbackKernelRead(&version), TPM_E_CORRUPTED_STATE,
+ "RollbackKernelRead() bad permissions");
+
+ /* Test write */
+ ResetMocks(0, 0);
+ TEST_EQ(RollbackKernelWrite(0xBEAD4321), 0, "RollbackKernelWrite()");
+ TEST_EQ(mock_rsk.kernel_versions, 0xBEAD4321,
+ "RollbackKernelWrite() version");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1008, 13)\n"
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ ResetMocks(1, TPM_E_IOERROR);
+ TEST_EQ(RollbackKernelWrite(123), TPM_E_IOERROR,
+ "RollbackKernelWrite() error");
+
+ /* Test lock (recovery off) */
+ ResetMocks(0, 0);
+ TEST_EQ(RollbackKernelLock(), 0, "RollbackKernelLock()");
+ TEST_STR_EQ(mock_calls,
+ "TlclLockPhysicalPresence()\n",
+ "tlcl calls");
+
+ ResetMocks(1, TPM_E_IOERROR);
+ TEST_EQ(RollbackKernelLock(), TPM_E_IOERROR,
+ "RollbackKernelLock() error");
+
+ /* Test lock with recovery on; shouldn't lock PP */
+ SetupTPM(1, 0, 0, 0, &rsf);
+ ResetMocks(0, 0);
+ TEST_EQ(RollbackKernelLock(), 0, "RollbackKernelLock() in recovery");
+ TEST_STR_EQ(mock_calls, "", "no tlcl calls");
}
/* Tests for RollbackS3Resume() */
-static void RollbackS3ResumeTest(void) {
-
- ResetMocks(0, 0);
- TEST_EQ(RollbackS3Resume(), 0, "RollbackS3Resume()");
- TEST_STR_EQ(mock_calls,
- "TlclLibInit()\n"
- "TlclResume()\n",
- "tlcl calls");
-
- /* Should ignore postinit error */
- ResetMocks(2, TPM_E_INVALID_POSTINIT);
- TEST_EQ(RollbackS3Resume(), 0, "RollbackS3Resume() postinit");
-
- /* Resume with other error */
- ResetMocks(2, TPM_E_IOERROR);
- TEST_EQ(RollbackS3Resume(), TPM_E_IOERROR, "RollbackS3Resume() other error");
+static void RollbackS3ResumeTest(void)
+{
+ ResetMocks(0, 0);
+ TEST_EQ(RollbackS3Resume(), 0, "RollbackS3Resume()");
+ TEST_STR_EQ(mock_calls,
+ "TlclLibInit()\n"
+ "TlclResume()\n",
+ "tlcl calls");
+
+ /* Should ignore postinit error */
+ ResetMocks(2, TPM_E_INVALID_POSTINIT);
+ TEST_EQ(RollbackS3Resume(), 0, "RollbackS3Resume() postinit");
+
+ /* Resume with other error */
+ ResetMocks(2, TPM_E_IOERROR);
+ TEST_EQ(RollbackS3Resume(), TPM_E_IOERROR,
+ "RollbackS3Resume() other error");
}
/* disable MSVC warnings on unused arguments */
__pragma(warning (disable: 4100))
-int main(int argc, char* argv[]) {
- int error_code = 0;
-
- CrcTestFirmware();
- CrcTestKernel();
- MiscTest();
- OneTimeInitTest();
- SetupTpmTest();
- RollbackFirmwareTest();
- RollbackKernelTest();
- RollbackS3ResumeTest();
-
- if (!gTestSuccess)
- error_code = 255;
-
- return error_code;
+int main(int argc, char* argv[])
+{
+ CrcTestFirmware();
+ CrcTestKernel();
+ MiscTest();
+ OneTimeInitTest();
+ SetupTpmTest();
+ RollbackFirmwareTest();
+ RollbackKernelTest();
+ RollbackS3ResumeTest();
+
+ return gTestSuccess ? 0 : 255;
}
diff --git a/tests/rollback_index3_tests.c b/tests/rollback_index3_tests.c
new file mode 100644
index 00000000..ece8bc08
--- /dev/null
+++ b/tests/rollback_index3_tests.c
@@ -0,0 +1,45 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Tests for do-nothing rollback_index functions with disabled TPM
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define _STUB_IMPLEMENTATION_ /* So we can use memset() ourselves */
+
+#include "rollback_index.h"
+#include "test_common.h"
+
+/* disable MSVC warnings on unused arguments */
+__pragma(warning (disable: 4100))
+
+int main(int argc, char* argv[])
+{
+ int is_virt_dev;
+ uint32_t version;
+
+ TEST_EQ(RollbackS3Resume(), 0, "RollbackS3Resume()");
+
+ is_virt_dev = 1;
+ version = 1;
+ TEST_EQ(RollbackFirmwareSetup(0, 0, 0, 0, &is_virt_dev, &version),
+ 0, "RollbackFirmwareSetup()");
+ TEST_EQ(is_virt_dev, 0, "rfs is_virt_dev");
+ TEST_EQ(version, 0, "rfs version");
+
+ TEST_EQ(RollbackFirmwareWrite(0), 0, "RollbackFirmwareWrite()");
+ TEST_EQ(RollbackFirmwareLock(), 0, "RollbackFirmwareLock()");
+
+ version = 1;
+ TEST_EQ(RollbackKernelRead(&version), 0, "RollbackKernelRead()");
+ TEST_EQ(version, 0, "rkr version");
+
+ TEST_EQ(RollbackKernelWrite(0), 0, "RollbackKernelWrite()");
+ TEST_EQ(RollbackKernelLock(), 0, "RollbackKernelLock()");
+
+ return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/run_vboot_ec_tests.sh b/tests/run_vboot_ec_tests.sh
deleted file mode 100755
index 302a3578..00000000
--- a/tests/run_vboot_ec_tests.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash -eu
-
-# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Run verified boot firmware and kernel verification tests.
-
-# Load common constants and variables.
-. "$(dirname "$0")/common.sh"
-
-check_test_keys
-
-for priv in ${TESTKEY_DIR}/*.vbprivk; do
- root=$(basename ${priv%.vbprivk})
- pub="${priv%.vbprivk}.vbpubk"
- echo "Trying $root ..."
- ${TEST_DIR}/vboot_ec_tests "$priv" "$pub"
-done
diff --git a/tests/test_using_qemu.sh b/tests/test_using_qemu.sh
new file mode 100755
index 00000000..6b3f0733
--- /dev/null
+++ b/tests/test_using_qemu.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+#
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Script to run a test under qemu
+#
+# Usage:
+# test_using_qemu.sh (command line to run)
+#
+# Required environment variables:
+# BUILD_RUN - path to build directory inside chroot
+# HOME - home directory inside chroot
+# QEMU_RUN - path to QEMU binary inside chroot
+# SYSROOT - path to root for target platform, outside chroot
+
+set -e
+
+# Set up mounts
+sudo mkdir -p "${SYSROOT}/proc" "${SYSROOT}/dev"
+sudo mount --bind /proc "${SYSROOT}/proc"
+sudo mount --bind /dev "${SYSROOT}/dev"
+
+# Don't exit on error, so we can capture the error code
+set +e
+sudo chroot ${SYSROOT} ${QEMU_RUN} -drop-ld-preload \
+ -E LD_LIBRARY_PATH=/lib64:/lib:/usr/lib64:/usr/lib \
+ -E HOME=${HOME} \
+ -E BUILD=${BUILD_RUN} \
+ -- $*
+exit_code=$?
+set -e
+
+# Clean up mounts
+sudo umount -l "${SYSROOT}/proc"
+sudo umount -l "${SYSROOT}/dev"
+
+# Pass through exit code from command
+exit $exit_code
diff --git a/tests/vboot_api_init_tests.c b/tests/vboot_api_init_tests.c
index dd6daee4..bde10a7c 100644
--- a/tests/vboot_api_init_tests.c
+++ b/tests/vboot_api_init_tests.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -21,7 +21,7 @@ static VbCommonParams cparams;
static VbInitParams iparams;
static VbNvContext vnc;
static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
-static VbSharedDataHeader* shared = (VbSharedDataHeader*)shared_data;
+static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
static uint64_t mock_timer;
static int rollback_s3_retval;
static int nv_write_called;
@@ -29,371 +29,496 @@ static GoogleBinaryBlockHeader gbb;
static int mock_virt_dev_sw;
static uint32_t mock_tpm_version;
static uint32_t mock_rfs_retval;
+static int rfs_clear_tpm_request;
+static int rfs_disable_dev_request;
/* Reset mock data (for use before each test) */
-static void ResetMocks(void) {
- Memset(&cparams, 0, sizeof(cparams));
- cparams.shared_data_size = sizeof(shared_data);
- cparams.shared_data_blob = shared_data;
- cparams.gbb_data = &gbb;
+static void ResetMocks(void)
+{
+ Memset(&cparams, 0, sizeof(cparams));
+ cparams.shared_data_size = sizeof(shared_data);
+ cparams.shared_data_blob = shared_data;
+ cparams.gbb_data = &gbb;
- Memset(&gbb, 0, sizeof(gbb));
- gbb.major_version = GBB_MAJOR_VER;
- gbb.minor_version = GBB_MINOR_VER;
- gbb.flags = 0;
+ Memset(&gbb, 0, sizeof(gbb));
+ gbb.major_version = GBB_MAJOR_VER;
+ gbb.minor_version = GBB_MINOR_VER;
+ gbb.flags = 0;
- Memset(&iparams, 0, sizeof(iparams));
+ Memset(&iparams, 0, sizeof(iparams));
- Memset(&vnc, 0, sizeof(vnc));
- VbNvSetup(&vnc);
- VbNvTeardown(&vnc); /* So CRC gets generated */
+ Memset(&vnc, 0, sizeof(vnc));
+ VbNvSetup(&vnc);
+ VbNvTeardown(&vnc); /* So CRC gets generated */
- Memset(&shared_data, 0, sizeof(shared_data));
- VbSharedDataInit(shared, sizeof(shared_data));
+ Memset(&shared_data, 0, sizeof(shared_data));
+ VbSharedDataInit(shared, sizeof(shared_data));
- mock_timer = 10;
- rollback_s3_retval = TPM_SUCCESS;
- nv_write_called = 0;
+ mock_timer = 10;
+ rollback_s3_retval = TPM_SUCCESS;
+ nv_write_called = 0;
- mock_virt_dev_sw = 0;
- mock_tpm_version = 0x10001;
- mock_rfs_retval = 0;
+ mock_virt_dev_sw = 0;
+ mock_tpm_version = 0x10001;
+ mock_rfs_retval = 0;
+
+ rfs_clear_tpm_request = 0;
+ rfs_disable_dev_request = 0;
}
/****************************************************************************/
/* Mocked verification functions */
-VbError_t VbExNvStorageRead(uint8_t* buf) {
- Memcpy(buf, vnc.raw, sizeof(vnc.raw));
- return VBERROR_SUCCESS;
+VbError_t VbExNvStorageRead(uint8_t *buf)
+{
+ Memcpy(buf, vnc.raw, sizeof(vnc.raw));
+ return VBERROR_SUCCESS;
}
-VbError_t VbExNvStorageWrite(const uint8_t* buf) {
- nv_write_called = 1;
- Memcpy(vnc.raw, buf, sizeof(vnc.raw));
- return VBERROR_SUCCESS;
+VbError_t VbExNvStorageWrite(const uint8_t *buf)
+{
+ nv_write_called = 1;
+ Memcpy(vnc.raw, buf, sizeof(vnc.raw));
+ return VBERROR_SUCCESS;
}
-uint64_t VbExGetTimer(void) {
- /* Exponential-ish rather than linear time, so that subtracting any
- * two mock values will yield a unique result. */
- uint64_t new_timer = mock_timer * 2 + 1;
- VbAssert(new_timer > mock_timer); /* Make sure we don't overflow */
- mock_timer = new_timer;
- return mock_timer;
+uint64_t VbExGetTimer(void)
+{
+ /*
+ * Exponential-ish rather than linear time, so that subtracting any
+ * two mock values will yield a unique result.
+ */
+ uint64_t new_timer = mock_timer * 2 + 1;
+ VbAssert(new_timer > mock_timer); /* Make sure we don't overflow */
+ mock_timer = new_timer;
+ return mock_timer;
}
-uint32_t RollbackS3Resume(void) {
- return rollback_s3_retval;
+uint32_t RollbackS3Resume(void)
+{
+ return rollback_s3_retval;
}
uint32_t RollbackFirmwareSetup(int recovery_mode, int is_hw_dev,
int disable_dev_request,
int clear_tpm_owner_request,
/* two outputs on success */
- int *is_virt_dev, uint32_t *version) {
- *is_virt_dev = mock_virt_dev_sw;
- *version = mock_tpm_version;
- return mock_rfs_retval;
+ int *is_virt_dev, uint32_t *version)
+{
+ rfs_clear_tpm_request = clear_tpm_owner_request;
+ rfs_disable_dev_request = disable_dev_request;
+
+ *is_virt_dev = mock_virt_dev_sw;
+ *version = mock_tpm_version;
+ return mock_rfs_retval;
}
/****************************************************************************/
/* Test VbInit() and check expected return value and recovery reason */
+
static void TestVbInit(VbError_t expected_retval,
- uint8_t expected_recovery, const char* desc) {
- uint32_t rr = 256;
+ uint8_t expected_recovery, const char *desc)
+{
+ uint32_t rr = 256;
- TEST_EQ(VbInit(&cparams, &iparams), expected_retval, desc);
- VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &rr);
- TEST_EQ(rr, expected_recovery, " (recovery request)");
+ TEST_EQ(VbInit(&cparams, &iparams), expected_retval, desc);
+ VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &rr);
+ TEST_EQ(rr, expected_recovery, " (recovery request)");
}
/****************************************************************************/
-static void VbInitTest(void) {
- uint32_t u;
-
- /* Test passing in too small a shared data area */
- ResetMocks();
- cparams.shared_data_size = VB_SHARED_DATA_MIN_SIZE - 1;
- TestVbInit(VBERROR_INIT_SHARED_DATA, 0, "Shared data too small");
-
- /* Normal call; dev=0 rec=0 */
- ResetMocks();
- TestVbInit(0, 0, "Normal call");
- TEST_EQ(shared->timer_vb_init_enter, 21, " time enter");
- TEST_EQ(shared->timer_vb_init_exit, 43, " time exit");
- TEST_EQ(shared->flags, 0, " shared flags");
- TEST_EQ(iparams.out_flags, 0, " out flags");
- TEST_EQ(nv_write_called, 0, " NV write not called since nothing changed");
-
- /* If NV data is trashed, we initialize it */
- ResetMocks();
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
- /* Note that we're not doing a VbNvTeardown(), so the CRC hasn't
- * been regenerated yet. So VbInit() should ignore the corrupted
- * recovery value and boot normally. */
- TestVbInit(0, 0, "NV data trashed");
- TEST_EQ(nv_write_called, 1, " NV write called");
-
- /* Test boot switch flags which are just passed through to shared
- * flags, and don't have an effect on VbInit(). */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_WP_ENABLED;
- TestVbInit(0, 0, "Flags test WP");
- TEST_EQ(shared->flags, VBSD_BOOT_FIRMWARE_WP_ENABLED, " shared flags WP");
-
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_SW_WP_ENABLED;
- TestVbInit(0, 0, "Flags test SW WP");
- TEST_EQ(shared->flags, VBSD_BOOT_FIRMWARE_SW_WP_ENABLED,
- " shared flags SW WP");
-
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_RO_NORMAL_SUPPORT;
- TestVbInit(0, 0, " flags test RO normal");
- TEST_EQ(shared->flags, VBSD_BOOT_RO_NORMAL_SUPPORT,
- " shared flags RO normal");
-
- /* S3 resume */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_S3_RESUME;
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
- VbNvTeardown(&vnc);
- /* S3 resume doesn't clear the recovery request (or act on it) */
- TestVbInit(0, 123, "S3 resume");
- TEST_EQ(shared->flags, VBSD_BOOT_S3_RESUME, " shared flags S3");
- TEST_EQ(iparams.out_flags, 0, " out flags");
- TEST_EQ(shared->recovery_reason, 0, " S3 doesn't look at recovery request");
-
- /* S3 resume with TPM resume error */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_S3_RESUME;
- rollback_s3_retval = 1;
- /* S3 resume doesn't clear the recovery request (or act on it) */
- TestVbInit(VBERROR_TPM_S3_RESUME, 0, "S3 resume rollback error");
-
- /* Normal boot doesn't care about TPM resume error because it
- * doesn't call RollbackS3Resume() */
- ResetMocks();
- rollback_s3_retval = 1;
- TestVbInit(0, 0, "Normal doesn't S3 resume");
-
- /* S3 resume with debug reset */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_S3_RESUME;
- VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 1);
- VbNvTeardown(&vnc);
- TestVbInit(0, 0, "S3 debug reset");
- TEST_EQ(iparams.out_flags, VB_INIT_OUT_S3_DEBUG_BOOT, " out flags");
- VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &u);
- TEST_EQ(u, 0, " S3 clears nv debug reset mode");
-
- /* Normal boot clears S3 debug reset mode, but doesn't set output flag */
- ResetMocks();
- VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 1);
- VbNvTeardown(&vnc);
- TestVbInit(0, 0, "Normal with debug reset mode");
- TEST_EQ(iparams.out_flags, 0, " out flags");
- VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &u);
- TEST_EQ(u, 0, " normal clears nv debug reset mode");
-
- /* S3 resume with debug reset is a normal boot, so doesn't resume the TPM */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_S3_RESUME;
- rollback_s3_retval = 1;
- VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 1);
- VbNvTeardown(&vnc);
- TestVbInit(0, 0, "S3 debug reset rollback error");
-
- /* Developer mode */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_DEV_SWITCH_ON;
- TestVbInit(0, 0, "Dev mode on");
- TEST_EQ(shared->recovery_reason, 0, " recovery reason");
- TEST_EQ(iparams.out_flags,
- VB_INIT_OUT_CLEAR_RAM |
- VB_INIT_OUT_ENABLE_DISPLAY |
- VB_INIT_OUT_ENABLE_USB_STORAGE |
- VB_INIT_OUT_ENABLE_DEVELOPER |
- VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
- TEST_EQ(shared->flags, VBSD_BOOT_DEV_SWITCH_ON, " shared flags");
-
- /* Developer mode forced by GBB flag */
- ResetMocks();
- iparams.flags = 0;
- gbb.flags = GBB_FLAG_FORCE_DEV_SWITCH_ON;
- TestVbInit(0, 0, "Dev mode via GBB");
- TEST_EQ(shared->recovery_reason, 0, " recovery reason");
- TEST_EQ(iparams.out_flags,
- VB_INIT_OUT_CLEAR_RAM |
- VB_INIT_OUT_ENABLE_DISPLAY |
- VB_INIT_OUT_ENABLE_USB_STORAGE |
- VB_INIT_OUT_ENABLE_DEVELOPER |
- VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
- TEST_EQ(shared->flags, VBSD_BOOT_DEV_SWITCH_ON, " shared flags");
-
- /* Recovery mode from NV storage */
- ResetMocks();
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
- VbNvTeardown(&vnc);
- TestVbInit(0, 0, "Recovery mode - from nv");
- TEST_EQ(shared->recovery_reason, 123, " recovery reason");
- TEST_EQ(iparams.out_flags,
- VB_INIT_OUT_ENABLE_RECOVERY |
- VB_INIT_OUT_CLEAR_RAM |
- VB_INIT_OUT_ENABLE_DISPLAY |
- VB_INIT_OUT_ENABLE_USB_STORAGE, " out flags");
- TEST_EQ(shared->flags, 0, " shared flags");
-
- /* Recovery mode from recovery button */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_REC_BUTTON_PRESSED;
- TestVbInit(0, 0, "Recovery mode - button");
- TEST_EQ(shared->recovery_reason, VBNV_RECOVERY_RO_MANUAL,
- " recovery reason");
- TEST_EQ(iparams.out_flags,
- VB_INIT_OUT_ENABLE_RECOVERY |
- VB_INIT_OUT_CLEAR_RAM |
- VB_INIT_OUT_ENABLE_DISPLAY |
- VB_INIT_OUT_ENABLE_USB_STORAGE, " out flags");
- TEST_EQ(shared->flags, VBSD_BOOT_REC_SWITCH_ON, " shared flags");
-
- /* Recovery button reason supersedes NV reason */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_REC_BUTTON_PRESSED;
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
- VbNvTeardown(&vnc);
- TestVbInit(0, 0, "Recovery mode - button AND nv");
- TEST_EQ(shared->recovery_reason, VBNV_RECOVERY_RO_MANUAL,
- " recovery reason");
-
- /* Recovery mode from previous boot fail */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_PREVIOUS_BOOT_FAIL;
- TestVbInit(0, 0, "Recovery mode - previous boot fail");
- TEST_EQ(shared->recovery_reason, VBNV_RECOVERY_RO_FIRMWARE,
- " recovery reason");
- TEST_EQ(iparams.out_flags,
- VB_INIT_OUT_ENABLE_RECOVERY |
- VB_INIT_OUT_CLEAR_RAM |
- VB_INIT_OUT_ENABLE_DISPLAY |
- VB_INIT_OUT_ENABLE_USB_STORAGE, " out flags");
- TEST_EQ(shared->flags, 0, " shared flags");
-
- /* Recovery mode from NV supersedes previous boot fail */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_PREVIOUS_BOOT_FAIL;
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
- VbNvTeardown(&vnc);
- TestVbInit(0, 0, "Recovery mode - previous boot fail AND nv");
- TEST_EQ(shared->recovery_reason, 123, " recovery reason");
-
- /* Dev + recovery = recovery */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_REC_BUTTON_PRESSED | VB_INIT_FLAG_DEV_SWITCH_ON;
- TestVbInit(0, 0, "Recovery mode - button");
- TEST_EQ(shared->recovery_reason, VBNV_RECOVERY_RO_MANUAL,
- " recovery reason");
- TEST_EQ(iparams.out_flags,
- VB_INIT_OUT_ENABLE_RECOVERY |
- VB_INIT_OUT_CLEAR_RAM |
- VB_INIT_OUT_ENABLE_DISPLAY |
- VB_INIT_OUT_ENABLE_USB_STORAGE, " out flags");
- TEST_EQ(shared->flags,
- VBSD_BOOT_REC_SWITCH_ON | VBSD_BOOT_DEV_SWITCH_ON, " shared flags");
+static void VbInitTest(void)
+{
+ uint32_t u;
+
+ /* Test passing in too small a shared data area */
+ ResetMocks();
+ cparams.shared_data_size = VB_SHARED_DATA_MIN_SIZE - 1;
+ TestVbInit(VBERROR_INIT_SHARED_DATA, 0, "Shared data too small");
+
+ /* Normal call; dev=0 rec=0 */
+ ResetMocks();
+ TestVbInit(0, 0, "Normal call");
+ TEST_EQ(shared->timer_vb_init_enter, 21, " time enter");
+ TEST_EQ(shared->timer_vb_init_exit, 43, " time exit");
+ TEST_EQ(shared->flags, 0, " shared flags");
+ TEST_EQ(iparams.out_flags, 0, " out flags");
+ TEST_EQ(nv_write_called, 0,
+ " NV write not called since nothing changed");
+
+ /* If NV data is trashed, we initialize it */
+ ResetMocks();
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
+ /*
+ * Note that we're not doing a VbNvTeardown(), so the CRC hasn't been
+ * regenerated yet. So VbInit() should ignore the corrupted recovery
+ * value and boot normally.
+ */
+ TestVbInit(0, 0, "NV data trashed");
+ TEST_EQ(nv_write_called, 1, " NV write called");
+
+ /*
+ * Test boot switch flags which are just passed through to shared
+ * flags, and don't have an effect on VbInit().
+ */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_WP_ENABLED;
+ TestVbInit(0, 0, "Flags test WP");
+ TEST_EQ(shared->flags, VBSD_BOOT_FIRMWARE_WP_ENABLED,
+ " shared flags");
+
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_SW_WP_ENABLED;
+ TestVbInit(0, 0, "Flags test SW WP");
+ TEST_EQ(shared->flags, VBSD_BOOT_FIRMWARE_SW_WP_ENABLED,
+ " shared flags");
+
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_RO_NORMAL_SUPPORT;
+ TestVbInit(0, 0, " flags test RO normal");
+ TEST_EQ(shared->flags, VBSD_BOOT_RO_NORMAL_SUPPORT,
+ " shared flags");
+
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_EC_SOFTWARE_SYNC;
+ TestVbInit(0, 0, " flags test EC software sync");
+ TEST_EQ(shared->flags, VBSD_EC_SOFTWARE_SYNC, " shared flags");
+
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_EC_SLOW_UPDATE;
+ TestVbInit(0, 0, " flags test EC slow update");
+ TEST_EQ(shared->flags, VBSD_EC_SLOW_UPDATE, " shared flags");
+
+ /* S3 resume */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_S3_RESUME;
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
+ VbNvTeardown(&vnc);
+ /* S3 resume doesn't clear the recovery request (or act on it) */
+ TestVbInit(0, 123, "S3 resume");
+ TEST_EQ(shared->flags, VBSD_BOOT_S3_RESUME, " shared flags S3");
+ TEST_EQ(iparams.out_flags, 0, " out flags");
+ TEST_EQ(shared->recovery_reason, 0,
+ " S3 doesn't look at recovery request");
+
+ /* S3 resume with TPM resume error */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_S3_RESUME;
+ rollback_s3_retval = 1;
+ /* S3 resume doesn't clear the recovery request (or act on it) */
+ TestVbInit(VBERROR_TPM_S3_RESUME, 0, "S3 resume rollback error");
+
+ /*
+ * Normal boot doesn't care about TPM resume error because it doesn't
+ * call RollbackS3Resume().
+ */
+ ResetMocks();
+ rollback_s3_retval = 1;
+ TestVbInit(0, 0, "Normal doesn't S3 resume");
+
+ /* S3 resume with debug reset */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_S3_RESUME;
+ VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 1);
+ VbNvTeardown(&vnc);
+ TestVbInit(0, 0, "S3 debug reset");
+ TEST_EQ(iparams.out_flags, VB_INIT_OUT_S3_DEBUG_BOOT, " out flags");
+ VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &u);
+ TEST_EQ(u, 0, " S3 clears nv debug reset mode");
+
+ /* Normal boot clears S3 debug reset mode; doesn't set output flag */
+ ResetMocks();
+ VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 1);
+ VbNvTeardown(&vnc);
+ TestVbInit(0, 0, "Normal with debug reset mode");
+ TEST_EQ(iparams.out_flags, 0, " out flags");
+ VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &u);
+ TEST_EQ(u, 0, " normal clears nv debug reset mode");
+
+ /*
+ * S3 resume with debug reset is a normal boot, so doesn't resume the
+ * TPM.
+ */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_S3_RESUME;
+ rollback_s3_retval = 1;
+ VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 1);
+ VbNvTeardown(&vnc);
+ TestVbInit(0, 0, "S3 debug reset rollback error");
+
+ /* Developer mode */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_DEV_SWITCH_ON;
+ TestVbInit(0, 0, "Dev mode on");
+ TEST_EQ(shared->recovery_reason, 0, " recovery reason");
+ TEST_EQ(iparams.out_flags,
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE |
+ VB_INIT_OUT_ENABLE_DEVELOPER |
+ VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
+ TEST_EQ(shared->flags, VBSD_BOOT_DEV_SWITCH_ON, " shared flags");
+
+ /* Developer mode forced by GBB flag */
+ ResetMocks();
+ iparams.flags = 0;
+ gbb.flags = GBB_FLAG_FORCE_DEV_SWITCH_ON;
+ TestVbInit(0, 0, "Dev mode via GBB");
+ TEST_EQ(shared->recovery_reason, 0, " recovery reason");
+ TEST_EQ(iparams.out_flags,
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE |
+ VB_INIT_OUT_ENABLE_DEVELOPER |
+ VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
+ TEST_EQ(shared->flags, VBSD_BOOT_DEV_SWITCH_ON, " shared flags");
+
+ /* Developer mode when option ROM matters and isn't loaded */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_DEV_SWITCH_ON |
+ VB_INIT_FLAG_OPROM_MATTERS;
+ TestVbInit(VBERROR_VGA_OPROM_MISMATCH, 0, "Dev mode need oprom");
+ VbNvGet(&vnc, VBNV_OPROM_NEEDED, &u);
+ TEST_EQ(u, 1, " oprom requested");
+
+ /* Developer mode when option ROM matters and is already loaded */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_DEV_SWITCH_ON |
+ VB_INIT_FLAG_OPROM_MATTERS | VB_INIT_FLAG_OPROM_LOADED;
+ TestVbInit(0, 0, "Dev mode has oprom");
+
+ /* Normal mode when option ROM matters and is loaded */
+ ResetMocks();
+ VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
+ VbNvTeardown(&vnc);
+ iparams.flags = VB_INIT_FLAG_OPROM_MATTERS | VB_INIT_FLAG_OPROM_LOADED;
+ TestVbInit(VBERROR_VGA_OPROM_MISMATCH, 0, "Normal mode with oprom");
+ VbNvGet(&vnc, VBNV_OPROM_NEEDED, &u);
+ TEST_EQ(u, 0, " oprom not requested");
+
+ /* Option ROMs can be forced by GBB flag */
+ ResetMocks();
+ gbb.flags = GBB_FLAG_LOAD_OPTION_ROMS;
+ TestVbInit(0, 0, "GBB load option ROMs");
+ TEST_EQ(iparams.out_flags, VB_INIT_OUT_ENABLE_OPROM, " out flags");
+
+ /* If requiring signed only, don't enable alternate OS by default */
+ ResetMocks();
+ VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 1);
+ VbNvTeardown(&vnc);
+ iparams.flags = VB_INIT_FLAG_DEV_SWITCH_ON;
+ TestVbInit(0, 0, "Dev signed only");
+ TEST_EQ(iparams.out_flags,
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE |
+ VB_INIT_OUT_ENABLE_DEVELOPER, " out flags");
+
+ /* But that can be overridden by the GBB */
+ ResetMocks();
+ VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 1);
+ VbNvTeardown(&vnc);
+ iparams.flags = VB_INIT_FLAG_DEV_SWITCH_ON;
+ gbb.flags = GBB_FLAG_ENABLE_ALTERNATE_OS;
+ TestVbInit(0, 0, "Force option ROMs via GBB");
+ TEST_EQ(iparams.out_flags,
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE |
+ VB_INIT_OUT_ENABLE_DEVELOPER |
+ VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
+
+ /* The GBB override is ignored in normal mode */
+ ResetMocks();
+ gbb.flags = GBB_FLAG_ENABLE_ALTERNATE_OS;
+ TestVbInit(0, 0, "Normal mode ignores forcing option ROMs via GBB");
+ TEST_EQ(iparams.out_flags, 0, " out flags");
+
+ /* Recovery mode from NV storage */
+ ResetMocks();
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
+ VbNvTeardown(&vnc);
+ TestVbInit(0, 0, "Recovery mode - from nv");
+ TEST_EQ(shared->recovery_reason, 123, " recovery reason");
+ TEST_EQ(iparams.out_flags,
+ VB_INIT_OUT_ENABLE_RECOVERY |
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE, " out flags");
+ TEST_EQ(shared->flags, 0, " shared flags");
+
+ /* Recovery mode from recovery button */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_REC_BUTTON_PRESSED;
+ TestVbInit(0, 0, "Recovery mode - button");
+ TEST_EQ(shared->recovery_reason, VBNV_RECOVERY_RO_MANUAL,
+ " recovery reason");
+ TEST_EQ(iparams.out_flags,
+ VB_INIT_OUT_ENABLE_RECOVERY |
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE, " out flags");
+ TEST_EQ(shared->flags, VBSD_BOOT_REC_SWITCH_ON, " shared flags");
+
+ /* Recovery button reason supersedes NV reason */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_REC_BUTTON_PRESSED;
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
+ VbNvTeardown(&vnc);
+ TestVbInit(0, 0, "Recovery mode - button AND nv");
+ TEST_EQ(shared->recovery_reason, VBNV_RECOVERY_RO_MANUAL,
+ " recovery reason");
+
+ /* Recovery mode from previous boot fail */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_PREVIOUS_BOOT_FAIL;
+ TestVbInit(0, 0, "Recovery mode - previous boot fail");
+ TEST_EQ(shared->recovery_reason, VBNV_RECOVERY_RO_FIRMWARE,
+ " recovery reason");
+ TEST_EQ(iparams.out_flags,
+ VB_INIT_OUT_ENABLE_RECOVERY |
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE, " out flags");
+ TEST_EQ(shared->flags, 0, " shared flags");
+
+ /* Recovery mode from NV supersedes previous boot fail */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_PREVIOUS_BOOT_FAIL;
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
+ VbNvTeardown(&vnc);
+ TestVbInit(0, 0, "Recovery mode - previous boot fail AND nv");
+ TEST_EQ(shared->recovery_reason, 123, " recovery reason");
+
+ /* Dev + recovery = recovery */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_REC_BUTTON_PRESSED |
+ VB_INIT_FLAG_DEV_SWITCH_ON;
+ TestVbInit(0, 0, "Recovery mode - button");
+ TEST_EQ(shared->recovery_reason, VBNV_RECOVERY_RO_MANUAL,
+ " recovery reason");
+ TEST_EQ(iparams.out_flags,
+ VB_INIT_OUT_ENABLE_RECOVERY |
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE, " out flags");
+ TEST_EQ(shared->flags,
+ VBSD_BOOT_REC_SWITCH_ON | VBSD_BOOT_DEV_SWITCH_ON,
+ " shared flags");
}
-static void VbInitTestTPM(void) {
-
- /* Rollback setup needs to reboot */
- ResetMocks();
- mock_rfs_retval = TPM_E_MUST_REBOOT;
- TestVbInit(VBERROR_TPM_REBOOT_REQUIRED, 0, "Rollback TPM reboot (rec=0)");
- ResetMocks();
- mock_rfs_retval = TPM_E_MUST_REBOOT;
- iparams.flags = VB_INIT_FLAG_REC_BUTTON_PRESSED;
- TestVbInit(VBERROR_TPM_REBOOT_REQUIRED, VBNV_RECOVERY_RO_TPM_REBOOT,
- "Rollback TPM reboot, in recovery, first time");
- /* Ignore if we already tried rebooting */
- ResetMocks();
- mock_rfs_retval = TPM_E_MUST_REBOOT;
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_REBOOT);
- VbNvTeardown(&vnc);
- TestVbInit(0, 0, "Rollback TPM reboot, in recovery, already retried");
- TEST_EQ(shared->fw_version_tpm, 0x10001, " shared fw_version_tpm");
-
- /* Other rollback setup errors */
- ResetMocks();
- mock_rfs_retval = TPM_E_IOERROR;
- mock_tpm_version = 0x20002;
- TestVbInit(VBERROR_TPM_FIRMWARE_SETUP, VBNV_RECOVERY_RO_TPM_S_ERROR,
- "Rollback TPM setup error - not in recovery");
- TEST_EQ(shared->fw_version_tpm, 0, " shared fw_version_tpm not set");
- ResetMocks();
- mock_rfs_retval = TPM_E_IOERROR;
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_US_TEST);
- VbNvTeardown(&vnc);
- TestVbInit(0, 0, "Rollback TPM setup error ignored in recovery");
- TEST_EQ(shared->fw_version_tpm, 0x10001, " shared fw_version_tpm");
-
- /* Virtual developer switch, but not enabled. */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_VIRTUAL_DEV_SWITCH;
- TestVbInit(0, 0, "TPM Dev mode off");
- TEST_EQ(shared->recovery_reason, 0, " recovery reason");
- TEST_EQ(iparams.out_flags, 0, " out flags");
- TEST_EQ(shared->flags, VBSD_HONOR_VIRT_DEV_SWITCH, " shared flags");
-
- /* Virtual developer switch, enabled. */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_VIRTUAL_DEV_SWITCH;
- mock_virt_dev_sw = 1;
- TestVbInit(0, 0, "TPM Dev mode on");
- TEST_EQ(shared->recovery_reason, 0, " recovery reason");
- TEST_EQ(iparams.out_flags,
- VB_INIT_OUT_CLEAR_RAM |
- VB_INIT_OUT_ENABLE_DISPLAY |
- VB_INIT_OUT_ENABLE_USB_STORAGE |
- VB_INIT_OUT_ENABLE_DEVELOPER |
- VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
- TEST_EQ(shared->flags, VBSD_BOOT_DEV_SWITCH_ON | VBSD_HONOR_VIRT_DEV_SWITCH,
- " shared flags");
-
- /* Ignore virtual developer switch, even though enabled. */
- ResetMocks();
- mock_virt_dev_sw = 1;
- TestVbInit(0, 0, "TPM Dev mode on but ignored");
- TEST_EQ(shared->recovery_reason, 0, " recovery reason");
- TEST_EQ(iparams.out_flags, 0, " out flags");
- TEST_EQ(shared->flags, 0, " shared flags");
-
- /* HW dev switch on, no virtual developer switch */
- ResetMocks();
- iparams.flags = VB_INIT_FLAG_DEV_SWITCH_ON;
- TestVbInit(0, 0, "HW Dev mode on");
- TEST_EQ(shared->recovery_reason, 0, " recovery reason");
- TEST_EQ(iparams.out_flags,
- VB_INIT_OUT_CLEAR_RAM |
- VB_INIT_OUT_ENABLE_DISPLAY |
- VB_INIT_OUT_ENABLE_USB_STORAGE |
- VB_INIT_OUT_ENABLE_DEVELOPER |
- VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
- TEST_EQ(shared->flags, VBSD_BOOT_DEV_SWITCH_ON, " shared flags");
+static void VbInitTestTPM(void)
+{
+ uint32_t u;
+
+ /* Rollback setup needs to reboot */
+ ResetMocks();
+ mock_rfs_retval = TPM_E_MUST_REBOOT;
+ TestVbInit(VBERROR_TPM_REBOOT_REQUIRED, 0,
+ "Rollback TPM reboot (rec=0)");
+ ResetMocks();
+ mock_rfs_retval = TPM_E_MUST_REBOOT;
+ iparams.flags = VB_INIT_FLAG_REC_BUTTON_PRESSED;
+ TestVbInit(VBERROR_TPM_REBOOT_REQUIRED, VBNV_RECOVERY_RO_TPM_REBOOT,
+ "Rollback TPM reboot, in recovery, first time");
+ /* Ignore if we already tried rebooting */
+ ResetMocks();
+ mock_rfs_retval = TPM_E_MUST_REBOOT;
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_REBOOT);
+ VbNvTeardown(&vnc);
+ TestVbInit(0, 0, "Rollback TPM reboot, in recovery, already retried");
+ TEST_EQ(shared->fw_version_tpm, 0x10001, " shared fw_version_tpm");
+
+ /* Other rollback setup errors */
+ ResetMocks();
+ mock_rfs_retval = TPM_E_IOERROR;
+ mock_tpm_version = 0x20002;
+ TestVbInit(VBERROR_TPM_FIRMWARE_SETUP, VBNV_RECOVERY_RO_TPM_S_ERROR,
+ "Rollback TPM setup error - not in recovery");
+ TEST_EQ(shared->fw_version_tpm, 0, " shared fw_version_tpm not set");
+ ResetMocks();
+ mock_rfs_retval = TPM_E_IOERROR;
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_US_TEST);
+ VbNvTeardown(&vnc);
+ TestVbInit(0, 0, "Rollback TPM setup error ignored in recovery");
+ TEST_EQ(shared->fw_version_tpm, 0x10001, " shared fw_version_tpm");
+
+ /* Virtual developer switch, but not enabled. */
+ ResetMocks();
+ VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 1);
+ VbNvTeardown(&vnc);
+ iparams.flags = VB_INIT_FLAG_VIRTUAL_DEV_SWITCH;
+ TestVbInit(0, 0, "TPM Dev mode off");
+ TEST_EQ(shared->recovery_reason, 0, " recovery reason");
+ TEST_EQ(iparams.out_flags, 0, " out flags");
+ TEST_EQ(shared->flags, VBSD_HONOR_VIRT_DEV_SWITCH, " shared flags");
+ VbNvGet(&vnc, VBNV_DISABLE_DEV_REQUEST, &u);
+ TEST_EQ(u, 0, " disable dev request");
+
+ /* Virtual developer switch, enabled. */
+ ResetMocks();
+ VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 1);
+ VbNvTeardown(&vnc);
+ iparams.flags = VB_INIT_FLAG_VIRTUAL_DEV_SWITCH;
+ mock_virt_dev_sw = 1;
+ TestVbInit(0, 0, "TPM Dev mode on");
+ TEST_EQ(shared->recovery_reason, 0, " recovery reason");
+ TEST_EQ(iparams.out_flags,
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE |
+ VB_INIT_OUT_ENABLE_DEVELOPER |
+ VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
+ TEST_EQ(shared->flags,
+ VBSD_BOOT_DEV_SWITCH_ON | VBSD_HONOR_VIRT_DEV_SWITCH,
+ " shared flags");
+ /* Disable-request doesn't get cleared because dev mode is still on */
+ VbNvGet(&vnc, VBNV_DISABLE_DEV_REQUEST, &u);
+ TEST_EQ(u, 1, " disable dev request");
+ /* Disable request was passed on to RollbackFirmwareSetup() */
+ TEST_EQ(rfs_disable_dev_request, 1, " rfs disable dev");
+
+ /* Ignore virtual developer switch, even though enabled. */
+ ResetMocks();
+ mock_virt_dev_sw = 1;
+ TestVbInit(0, 0, "TPM Dev mode on but ignored");
+ TEST_EQ(shared->recovery_reason, 0, " recovery reason");
+ TEST_EQ(iparams.out_flags, 0, " out flags");
+ TEST_EQ(shared->flags, 0, " shared flags");
+
+ /* HW dev switch on, no virtual developer switch */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_DEV_SWITCH_ON;
+ TestVbInit(0, 0, "HW Dev mode on");
+ TEST_EQ(shared->recovery_reason, 0, " recovery reason");
+ TEST_EQ(iparams.out_flags,
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE |
+ VB_INIT_OUT_ENABLE_DEVELOPER |
+ VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
+ TEST_EQ(shared->flags, VBSD_BOOT_DEV_SWITCH_ON, " shared flags");
+
+ /* Check TPM owner clear request */
+ ResetMocks();
+ VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST, 1);
+ VbNvTeardown(&vnc);
+ TestVbInit(0, 0, "TPM clear owner");
+ VbNvGet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST, &u);
+ TEST_EQ(u, 0, " tpm clear request");
+ VbNvGet(&vnc, VBNV_CLEAR_TPM_OWNER_DONE, &u);
+ TEST_EQ(u, 1, " tpm clear request");
+ TEST_EQ(rfs_clear_tpm_request, 1, "rfs tpm clear request");
}
-
/* disable MSVC warnings on unused arguments */
__pragma(warning (disable: 4100))
-int main(int argc, char* argv[]) {
- int error_code = 0;
-
- VbInitTest();
- VbInitTestTPM();
-
- if (!gTestSuccess)
- error_code = 255;
+int main(int argc, char *argv[])
+{
+ VbInitTest();
+ VbInitTestTPM();
- return error_code;
+ return gTestSuccess ? 0 : 255;
}
diff --git a/tests/vboot_common2_tests.c b/tests/vboot_common2_tests.c
index 54a3f316..f2ed5260 100644
--- a/tests/vboot_common2_tests.c
+++ b/tests/vboot_common2_tests.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -7,6 +7,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "cryptolib.h"
#include "file_keys.h"
@@ -14,231 +15,261 @@
#include "test_common.h"
#include "vboot_common.h"
-
-static void VerifyPublicKeyToRSA(const VbPublicKey* orig_key) {
-
- RSAPublicKey *rsa;
- VbPublicKey *key = PublicKeyAlloc(orig_key->key_size, 0, 0);
-
- PublicKeyCopy(key, orig_key);
- key->algorithm = kNumAlgorithms;
- TEST_EQ((size_t)PublicKeyToRSA(key), 0,
- "PublicKeyToRSA() invalid algorithm");
-
- PublicKeyCopy(key, orig_key);
- key->key_size -= 1;
- TEST_EQ((size_t)PublicKeyToRSA(key), 0,
- "PublicKeyToRSA() invalid size");
-
- rsa = PublicKeyToRSA(orig_key);
- TEST_NEQ((size_t)rsa, 0, "PublicKeyToRSA() ok");
- if (rsa) {
- TEST_EQ((int)rsa->algorithm, (int)key->algorithm,
- "PublicKeyToRSA() algorithm");
- RSAPublicKeyFree(rsa);
- }
+static void VerifyPublicKeyToRSA(const VbPublicKey *orig_key)
+{
+ RSAPublicKey *rsa;
+ VbPublicKey *key = PublicKeyAlloc(orig_key->key_size, 0, 0);
+
+ PublicKeyCopy(key, orig_key);
+ key->algorithm = kNumAlgorithms;
+ TEST_EQ((size_t)PublicKeyToRSA(key), 0,
+ "PublicKeyToRSA() invalid algorithm");
+
+ PublicKeyCopy(key, orig_key);
+ key->key_size -= 1;
+ TEST_EQ((size_t)PublicKeyToRSA(key), 0,
+ "PublicKeyToRSA() invalid size");
+
+ rsa = PublicKeyToRSA(orig_key);
+ TEST_NEQ((size_t)rsa, 0, "PublicKeyToRSA() ok");
+ if (rsa) {
+ TEST_EQ((int)rsa->algorithm, (int)key->algorithm,
+ "PublicKeyToRSA() algorithm");
+ RSAPublicKeyFree(rsa);
+ }
}
+static void VerifyDataTest(const VbPublicKey *public_key,
+ const VbPrivateKey *private_key)
+{
+ const uint8_t test_data[] = "This is some test data to sign.";
+ const uint64_t test_size = sizeof(test_data);
+ VbSignature *sig;
+ RSAPublicKey *rsa;
-static void VerifyDataTest(const VbPublicKey* public_key,
- const VbPrivateKey* private_key) {
+ sig = CalculateSignature(test_data, test_size, private_key);
+ TEST_PTR_NEQ(sig, 0, "VerifyData() calculate signature");
- const uint8_t test_data[] = "This is some test data to sign.";
- const uint64_t test_size = sizeof(test_data);
- VbSignature* sig;
- RSAPublicKey* rsa;
+ rsa = PublicKeyToRSA(public_key);
+ TEST_PTR_NEQ(rsa, 0, "VerifyData() calculate rsa");
- sig = CalculateSignature(test_data, test_size, private_key);
- rsa = PublicKeyToRSA(public_key);
- TEST_NEQ(sig && rsa, 0, "VerifyData() prerequisites");
- if (!sig || !rsa)
- return;
+ if (!sig || !rsa)
+ return;
- TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 0, "VerifyData() ok");
+ TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 0,
+ "VerifyData() ok");
- sig->sig_size -= 16;
- TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 1,
- "VerifyData() wrong sig size");
- sig->sig_size += 16;
+ sig->sig_size -= 16;
+ TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 1,
+ "VerifyData() wrong sig size");
+ sig->sig_size += 16;
- TEST_EQ(VerifyData(test_data, test_size - 1, sig, rsa), 1,
- "VerifyData() input buffer too small");
+ TEST_EQ(VerifyData(test_data, test_size - 1, sig, rsa), 1,
+ "VerifyData() input buffer too small");
- GetSignatureData(sig)[0] ^= 0x5A;
- TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 1,
- "VerifyData() wrong sig");
+ GetSignatureData(sig)[0] ^= 0x5A;
+ TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 1,
+ "VerifyData() wrong sig");
- RSAPublicKeyFree(rsa);
- free(sig);
+ RSAPublicKeyFree(rsa);
+ free(sig);
}
-
-static void VerifyDigestTest(const VbPublicKey* public_key,
- const VbPrivateKey* private_key) {
-
- const uint8_t test_data[] = "This is some other test data to sign.";
- VbSignature* sig;
- RSAPublicKey* rsa;
- uint8_t* digest;
-
- sig = CalculateSignature(test_data, sizeof(test_data), private_key);
- rsa = PublicKeyToRSA(public_key);
- digest = DigestBuf(test_data, sizeof(test_data), (int)public_key->algorithm);
- TEST_NEQ(sig && rsa && digest, 0, "VerifyData() prerequisites");
- if (!sig || !rsa || !digest)
- return;
-
- TEST_EQ(VerifyDigest(digest, sig, rsa), 0, "VerifyDigest() ok");
-
- GetSignatureData(sig)[0] ^= 0x5A;
- TEST_EQ(VerifyDigest(digest, sig, rsa), 1, "VerifyDigest() wrong sig");
-
- RSAPublicKeyFree(rsa);
- free(sig);
- free(digest);
+static void VerifyDigestTest(const VbPublicKey *public_key,
+ const VbPrivateKey *private_key)
+{
+ const uint8_t test_data[] = "This is some other test data to sign.";
+ VbSignature *sig;
+ RSAPublicKey *rsa;
+ uint8_t *digest;
+
+ sig = CalculateSignature(test_data, sizeof(test_data), private_key);
+ rsa = PublicKeyToRSA(public_key);
+ digest = DigestBuf(test_data, sizeof(test_data),
+ (int)public_key->algorithm);
+ TEST_NEQ(sig && rsa && digest, 0, "VerifyData() prerequisites");
+ if (!sig || !rsa || !digest)
+ return;
+
+ TEST_EQ(VerifyDigest(digest, sig, rsa), 0, "VerifyDigest() ok");
+
+ GetSignatureData(sig)[0] ^= 0x5A;
+ TEST_EQ(VerifyDigest(digest, sig, rsa), 1, "VerifyDigest() wrong sig");
+
+ RSAPublicKeyFree(rsa);
+ free(sig);
+ free(digest);
}
-
static void ReSignKernelPreamble(VbKernelPreambleHeader *h,
- const VbPrivateKey *key) {
- VbSignature *sig = CalculateSignature((const uint8_t*)h,
- h->preamble_signature.data_size, key);
+ const VbPrivateKey *key)
+{
+ VbSignature *sig = CalculateSignature((const uint8_t *)h,
+ h->preamble_signature.data_size, key);
- SignatureCopy(&h->preamble_signature, sig);
- free(sig);
+ SignatureCopy(&h->preamble_signature, sig);
+ free(sig);
}
-
-static void VerifyKernelPreambleTest(const VbPublicKey* public_key,
- const VbPrivateKey* private_key) {
-
- VbKernelPreambleHeader *hdr;
- VbKernelPreambleHeader *h;
- RSAPublicKey* rsa;
- unsigned hsize;
-
- /* Create a dummy signature */
- VbSignature *body_sig = SignatureAlloc(56, 78);
-
- rsa = PublicKeyToRSA(public_key);
- hdr = CreateKernelPreamble(0x1234, 0x100000, 0x300000, 0x4000, body_sig,
- 0, private_key);
- TEST_NEQ(hdr && rsa, 0, "VerifyKernelPreamble() prerequisites");
- if (!hdr)
- return;
- hsize = (unsigned) hdr->preamble_size;
- h = (VbKernelPreambleHeader*)malloc(hsize + 16384);
-
- TEST_EQ(VerifyKernelPreamble(hdr, hsize, rsa), 0,
- "VerifyKernelPreamble() ok using key");
- TEST_NEQ(VerifyKernelPreamble(hdr, hsize - 1, rsa), 0,
- "VerifyKernelPreamble() size--");
- TEST_EQ(VerifyKernelPreamble(hdr, hsize + 1, rsa), 0,
- "VerifyKernelPreamble() size++");
-
- /* Care about major version but not minor */
- Memcpy(h, hdr, hsize);
- h->header_version_major++;
- ReSignKernelPreamble(h, private_key);
- TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
- "VerifyKernelPreamble() major++");
-
- Memcpy(h, hdr, hsize);
- h->header_version_major--;
- ReSignKernelPreamble(h, private_key);
- TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
- "VerifyKernelPreamble() major--");
-
- Memcpy(h, hdr, hsize);
- h->header_version_minor++;
- ReSignKernelPreamble(h, private_key);
- TEST_EQ(VerifyKernelPreamble(h, hsize, rsa), 0,
- "VerifyKernelPreamble() minor++");
-
- Memcpy(h, hdr, hsize);
- h->header_version_minor--;
- ReSignKernelPreamble(h, private_key);
- TEST_EQ(VerifyKernelPreamble(h, hsize, rsa), 0,
- "VerifyKernelPreamble() minor--");
-
- /* Check signature */
- Memcpy(h, hdr, hsize);
- h->preamble_signature.sig_offset = hsize;
- ReSignKernelPreamble(h, private_key);
- TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
- "VerifyKernelPreamble() sig off end");
-
- Memcpy(h, hdr, hsize);
- h->preamble_signature.sig_size--;
- ReSignKernelPreamble(h, private_key);
- TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
- "VerifyKernelPreamble() sig too small");
-
- Memcpy(h, hdr, hsize);
- GetSignatureData(&h->body_signature)[0] ^= 0x34;
- TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
- "VerifyKernelPreamble() sig mismatch");
-
- /* Check that we signed header and body sig */
- Memcpy(h, hdr, hsize);
- h->preamble_signature.data_size = 4;
- h->body_signature.sig_offset = 0;
- h->body_signature.sig_size = 0;
- ReSignKernelPreamble(h, private_key);
- TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
- "VerifyKernelPreamble() didn't sign header");
-
- Memcpy(h, hdr, hsize);
- h->body_signature.sig_offset = hsize;
- ReSignKernelPreamble(h, private_key);
- TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
- "VerifyKernelPreamble() body sig off end");
-
- /* TODO: verify parser can support a bigger header. */
-
- free(h);
- RSAPublicKeyFree(rsa);
- free(hdr);
+static void VerifyKernelPreambleTest(const VbPublicKey *public_key,
+ const VbPrivateKey *private_key)
+{
+ VbKernelPreambleHeader *hdr;
+ VbKernelPreambleHeader *h;
+ RSAPublicKey *rsa;
+ unsigned hsize;
+
+ /* Create a dummy signature */
+ VbSignature *body_sig = SignatureAlloc(56, 78);
+
+ rsa = PublicKeyToRSA(public_key);
+ hdr = CreateKernelPreamble(0x1234, 0x100000, 0x300000, 0x4000, body_sig,
+ 0, private_key);
+ TEST_NEQ(hdr && rsa, 0, "VerifyKernelPreamble() prerequisites");
+ if (!hdr)
+ return;
+ hsize = (unsigned) hdr->preamble_size;
+ h = (VbKernelPreambleHeader *)malloc(hsize + 16384);
+
+ TEST_EQ(VerifyKernelPreamble(hdr, hsize, rsa), 0,
+ "VerifyKernelPreamble() ok using key");
+ TEST_NEQ(VerifyKernelPreamble(hdr, hsize - 1, rsa), 0,
+ "VerifyKernelPreamble() size--");
+ TEST_EQ(VerifyKernelPreamble(hdr, hsize + 1, rsa), 0,
+ "VerifyKernelPreamble() size++");
+
+ /* Care about major version but not minor */
+ Memcpy(h, hdr, hsize);
+ h->header_version_major++;
+ ReSignKernelPreamble(h, private_key);
+ TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
+ "VerifyKernelPreamble() major++");
+
+ Memcpy(h, hdr, hsize);
+ h->header_version_major--;
+ ReSignKernelPreamble(h, private_key);
+ TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
+ "VerifyKernelPreamble() major--");
+
+ Memcpy(h, hdr, hsize);
+ h->header_version_minor++;
+ ReSignKernelPreamble(h, private_key);
+ TEST_EQ(VerifyKernelPreamble(h, hsize, rsa), 0,
+ "VerifyKernelPreamble() minor++");
+
+ Memcpy(h, hdr, hsize);
+ h->header_version_minor--;
+ ReSignKernelPreamble(h, private_key);
+ TEST_EQ(VerifyKernelPreamble(h, hsize, rsa), 0,
+ "VerifyKernelPreamble() minor--");
+
+ /* Check signature */
+ Memcpy(h, hdr, hsize);
+ h->preamble_signature.sig_offset = hsize;
+ ReSignKernelPreamble(h, private_key);
+ TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
+ "VerifyKernelPreamble() sig off end");
+
+ Memcpy(h, hdr, hsize);
+ h->preamble_signature.sig_size--;
+ ReSignKernelPreamble(h, private_key);
+ TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
+ "VerifyKernelPreamble() sig too small");
+
+ Memcpy(h, hdr, hsize);
+ GetSignatureData(&h->body_signature)[0] ^= 0x34;
+ TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
+ "VerifyKernelPreamble() sig mismatch");
+
+ /* Check that we signed header and body sig */
+ Memcpy(h, hdr, hsize);
+ h->preamble_signature.data_size = 4;
+ h->body_signature.sig_offset = 0;
+ h->body_signature.sig_size = 0;
+ ReSignKernelPreamble(h, private_key);
+ TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
+ "VerifyKernelPreamble() didn't sign header");
+
+ Memcpy(h, hdr, hsize);
+ h->body_signature.sig_offset = hsize;
+ ReSignKernelPreamble(h, private_key);
+ TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0,
+ "VerifyKernelPreamble() body sig off end");
+
+ /* TODO: verify parser can support a bigger header. */
+
+ free(h);
+ RSAPublicKeyFree(rsa);
+ free(hdr);
}
+int test_algorithm(int key_algorithm, const char *keys_dir)
+{
+ char filename[1024];
+ int rsa_len = siglen_map[key_algorithm] * 8;
+
+ VbPrivateKey *private_key = NULL;
+ VbPublicKey *public_key = NULL;
+
+ printf("***Testing algorithm: %s\n", algo_strings[key_algorithm]);
+
+ sprintf(filename, "%s/key_rsa%d.pem", keys_dir, rsa_len);
+ private_key = PrivateKeyReadPem(filename, key_algorithm);
+ if (!private_key) {
+ fprintf(stderr, "Error reading private_key: %s\n", filename);
+ return 1;
+ }
+
+ sprintf(filename, "%s/key_rsa%d.keyb", keys_dir, rsa_len);
+ public_key = PublicKeyReadKeyb(filename, key_algorithm, 1);
+ if (!public_key) {
+ fprintf(stderr, "Error reading public_key: %s\n", filename);
+ return 1;
+ }
+
+ VerifyPublicKeyToRSA(public_key);
+ VerifyDataTest(public_key, private_key);
+ VerifyDigestTest(public_key, private_key);
+ VerifyKernelPreambleTest(public_key, private_key);
+
+ if (public_key)
+ free(public_key);
+ if (private_key)
+ free(private_key);
+
+ return 0;
+}
-int main(int argc, char* argv[]) {
- VbPrivateKey* private_key = NULL;
- VbPublicKey* public_key = NULL;
- int key_algorithm;
-
- int error_code = 0;
-
- if(argc != 4) {
- fprintf(stderr, "Usage: %s <key_algorithm> <key> <processed pubkey>"
- " <signing key> <processed signing key>\n", argv[0]);
- return -1;
- }
+/*
+ * Test only the algorithms we use:
+ * 4 (rsa2048 sha256)
+ * 7 (rsa4096 sha256)
+ * 11 (rsa8192 sha512)
+ */
+const int key_algs[] = {4, 7, 11};
- /* Read verification keys and create a test image. */
- key_algorithm = atoi(argv[1]);
+int main(int argc, char *argv[]) {
+ if (argc == 2) {
+ int i;
- private_key = PrivateKeyReadPem(argv[2], key_algorithm);
- if (!private_key) {
- fprintf(stderr, "Error reading private_key");
- return 1;
- }
+ for (i = 0; i < ARRAY_SIZE(key_algs); i++) {
+ if (test_algorithm(key_algs[i], argv[1]))
+ return 1;
+ }
- public_key = PublicKeyReadKeyb(argv[3], key_algorithm, 1);
- if (!public_key) {
- fprintf(stderr, "Error reading public_key");
- return 1;
- }
+ } else if (argc == 3 && !strcasecmp(argv[2], "--all")) {
+ /* Test all the algorithms */
+ int alg;
- VerifyPublicKeyToRSA(public_key);
- VerifyDataTest(public_key, private_key);
- VerifyDigestTest(public_key, private_key);
- VerifyKernelPreambleTest(public_key, private_key);
+ for (alg = 0; alg < kNumAlgorithms; alg++) {
+ if (test_algorithm(alg, argv[1]))
+ return 1;
+ }
- if (public_key)
- free(public_key);
- if (private_key)
- free(private_key);
+ } else {
+ fprintf(stderr, "Usage: %s <keys_dir> [--all]", argv[0]);
+ return -1;
+ }
- return error_code;
+ return gTestSuccess ? 0 : 255;
}
diff --git a/tests/vboot_common3_tests.c b/tests/vboot_common3_tests.c
index a63e477c..ce818a4c 100644
--- a/tests/vboot_common3_tests.c
+++ b/tests/vboot_common3_tests.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -7,6 +7,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "cryptolib.h"
#include "file_keys.h"
@@ -254,56 +255,107 @@ static void VerifyFirmwarePreambleTest(const VbPublicKey* public_key,
free(hdr);
}
+int test_permutation(int signing_key_algorithm, int data_key_algorithm,
+ const char *keys_dir)
+{
+ char filename[1024];
+ int signing_rsa_len = siglen_map[signing_key_algorithm] * 8;;
+ int data_rsa_len = siglen_map[data_key_algorithm] * 8;;
+
+ VbPrivateKey* signing_private_key = NULL;
+ VbPublicKey* signing_public_key = NULL;
+ VbPublicKey* data_public_key = NULL;
+
+ printf("***Testing signing algorithm: %s\n",
+ algo_strings[signing_key_algorithm]);
+ printf("***With data key algorithm: %s\n",
+ algo_strings[data_key_algorithm]);
+
+ sprintf(filename, "%s/key_rsa%d.pem", keys_dir, signing_rsa_len);
+ signing_private_key = PrivateKeyReadPem(filename,
+ signing_key_algorithm);
+ if (!signing_private_key) {
+ fprintf(stderr, "Error reading signing_private_key: %s\n",
+ filename);
+ return 1;
+ }
+
+ sprintf(filename, "%s/key_rsa%d.keyb", keys_dir, signing_rsa_len);
+ signing_public_key = PublicKeyReadKeyb(filename,
+ signing_key_algorithm, 1);
+ if (!signing_public_key) {
+ fprintf(stderr, "Error reading signing_public_key: %s\n",
+ filename);
+ return 1;
+ }
+
+ sprintf(filename, "%s/key_rsa%d.keyb", keys_dir, data_rsa_len);
+ data_public_key = PublicKeyReadKeyb(filename,
+ data_key_algorithm, 1);
+ if (!data_public_key) {
+ fprintf(stderr, "Error reading data_public_key: %s\n",
+ filename);
+ return 1;
+ }
+
+ KeyBlockVerifyTest(signing_public_key, signing_private_key,
+ data_public_key);
+ VerifyFirmwarePreambleTest(signing_public_key, signing_private_key,
+ data_public_key);
+
+ if (signing_public_key)
+ free(signing_public_key);
+ if (signing_private_key)
+ free(signing_private_key);
+ if (data_public_key)
+ free(data_public_key);
+
+ return 0;
+}
-int main(int argc, char* argv[]) {
- VbPrivateKey* signing_private_key = NULL;
- VbPublicKey* signing_public_key = NULL;
- int signing_key_algorithm;
-
- VbPublicKey* data_public_key = NULL;
- int data_key_algorithm;
-
- int error_code = 0;
-
- if(argc != 7) {
- fprintf(stderr, "Usage: %s <signing_key_algorithm> <data_key_algorithm>"
- " <signing key> <processed signing pubkey>"
- " <data key> <processed data pubkey>\n", argv[0]);
- return -1;
- }
-
- /* Read verification keys and create a test image. */
- signing_key_algorithm = atoi(argv[1]);
- data_key_algorithm = atoi(argv[2]);
-
- signing_private_key = PrivateKeyReadPem(argv[3], signing_key_algorithm);
- if (!signing_private_key) {
- fprintf(stderr, "Error reading signing_private_key");
- return 1;
- }
-
- signing_public_key = PublicKeyReadKeyb(argv[4], signing_key_algorithm, 1);
- if (!signing_public_key) {
- fprintf(stderr, "Error reading signing_public_key");
- return 1;
- }
-
- data_public_key = PublicKeyReadKeyb(argv[6], data_key_algorithm, 1);
- if (!data_public_key) {
- fprintf(stderr, "Error reading data_public_key");
- return 1;
- }
-
- KeyBlockVerifyTest(signing_public_key, signing_private_key, data_public_key);
- VerifyFirmwarePreambleTest(signing_public_key, signing_private_key,
- data_public_key);
-
- if (signing_public_key)
- free(signing_public_key);
- if (signing_private_key)
- free(signing_private_key);
- if (data_public_key)
- free(data_public_key);
-
- return error_code;
+struct test_perm
+{
+ int signing_algorithm;
+ int data_key_algorithm;
+};
+
+/*
+ * Permutations of signing and data key algorithms in active use:
+ * 7 (rsa4096 sha256) - 4 (rsa2048 sha256)
+ * 11 (rsa8192 sha512) - 4 (rsa2048 sha256)
+ * 11 (rsa8192 sha512) - 7 (rsa4096 sha256)
+ */
+const struct test_perm test_perms[] = {{7, 4}, {11, 4}, {11, 7}};
+
+int main(int argc, char* argv[])
+{
+ if (argc == 2) {
+ /* Test only the algorithms we use */
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(test_perms); i++) {
+ if (test_permutation(test_perms[i].signing_algorithm,
+ test_perms[i].data_key_algorithm,
+ argv[1]))
+ return 1;
+ }
+
+ } else if (argc == 3 && !strcasecmp(argv[2], "--all")) {
+ /* Test all the algorithms */
+ int sign_alg, data_alg;
+
+ for (sign_alg = 0; sign_alg < kNumAlgorithms; sign_alg++) {
+ for (data_alg = 0; data_alg < kNumAlgorithms;
+ data_alg++) {
+ if (test_permutation(sign_alg, data_alg,
+ argv[1]))
+ return 1;
+ }
+ }
+ } else {
+ fprintf(stderr, "Usage: %s <keys_dir> [--all]", argv[0]);
+ return -1;
+ }
+
+ return gTestSuccess ? 0 : 255;
}
diff --git a/tests/vboot_common_tests.c b/tests/vboot_common_tests.c
index 85b2d4ed..f36ec76d 100644
--- a/tests/vboot_common_tests.c
+++ b/tests/vboot_common_tests.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -12,209 +12,220 @@
#include "utility.h"
#include "vboot_common.h"
-/* Test struct packing for vboot_struct.h structs which are passed
- * between firmware and OS, or passed between different phases of
- * firmware. */
-static void StructPackingTest(void) {
- TEST_EQ(EXPECTED_VBPUBLICKEY_SIZE, sizeof(VbPublicKey),
- "sizeof(VbPublicKey)");
- TEST_EQ(EXPECTED_VBSIGNATURE_SIZE, sizeof(VbSignature),
- "sizeof(VbSignature)");
- TEST_EQ(EXPECTED_VBKEYBLOCKHEADER_SIZE, sizeof(VbKeyBlockHeader),
- "sizeof(VbKeyBlockHeader)");
- TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER2_0_SIZE,
- sizeof(VbFirmwarePreambleHeader2_0),
- "sizeof(VbFirmwarePreambleHeader2_0)");
- TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER2_1_SIZE,
- sizeof(VbFirmwarePreambleHeader),
- "sizeof(VbFirmwarePreambleHeader)");
- TEST_EQ(EXPECTED_VBKERNELPREAMBLEHEADER_SIZE,
- sizeof(VbKernelPreambleHeader), "sizeof(VbKernelPreambleHeader)");
-
- TEST_EQ(VB_SHARED_DATA_HEADER_SIZE_V1,
- (long)&((VbSharedDataHeader*)NULL)->recovery_reason,
- "sizeof(VbSharedDataHeader) V1");
-
- TEST_EQ(VB_SHARED_DATA_HEADER_SIZE_V2,
- sizeof(VbSharedDataHeader),
- "sizeof(VbSharedDataHeader) V2");
+/*
+ * Test struct packing for vboot_struct.h structs which are passed between
+ * firmware and OS, or passed between different phases of firmware.
+ */
+static void StructPackingTest(void)
+{
+ TEST_EQ(EXPECTED_VBPUBLICKEY_SIZE, sizeof(VbPublicKey),
+ "sizeof(VbPublicKey)");
+ TEST_EQ(EXPECTED_VBSIGNATURE_SIZE, sizeof(VbSignature),
+ "sizeof(VbSignature)");
+ TEST_EQ(EXPECTED_VBKEYBLOCKHEADER_SIZE, sizeof(VbKeyBlockHeader),
+ "sizeof(VbKeyBlockHeader)");
+ TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER2_0_SIZE,
+ sizeof(VbFirmwarePreambleHeader2_0),
+ "sizeof(VbFirmwarePreambleHeader2_0)");
+ TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER2_1_SIZE,
+ sizeof(VbFirmwarePreambleHeader),
+ "sizeof(VbFirmwarePreambleHeader)");
+ TEST_EQ(EXPECTED_VBKERNELPREAMBLEHEADER_SIZE,
+ sizeof(VbKernelPreambleHeader),
+ "sizeof(VbKernelPreambleHeader)");
+
+ TEST_EQ(VB_SHARED_DATA_HEADER_SIZE_V1,
+ (long)&((VbSharedDataHeader*)NULL)->recovery_reason,
+ "sizeof(VbSharedDataHeader) V1");
+
+ TEST_EQ(VB_SHARED_DATA_HEADER_SIZE_V2,
+ sizeof(VbSharedDataHeader),
+ "sizeof(VbSharedDataHeader) V2");
}
-
/* Test array size macro */
-static void ArraySizeTest(void) {
- uint8_t arr1[12];
- uint32_t arr2[7];
- uint64_t arr3[9];
-
- TEST_EQ(ARRAY_SIZE(arr1), 12, "ARRAYSIZE(uint8_t)");
- TEST_EQ(ARRAY_SIZE(arr2), 7, "ARRAYSIZE(uint32_t)");
- TEST_EQ(ARRAY_SIZE(arr3), 9, "ARRAYSIZE(uint64_t)");
+static void ArraySizeTest(void)
+{
+ uint8_t arr1[12];
+ uint32_t arr2[7];
+ uint64_t arr3[9];
+
+ TEST_EQ(ARRAY_SIZE(arr1), 12, "ARRAYSIZE(uint8_t)");
+ TEST_EQ(ARRAY_SIZE(arr2), 7, "ARRAYSIZE(uint32_t)");
+ TEST_EQ(ARRAY_SIZE(arr3), 9, "ARRAYSIZE(uint64_t)");
}
-
/* Helper functions not dependent on specific key sizes */
-static void VerifyHelperFunctions(void) {
-
- {
- uint8_t *p = (uint8_t *)VerifyHelperFunctions;
- TEST_EQ((int)OffsetOf(p, p), 0, "OffsetOf() equal");
- TEST_EQ((int)OffsetOf(p, p+10), 10, "OffsetOf() positive");
- TEST_EQ((int)OffsetOf(p, p+0x12345678), 0x12345678, "OffsetOf() large");
- }
-
- {
- VbPublicKey k = {sizeof(k), 2, 3, 4};
- TEST_EQ((int)OffsetOf(&k, GetPublicKeyData(&k)), sizeof(k),
- "GetPublicKeyData() adjacent");
- TEST_EQ((int)OffsetOf(&k, GetPublicKeyDataC(&k)), sizeof(k),
- "GetPublicKeyDataC() adjacent");
- }
-
- {
- VbPublicKey k = {123, 2, 3, 4};
- TEST_EQ((int)OffsetOf(&k, GetPublicKeyData(&k)), 123,
- "GetPublicKeyData() spaced");
- TEST_EQ((int)OffsetOf(&k, GetPublicKeyDataC(&k)), 123,
- "GetPublicKeyDataC() spaced");
- }
-
- {
- uint8_t *p = (uint8_t *)VerifyHelperFunctions;
- TEST_EQ(VerifyMemberInside(p, 20, p, 6, 11, 3), 0, "MemberInside ok 1");
- TEST_EQ(VerifyMemberInside(p, 20, p+4, 4, 8, 4), 0, "MemberInside ok 2");
- TEST_EQ(VerifyMemberInside(p, 20, p-4, 4, 8, 4), 1,
- "MemberInside member before parent");
- TEST_EQ(VerifyMemberInside(p, 20, p+20, 4, 8, 4), 1,
- "MemberInside member after parent");
- TEST_EQ(VerifyMemberInside(p, 20, p, 21, 0, 0), 1,
- "MemberInside member too big");
- TEST_EQ(VerifyMemberInside(p, 20, p, 4, 21, 0), 1,
- "MemberInside data after parent");
- TEST_EQ(VerifyMemberInside(p, 20, p, 4, (uint64_t)-1, 0), 1,
- "MemberInside data before parent");
- TEST_EQ(VerifyMemberInside(p, 20, p, 4, 4, 17), 1,
- "MemberInside data too big");
- }
-
- {
- VbPublicKey k = {sizeof(k), 128, 0, 0};
- TEST_EQ(VerifyPublicKeyInside(&k, sizeof(k)+128, &k), 0,
- "PublicKeyInside ok 1");
- TEST_EQ(VerifyPublicKeyInside(&k - 1, 2*sizeof(k)+128, &k), 0,
- "PublicKeyInside ok 2");
- TEST_EQ(VerifyPublicKeyInside(&k, 128, &k), 1,
- "PublicKeyInside key too big");
- }
- {
- VbPublicKey k = {100, 4, 0, 0};
- TEST_EQ(VerifyPublicKeyInside(&k, 99, &k), 1,
- "PublicKeyInside offset too big");
- }
- {
- VbSignature s = {sizeof(s), 128, 2000};
- TEST_EQ(VerifySignatureInside(&s, sizeof(s)+128, &s), 0,
- "SignatureInside ok 1");
- TEST_EQ(VerifySignatureInside(&s - 1, 2*sizeof(s)+128, &s), 0,
- "SignatureInside ok 2");
- TEST_EQ(VerifySignatureInside(&s, 128, &s), 1,
- "SignatureInside sig too big");
- }
- {
- VbSignature s = {100, 4, 0};
- TEST_EQ(VerifySignatureInside(&s, 99, &s), 1,
- "SignatureInside offset too big");
- }
+static void VerifyHelperFunctions(void)
+{
+ {
+ uint8_t *p = (uint8_t *)VerifyHelperFunctions;
+ TEST_EQ((int)OffsetOf(p, p), 0, "OffsetOf() equal");
+ TEST_EQ((int)OffsetOf(p, p+10), 10, "OffsetOf() positive");
+ TEST_EQ((int)OffsetOf(p, p+0x12345678), 0x12345678,
+ "OffsetOf() large");
+ }
+
+ {
+ VbPublicKey k = {sizeof(k), 2, 3, 4};
+ TEST_EQ((int)OffsetOf(&k, GetPublicKeyData(&k)), sizeof(k),
+ "GetPublicKeyData() adjacent");
+ TEST_EQ((int)OffsetOf(&k, GetPublicKeyDataC(&k)), sizeof(k),
+ "GetPublicKeyDataC() adjacent");
+ }
+
+ {
+ VbPublicKey k = {123, 2, 3, 4};
+ TEST_EQ((int)OffsetOf(&k, GetPublicKeyData(&k)), 123,
+ "GetPublicKeyData() spaced");
+ TEST_EQ((int)OffsetOf(&k, GetPublicKeyDataC(&k)), 123,
+ "GetPublicKeyDataC() spaced");
+ }
+
+ {
+ uint8_t *p = (uint8_t *)VerifyHelperFunctions;
+ TEST_EQ(VerifyMemberInside(p, 20, p, 6, 11, 3), 0,
+ "MemberInside ok 1");
+ TEST_EQ(VerifyMemberInside(p, 20, p+4, 4, 8, 4), 0,
+ "MemberInside ok 2");
+ TEST_EQ(VerifyMemberInside(p, 20, p-4, 4, 8, 4), 1,
+ "MemberInside member before parent");
+ TEST_EQ(VerifyMemberInside(p, 20, p+20, 4, 8, 4), 1,
+ "MemberInside member after parent");
+ TEST_EQ(VerifyMemberInside(p, 20, p, 21, 0, 0), 1,
+ "MemberInside member too big");
+ TEST_EQ(VerifyMemberInside(p, 20, p, 4, 21, 0), 1,
+ "MemberInside data after parent");
+ TEST_EQ(VerifyMemberInside(p, 20, p, 4, (uint64_t)-1, 0), 1,
+ "MemberInside data before parent");
+ TEST_EQ(VerifyMemberInside(p, 20, p, 4, 4, 17), 1,
+ "MemberInside data too big");
+ }
+
+ {
+ VbPublicKey k = {sizeof(k), 128, 0, 0};
+ TEST_EQ(VerifyPublicKeyInside(&k, sizeof(k)+128, &k), 0,
+ "PublicKeyInside ok 1");
+ TEST_EQ(VerifyPublicKeyInside(&k - 1, 2*sizeof(k)+128, &k), 0,
+ "PublicKeyInside ok 2");
+ TEST_EQ(VerifyPublicKeyInside(&k, 128, &k), 1,
+ "PublicKeyInside key too big");
+ }
+
+ {
+ VbPublicKey k = {100, 4, 0, 0};
+ TEST_EQ(VerifyPublicKeyInside(&k, 99, &k), 1,
+ "PublicKeyInside offset too big");
+ }
+
+ {
+ VbSignature s = {sizeof(s), 128, 2000};
+ TEST_EQ(VerifySignatureInside(&s, sizeof(s)+128, &s), 0,
+ "SignatureInside ok 1");
+ TEST_EQ(VerifySignatureInside(&s - 1, 2*sizeof(s)+128, &s), 0,
+ "SignatureInside ok 2");
+ TEST_EQ(VerifySignatureInside(&s, 128, &s), 1,
+ "SignatureInside sig too big");
+ }
+
+ {
+ VbSignature s = {100, 4, 0};
+ TEST_EQ(VerifySignatureInside(&s, 99, &s), 1,
+ "SignatureInside offset too big");
+ }
}
-
/* Public key utility functions */
-static void PublicKeyTest(void) {
- VbPublicKey k[3];
- VbPublicKey j[5];
-
- /* Fill some bits of the public key data */
- Memset(j, 0, sizeof(j));
- Memset(k, 0x42, sizeof(k));
- k[1].key_size = 12345;
- k[2].key_version = 67;
-
- PublicKeyInit(k, (uint8_t*)(k + 1), 2 * sizeof(VbPublicKey));
- TEST_EQ(k->key_offset, sizeof(VbPublicKey), "PublicKeyInit key_offset");
- TEST_EQ(k->key_size, 2 * sizeof(VbPublicKey), "PublicKeyInit key_size");
- TEST_EQ(k->algorithm, kNumAlgorithms, "PublicKeyInit algorithm");
- TEST_EQ(k->key_version, 0, "PublicKeyInit key_version");
-
- /* Set algorithm and version, so we can tell if they get copied */
- k->algorithm = 3;
- k->key_version = 21;
-
- /* Copying to a smaller destination should fail */
- PublicKeyInit(j, (uint8_t*)(j + 1), 2 * sizeof(VbPublicKey) - 1);
- TEST_NEQ(0, PublicKeyCopy(j, k), "PublicKeyCopy too small");
-
- /* Copying to same or larger size should succeed */
- PublicKeyInit(j, (uint8_t*)(j + 2), 2 * sizeof(VbPublicKey) + 1);
- TEST_EQ(0, PublicKeyCopy(j, k), "PublicKeyCopy same");
- /* Offset in destination shouldn't have been modified */
- TEST_EQ(j->key_offset, 2 * sizeof(VbPublicKey), "PublicKeyCopy key_offset");
- /* Size should have been reduced to match the source */
- TEST_EQ(k->key_size, 2 * sizeof(VbPublicKey), "PublicKeyCopy key_size");
- /* Other fields should have been copied */
- TEST_EQ(k->algorithm, j->algorithm, "PublicKeyCopy algorithm");
- TEST_EQ(k->key_version, j->key_version, "PublicKeyCopy key_version");
- /* Data should have been copied */
- TEST_EQ(0, Memcmp(GetPublicKeyData(k), GetPublicKeyData(j), k->key_size),
- "PublicKeyCopy data");
+static void PublicKeyTest(void)
+{
+ VbPublicKey k[3];
+ VbPublicKey j[5];
+
+ /* Fill some bits of the public key data */
+ Memset(j, 0, sizeof(j));
+ Memset(k, 0x42, sizeof(k));
+ k[1].key_size = 12345;
+ k[2].key_version = 67;
+
+ PublicKeyInit(k, (uint8_t*)(k + 1), 2 * sizeof(VbPublicKey));
+ TEST_EQ(k->key_offset, sizeof(VbPublicKey), "PublicKeyInit key_offset");
+ TEST_EQ(k->key_size, 2 * sizeof(VbPublicKey), "PublicKeyInit key_size");
+ TEST_EQ(k->algorithm, kNumAlgorithms, "PublicKeyInit algorithm");
+ TEST_EQ(k->key_version, 0, "PublicKeyInit key_version");
+
+ /* Set algorithm and version, so we can tell if they get copied */
+ k->algorithm = 3;
+ k->key_version = 21;
+
+ /* Copying to a smaller destination should fail */
+ PublicKeyInit(j, (uint8_t*)(j + 1), 2 * sizeof(VbPublicKey) - 1);
+ TEST_NEQ(0, PublicKeyCopy(j, k), "PublicKeyCopy too small");
+
+ /* Copying to same or larger size should succeed */
+ PublicKeyInit(j, (uint8_t*)(j + 2), 2 * sizeof(VbPublicKey) + 1);
+ TEST_EQ(0, PublicKeyCopy(j, k), "PublicKeyCopy same");
+ /* Offset in destination shouldn't have been modified */
+ TEST_EQ(j->key_offset, 2 * sizeof(VbPublicKey),
+ "PublicKeyCopy key_offset");
+ /* Size should have been reduced to match the source */
+ TEST_EQ(k->key_size, 2 * sizeof(VbPublicKey), "PublicKeyCopy key_size");
+ /* Other fields should have been copied */
+ TEST_EQ(k->algorithm, j->algorithm, "PublicKeyCopy algorithm");
+ TEST_EQ(k->key_version, j->key_version, "PublicKeyCopy key_version");
+ /* Data should have been copied */
+ TEST_EQ(0,
+ Memcmp(GetPublicKeyData(k), GetPublicKeyData(j), k->key_size),
+ "PublicKeyCopy data");
}
-
/* VbSharedData utility tests */
-static void VbSharedDataTest(void) {
- uint8_t buf[VB_SHARED_DATA_MIN_SIZE + 1];
- VbSharedDataHeader* d = (VbSharedDataHeader*)buf;
-
- TEST_NEQ(VBOOT_SUCCESS, VbSharedDataInit(d, sizeof(VbSharedDataHeader) - 1),
- "VbSharedDataInit too small");
- TEST_NEQ(VBOOT_SUCCESS, VbSharedDataInit(d, VB_SHARED_DATA_MIN_SIZE - 1),
- "VbSharedDataInit too small 2");
- TEST_NEQ(VBOOT_SUCCESS, VbSharedDataInit(NULL, VB_SHARED_DATA_MIN_SIZE),
- "VbSharedDataInit null");
-
- Memset(buf, 0x68, sizeof(buf));
- TEST_EQ(VBOOT_SUCCESS, VbSharedDataInit(d, VB_SHARED_DATA_MIN_SIZE),
- "VbSharedDataInit");
- /* Check fields that should have been initialized */
- TEST_EQ(d->magic, VB_SHARED_DATA_MAGIC, "VbSharedDataInit magic");
- TEST_EQ(d->struct_version, VB_SHARED_DATA_VERSION,
- "VbSharedDataInit version");
- TEST_EQ(d->struct_size, sizeof(VbSharedDataHeader),
- "VbSharedDataInit struct_size");
- TEST_EQ(d->data_size, VB_SHARED_DATA_MIN_SIZE, "VbSharedDataInit data_size");
- TEST_EQ(d->data_used, d->struct_size, "VbSharedDataInit data_used");
- TEST_EQ(d->firmware_index, 0xFF, "VbSharedDataInit firmware index");
- /* Sample some other fields to make sure they were zeroed */
- TEST_EQ(d->flags, 0, "VbSharedDataInit firmware flags");
- TEST_EQ(d->lk_call_count, 0, "VbSharedDataInit lk_call_count");
- TEST_EQ(d->kernel_version_lowest, 0,
- "VbSharedDataInit kernel_version_lowest");
+static void VbSharedDataTest(void)
+{
+ uint8_t buf[VB_SHARED_DATA_MIN_SIZE + 1];
+ VbSharedDataHeader* d = (VbSharedDataHeader*)buf;
+
+ TEST_NEQ(VBOOT_SUCCESS,
+ VbSharedDataInit(d, sizeof(VbSharedDataHeader) - 1),
+ "VbSharedDataInit too small");
+ TEST_NEQ(VBOOT_SUCCESS,
+ VbSharedDataInit(d, VB_SHARED_DATA_MIN_SIZE - 1),
+ "VbSharedDataInit too small 2");
+ TEST_NEQ(VBOOT_SUCCESS,
+ VbSharedDataInit(NULL, VB_SHARED_DATA_MIN_SIZE),
+ "VbSharedDataInit null");
+
+ Memset(buf, 0x68, sizeof(buf));
+ TEST_EQ(VBOOT_SUCCESS, VbSharedDataInit(d, VB_SHARED_DATA_MIN_SIZE),
+ "VbSharedDataInit");
+
+ /* Check fields that should have been initialized */
+ TEST_EQ(d->magic, VB_SHARED_DATA_MAGIC, "VbSharedDataInit magic");
+ TEST_EQ(d->struct_version, VB_SHARED_DATA_VERSION,
+ "VbSharedDataInit version");
+ TEST_EQ(d->struct_size, sizeof(VbSharedDataHeader),
+ "VbSharedDataInit struct_size");
+ TEST_EQ(d->data_size, VB_SHARED_DATA_MIN_SIZE,
+ "VbSharedDataInit data_size");
+ TEST_EQ(d->data_used, d->struct_size, "VbSharedDataInit data_used");
+ TEST_EQ(d->firmware_index, 0xFF, "VbSharedDataInit firmware index");
+
+ /* Sample some other fields to make sure they were zeroed */
+ TEST_EQ(d->flags, 0, "VbSharedDataInit firmware flags");
+ TEST_EQ(d->lk_call_count, 0, "VbSharedDataInit lk_call_count");
+ TEST_EQ(d->kernel_version_lowest, 0,
+ "VbSharedDataInit kernel_version_lowest");
}
-
/* disable MSVC warnings on unused arguments */
__pragma(warning (disable: 4100))
-int main(int argc, char* argv[]) {
- int error_code = 0;
-
- StructPackingTest();
- ArraySizeTest();
- VerifyHelperFunctions();
- PublicKeyTest();
- VbSharedDataTest();
-
- if (!gTestSuccess)
- error_code = 255;
+int main(int argc, char* argv[])
+{
+ StructPackingTest();
+ ArraySizeTest();
+ VerifyHelperFunctions();
+ PublicKeyTest();
+ VbSharedDataTest();
- return error_code;
+ return gTestSuccess ? 0 : 255;
}
diff --git a/tests/vboot_display_tests.c b/tests/vboot_display_tests.c
new file mode 100644
index 00000000..5713667b
--- /dev/null
+++ b/tests/vboot_display_tests.c
@@ -0,0 +1,83 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Tests for firmware display library.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gbb_header.h"
+#include "host_common.h"
+#include "test_common.h"
+#include "vboot_common.h"
+#include "vboot_display.h"
+#include "vboot_nvstorage.h"
+
+/* Mock data */
+static VbCommonParams cparams;
+static VbNvContext vnc;
+static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
+static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
+static GoogleBinaryBlockHeader gbb;
+static char debug_info[4096];
+
+/* Reset mock data (for use before each test) */
+static void ResetMocks(void)
+{
+ Memset(&cparams, 0, sizeof(cparams));
+ cparams.shared_data_size = sizeof(shared_data);
+ cparams.shared_data_blob = shared_data;
+ cparams.gbb_data = &gbb;
+
+ Memset(&gbb, 0, sizeof(gbb));
+ gbb.major_version = GBB_MAJOR_VER;
+ gbb.minor_version = GBB_MINOR_VER;
+ gbb.flags = 0;
+
+ Memset(&vnc, 0, sizeof(vnc));
+ VbNvSetup(&vnc);
+ VbNvTeardown(&vnc); /* So CRC gets generated */
+
+ Memset(&shared_data, 0, sizeof(shared_data));
+ VbSharedDataInit(shared, sizeof(shared_data));
+
+ *debug_info = 0;
+}
+
+/* Mocks */
+
+VbError_t VbExDisplayDebugInfo(const char *info_str)
+{
+ strncpy(debug_info, info_str, sizeof(debug_info));
+ debug_info[sizeof(debug_info) - 1] = '\0';
+ return VBERROR_SUCCESS;
+}
+
+/* Test displaying debug info */
+static void DebugInfoTest(void)
+{
+ int i;
+
+ /* Recovery string should be non-null for any code */
+ for (i = 0; i < 0x100; i++)
+ TEST_PTR_NEQ(RecoveryReasonString(i), NULL, "Non-null reason");
+
+ /* Display debug info */
+ VbDisplayDebugInfo(&cparams, &vnc);
+ TEST_NEQ(*debug_info, '\0', "Some debug info was displayed");
+}
+
+/* disable MSVC warnings on unused arguments */
+__pragma(warning (disable: 4100))
+
+int main(int argc, char* argv[])
+{
+ ResetMocks(); // KLUDGE
+
+ DebugInfoTest();
+
+ return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/vboot_ec_tests.c b/tests/vboot_ec_tests.c
deleted file mode 100644
index 831565fc..00000000
--- a/tests/vboot_ec_tests.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Tests for EC firmware vboot stuff.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "cryptolib.h"
-#include "file_keys.h"
-#include "host_common.h"
-#include "test_common.h"
-#include "vboot_common.h"
-
-static void ReSignECPreamble(VbECPreambleHeader* h,
- const VbPrivateKey* key) {
- VbSignature *sig = CalculateSignature((const uint8_t*)h,
- h->preamble_signature.data_size, key);
-
- SignatureCopy(&h->preamble_signature, sig);
- free(sig);
-}
-
-
-static void VerifyECPreambleTest(const VbPublicKey* public_key,
- const VbPrivateKey* private_key) {
- VbECPreambleHeader* hdr;
- VbECPreambleHeader* h;
- RSAPublicKey* rsa;
- unsigned hsize;
-
- /* Create a dummy signature */
- VbSignature* body_sig = SignatureAlloc(56, 78);
-
- rsa = PublicKeyToRSA(public_key);
- hdr = CreateECPreamble(0x1234, body_sig, private_key,
- 0x5678, "Foo bar");
- TEST_NEQ(hdr && rsa, 0, "VerifyECPreamble() prerequisites");
- if (!hdr)
- return;
-
- hsize = (unsigned) hdr->preamble_size;
- h = (VbECPreambleHeader*)malloc(hsize + 16384);
-
- TEST_EQ(VerifyECPreamble(hdr, hsize, rsa), 0,
- "VerifyECPreamble() ok using key");
- TEST_NEQ(VerifyECPreamble(hdr, hsize - 1, rsa), 0,
- "VerifyECPreamble() size--");
- TEST_EQ(VerifyECPreamble(hdr, hsize + 1, rsa), 0,
- "VerifyECPreamble() size++");
-
- TEST_EQ(hdr->firmware_version, 0x1234,
- "VerifyECPreamble() firmware version");
- TEST_EQ(hdr->flags, 0x5678,
- "VerifyECPreamble() flags");
- TEST_EQ(strncmp(hdr->name, "Foo bar", sizeof(hdr->name)), 0,
- "VerifyECPreamble() name");
-
- /* Care about major version but not minor */
- Memcpy(h, hdr, hsize);
- h->header_version_major++;
- ReSignECPreamble(h, private_key);
- TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
- "VerifyECPreamble() major++");
-
- Memcpy(h, hdr, hsize);
- h->header_version_major--;
- ReSignECPreamble(h, private_key);
- TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
- "VerifyECPreamble() major--");
-
- Memcpy(h, hdr, hsize);
- h->header_version_minor++;
- ReSignECPreamble(h, private_key);
- TEST_EQ(VerifyECPreamble(h, hsize, rsa), 0,
- "VerifyECPreamble() minor++");
-
- Memcpy(h, hdr, hsize);
- h->header_version_minor--;
- ReSignECPreamble(h, private_key);
- TEST_EQ(VerifyECPreamble(h, hsize, rsa), 0,
- "VerifyECPreamble() minor--");
-
- /* Check signature */
- Memcpy(h, hdr, hsize);
- h->preamble_signature.sig_offset = hsize;
- ReSignECPreamble(h, private_key);
- TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
- "VerifyECPreamble() sig off end");
-
- Memcpy(h, hdr, hsize);
- h->preamble_signature.sig_size--;
- ReSignECPreamble(h, private_key);
- TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
- "VerifyECPreamble() sig too small");
-
- Memcpy(h, hdr, hsize);
- GetSignatureData(&h->body_digest)[0] ^= 0x34;
- TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
- "VerifyECPreamble() sig mismatch");
-
- /* Check that we signed header and body sig */
- Memcpy(h, hdr, hsize);
- h->preamble_signature.data_size = 4;
- h->body_digest.sig_offset = 0;
- h->body_digest.sig_size = 0;
- ReSignECPreamble(h, private_key);
- TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
- "VerifyECPreamble() didn't sign header");
-
- Memcpy(h, hdr, hsize);
- h->body_digest.sig_offset = hsize;
- ReSignECPreamble(h, private_key);
- TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
- "VerifyECPreamble() body sig off end");
-
- /* TODO: verify with extra padding at end of header. */
-
- free(h);
- RSAPublicKeyFree(rsa);
- free(hdr);
-}
-
-
-int main(int argc, char* argv[]) {
- VbPrivateKey* signing_private_key = NULL;
- VbPublicKey* signing_public_key = NULL;
-
- int error_code = 0;
-
- if(argc != 3) {
- fprintf(stderr, "Usage: %s <signing privkey> <signing pubkey>", argv[0]);
- return -1;
- }
-
- signing_private_key = PrivateKeyRead(argv[1]);
- if (!signing_private_key) {
- fprintf(stderr, "Error reading signing_private_key\n");
- return 1;
- }
-
- signing_public_key = PublicKeyRead(argv[2]);
- if (!signing_public_key) {
- fprintf(stderr, "Error reading signing_public_key\n");
- return 1;
- }
-
- VerifyECPreambleTest(signing_public_key, signing_private_key);
-
-
- if (signing_public_key)
- free(signing_public_key);
- if (signing_private_key)
- free(signing_private_key);
-
- return error_code;
-}
diff --git a/tests/vboot_nvstorage_test.c b/tests/vboot_nvstorage_test.c
index 19937d6d..15c229f3 100644
--- a/tests/vboot_nvstorage_test.c
+++ b/tests/vboot_nvstorage_test.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -35,6 +35,7 @@ static VbNvField nvfields[] = {
{VBNV_DISABLE_DEV_REQUEST, 0, 1, 0, "disable dev request"},
{VBNV_CLEAR_TPM_OWNER_REQUEST, 0, 1, 0, "clear tpm owner request"},
{VBNV_CLEAR_TPM_OWNER_DONE, 0, 1, 0, "clear tpm owner done"},
+ {VBNV_OPROM_NEEDED, 0, 1, 0, "oprom needed"},
{0, 0, 0, 0, NULL}
};
@@ -102,6 +103,25 @@ static void VbNvStorageTest(void) {
/* That should have changed the CRC */
TEST_NEQ(c.raw[15], goodcrc, "VbNvTeardown() CRC changed due to flags clear");
+ /* Test explicitly setting the reset flags again */
+ VbNvSetup(&c);
+ VbNvSet(&c, VBNV_FIRMWARE_SETTINGS_RESET, 1);
+ VbNvGet(&c, VBNV_FIRMWARE_SETTINGS_RESET, &data);
+ TEST_EQ(data, 1, "Firmware settings forced reset");
+ VbNvSet(&c, VBNV_FIRMWARE_SETTINGS_RESET, 0);
+
+ VbNvSet(&c, VBNV_KERNEL_SETTINGS_RESET, 1);
+ VbNvGet(&c, VBNV_KERNEL_SETTINGS_RESET, &data);
+ TEST_EQ(data, 1, "Kernel settings forced reset");
+ VbNvSet(&c, VBNV_KERNEL_SETTINGS_RESET, 0);
+ VbNvTeardown(&c);
+
+ /* Get/set an invalid field */
+ VbNvSetup(&c);
+ TEST_EQ(VbNvGet(&c, -1, &data), 1, "Get invalid setting");
+ TEST_EQ(VbNvSet(&c, -1, 0), 1, "Set invalid setting");
+ VbNvTeardown(&c);
+
/* Test other fields */
VbNvSetup(&c);
for (vnf = nvfields; vnf->desc; vnf++) {
@@ -134,6 +154,19 @@ static void VbNvStorageTest(void) {
TEST_EQ(c.regenerate_crc, 0, "No regen CRC if data not changed");
VbNvTeardown(&c);
TEST_EQ(c.raw_changed, 0, "No raw change if data not changed");
+
+ /* Test out-of-range fields mapping to defaults */
+ VbNvSetup(&c);
+ VbNvSet(&c, VBNV_TRY_B_COUNT, 16);
+ VbNvGet(&c, VBNV_TRY_B_COUNT, &data);
+ TEST_EQ(data, 15, "Try b count out of range");
+ VbNvSet(&c, VBNV_RECOVERY_REQUEST, 0x101);
+ VbNvGet(&c, VBNV_RECOVERY_REQUEST, &data);
+ TEST_EQ(data, VBNV_RECOVERY_LEGACY, "Recovery request out of range");
+ VbNvSet(&c, VBNV_LOCALIZATION_INDEX, 0x102);
+ VbNvGet(&c, VBNV_LOCALIZATION_INDEX, &data);
+ TEST_EQ(data, 0, "Localization index out of range");
+ VbNvTeardown(&c);
}
diff --git a/utility/vbutil_ec.c b/utility/vbutil_ec.c
deleted file mode 100644
index 4aa0d3f8..00000000
--- a/utility/vbutil_ec.c
+++ /dev/null
@@ -1,532 +0,0 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Verified boot utility for EC firmware
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "cryptolib.h"
-#include "fmap.h"
-#include "host_common.h"
-#include "vboot_common.h"
-
-
-/* Command line options */
-enum {
- OPT_MODE_SIGN = 1000,
- OPT_MODE_VERIFY,
- OPT_KEYBLOCK,
- OPT_SIGNPUBKEY,
- OPT_SIGNPRIVATE,
- OPT_VERSION,
- OPT_FV,
- OPT_KERNELKEY,
- OPT_FLAGS,
- OPT_NAME,
-};
-
-static struct option long_opts[] = {
- {"sign", 1, 0, OPT_MODE_SIGN },
- {"verify", 1, 0, OPT_MODE_VERIFY },
- {"keyblock", 1, 0, OPT_KEYBLOCK },
- {"signpubkey", 1, 0, OPT_SIGNPUBKEY },
- {"signprivate", 1, 0, OPT_SIGNPRIVATE },
- {"version", 1, 0, OPT_VERSION },
- {"flags", 1, 0, OPT_FLAGS },
- {"name", 1, 0, OPT_NAME },
- {NULL, 0, 0, 0}
-};
-
-
-/* Print help and return error */
-static int PrintHelp(void) {
-
- puts("vbutil_ec - Verified boot signing utility for EC firmware\n"
- "\n"
- "This will sign, re-sign, or test a complete EC firmware image.\n"
- "The EC image is initially completely unsigned. To make it bootable\n"
- "the pubic root key must be installed in the RO section, and each RW\n"
- "section must be signed with the appropriate private keys.\n"
- "\n"
- "To sign an image: vbutil_ec --sign <file> [OPTIONS]\n"
- "\n"
- "For signing, these options are required:\n"
- "\n"
- " --keyblock <file> Key block in .keyblock format\n"
- " --signprivate <file> Signing private key in .vbprivk format\n"
- " --version <number> Firmware version\n"
- "\n"
- "If the RO public key has not been installed, you will also need\n"
- "\n"
- " --signpubkey <file> Signing public key in .vbpubk format\n"
- "\n"
- "Optional args are:\n"
- "\n"
- " --flags <number> Preamble flags (defaults to 0)\n"
- " --name <string> Human-readable description\n"
- "\n"
- "\n"
- "To verify an image: vbutil_ec --verify <file>\n"
- "\n");
- return 1;
-}
-
-
-static int FindInFmap(FmapHeader *fh, const char *name,
- uint8_t *base, uint64_t base_size,
- uint8_t **data, uint64_t *size) {
- const FmapAreaHeader *ah;
- int i;
-
- ah = (FmapAreaHeader *)(fh + 1);
- for (i = 0; i < fh->fmap_nareas; i++)
- if (!strncmp(ah[i].area_name, name, FMAP_NAMELEN)) {
- if (ah[i].area_size + ah[i].area_offset > base_size) {
- printf("FMAP region %s extends off image file\n", name);
- return 0;
- }
- if (data)
- *data = base + ah[i].area_offset;
- if (size)
- *size = ah[i].area_size;
- return 1;
- }
-
- return 0;
-}
-
-static int GoodKey(VbPublicKey *key, uint64_t region_size)
-{
- uint64_t key_size;
-
- if (0 != VerifyPublicKeyInside(key, region_size, key))
- return 0;
-
- if (key->algorithm >= kNumAlgorithms)
- return 0;
-
- /* Currently, TPM only supports 16-bit version */
- if (key->key_version > 0xFFFF)
- return 0;
-
- if (!RSAProcessedKeySize(key->algorithm, &key_size) ||
- key_size != key->key_size)
- return 0;
-
- return 1;
-}
-
-
-/* We build the image file with a non-FF byte at the end of each RW firmware,
- * just so we can do this. */
-static uint64_t FindImageEnd(uint8_t *data, uint64_t size)
-{
- for (size-- ; size && data[size] == 0xff; size--)
- ;
- return size;
-}
-
-static void SignImage(const char *filename,
- VbKeyBlockHeader *key_block, uint64_t key_block_size,
- VbPrivateKey *privkey, uint64_t version,
- VbPublicKey *pubkey, uint32_t preamble_flags,
- const char *name) {
- struct stat sb;
- int fd;
- void *image;
- uint64_t image_size;
- FmapHeader* fmap;
- VbECPreambleHeader *preamble;
- uint8_t *fv_data = 0;
- uint8_t *vblock_data = 0;
- uint64_t fv_size, vblock_size;
- VbSignature* body_digest;
-
- if (name && strlen(name)+1 > sizeof(preamble->name))
- VbExError("Name string is too long\n");
-
- if (0 != stat(filename, &sb))
- VbExError("Can't stat %s: %s\n", filename, strerror(errno));
-
- fd = open(filename, O_RDWR);
- if (fd < 0)
- VbExError("Can't open %s: %s\n", filename, strerror(errno));
-
- image = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
- if (image == (void *)-1)
- VbExError("Can't mmap %s: %s\n", filename, strerror(errno));
- close(fd); /* done with this now */
-
- fmap = (FmapHeader *)FmapFind(image, sb.st_size);
- if (!fmap)
- VbExError("File %s doesn't have an FMAP - can't continue.\n");
-
- if (fmap->fmap_size > sb.st_size)
- VbExError("FMAP is bigger than file size (%ld vs %ld)\n",
- fmap->fmap_size, sb.st_size);
-
- image_size = sb.st_size;
-
- /* Install pubkey if provided */
- if (pubkey) {
- if (!FindInFmap(fmap, "ROOT_KEY", image, image_size,
- &vblock_data, &vblock_size))
- VbExError("Can't find ROOT_KEY in %s\n", filename);
-
- if (pubkey->key_offset + pubkey->key_size > vblock_size)
- VbExError("ROOT_KEY is too small for pubkey (%d bytes, needs %d)\n",
- vblock_size, pubkey->key_offset + pubkey->key_size);
-
- memcpy(vblock_data, pubkey, pubkey->key_offset + pubkey->key_size);
- }
-
-
- /* Sign FW A */
- if (!FindInFmap(fmap, "FW_MAIN_A", image, image_size, &fv_data, &fv_size))
- VbExError("Can't find FW_MAIN_A in %s\n", filename);
-
- if (!FindInFmap(fmap, "VBLOCK_A", image, image_size,
- &vblock_data, &vblock_size))
- VbExError("Can't find VBLOCK_A in %s\n", filename);
-
- fv_size = FindImageEnd(fv_data, fv_size);
-
- body_digest = CalculateHash(fv_data, fv_size, privkey);
- if (!body_digest)
- VbExError("Error calculating body digest\n");
-
- preamble = CreateECPreamble(version, body_digest, privkey,
- preamble_flags, name);
- if (!preamble)
- VbExError("Error creating preamble.\n");
-
- if (key_block_size + preamble->preamble_size > vblock_size)
- VbExError("VBLOCK_A is too small for digest (%d bytes, needs %d)\n",
- vblock_size, key_block_size + preamble->preamble_size);
-
- memcpy(vblock_data, key_block, key_block_size);
- memcpy(vblock_data + key_block_size, preamble, preamble->preamble_size);
-
- free(body_digest);
- free(preamble);
-
-
- /* Sign FW B - skip if there isn't one */
- if (!FindInFmap(fmap, "FW_MAIN_B", image, image_size, &fv_data, &fv_size) ||
- !FindInFmap(fmap, "VBLOCK_B", image, image_size,
- &vblock_data, &vblock_size)) {
- printf("Image does not contain FW B - ignoring that part\n");
- } else {
- fv_size = FindImageEnd(fv_data, fv_size);
-
- body_digest = CalculateHash(fv_data, fv_size, privkey);
- if (!body_digest)
- VbExError("Error calculating body digest\n");
-
- preamble = CreateECPreamble(version, body_digest, privkey,
- preamble_flags, name);
- if (!preamble)
- VbExError("Error creating preamble.\n");
-
- if (key_block_size + preamble->preamble_size > vblock_size)
- VbExError("VBLOCK_B is too small for digest (%d bytes, needs %d)\n",
- vblock_size, key_block_size + preamble->preamble_size);
-
- memcpy(vblock_data, key_block, key_block_size);
- memcpy(vblock_data + key_block_size, preamble, preamble->preamble_size);
-
- free(body_digest);
- free(preamble);
- }
-
- /* Unmap to write changes to disk. */
- if (0 != munmap(image, sb.st_size))
- VbExError("Can't munmap %s: %s\n", filename, strerror(errno));
-
- printf("Image signing completed\n");
-
-}
-
-static int Verify(const char *filename) {
- struct stat sb;
- int fd;
- void *image;
- uint64_t image_size;
- FmapHeader* fmap;
- VbECPreambleHeader *preamble;
- VbPublicKey *pubkey;
- uint64_t pubkey_size;
- VbKeyBlockHeader *key_block;
- uint64_t key_block_size;
- uint8_t *fv_data = 0;
- uint64_t fv_size;
- VbPublicKey *data_key;
- RSAPublicKey* rsa;
- int errorcnt = 0;
- char buf[80];
- int i;
-
- if (0 != stat(filename, &sb))
- VbExError("Can't stat %s: %s\n", filename, strerror(errno));
-
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- VbExError("Can't open %s: %s\n", filename, strerror(errno));
-
- image = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (image == (void *)-1)
- VbExError("Can't mmap %s: %s\n", filename, strerror(errno));
- close(fd); /* done with this now */
-
- fmap = (FmapHeader *)FmapFind(image, sb.st_size);
- if (!fmap)
- VbExError("File %s doesn't have an FMAP - can't continue.\n");
-
- if (fmap->fmap_size > sb.st_size)
- VbExError("FMAP is bigger than file size (%ld vs %ld)\n",
- fmap->fmap_size, sb.st_size);
-
- image_size = sb.st_size;
-
- /* Read pubkey */
- if (!FindInFmap(fmap, "ROOT_KEY", image, image_size,
- (uint8_t **)&pubkey, &pubkey_size)) {
- printf("Can't find ROOT_KEY in %s\n", filename);
- errorcnt++;
- } else if (!GoodKey(pubkey, pubkey_size)) {
- printf("ROOT_KEY is invalid\n");
- errorcnt++;
- } else {
- printf("ROOT_KEY\n");
- printf(" Algorithm: %" PRIu64 " %s\n", pubkey->algorithm,
- (pubkey->algorithm < kNumAlgorithms ?
- algo_strings[pubkey->algorithm] : "(invalid)"));
- printf(" Key Version: %" PRIu64 "\n", pubkey->key_version);
- printf(" Key sha1sum: ");
- PrintPubKeySha1Sum(pubkey);
- printf("\n");
- }
-
- for (i = 'A'; i <= 'B'; i++) {
-
- fv_data = 0;
- key_block = 0;
- preamble = 0;
-
- printf("FW %c\n", i);
- sprintf(buf, "FW_MAIN_%c", i);
- if (!FindInFmap(fmap, buf, image, image_size, &fv_data, &fv_size)) {
- printf("Can't find %s in %s\n", buf, filename);
- /* Not an error for firmware B */
- if (i != 'B')
- errorcnt++;
- continue;
- }
-
- sprintf(buf, "VBLOCK_%c", i);
- if (!FindInFmap(fmap, buf, image, image_size,
- (uint8_t **)&key_block, &key_block_size)) {
- printf("Can't find %s in %s\n", buf, filename);
- /* Not an error for firmware B */
- if (i != 'B')
- errorcnt++;
- continue;
- }
-
- if (0 != KeyBlockVerify(key_block, key_block_size, pubkey, !pubkey)) {
- printf("Error verifying key block for %s.\n", buf);
- errorcnt++;
- continue;
- }
- printf(" Key block:\n");
- data_key = &key_block->data_key;
- printf(" Size: %" PRIu64 "\n",
- key_block->key_block_size);
- printf(" Flags: %" PRIu64 " (ignored)\n",
- key_block->key_block_flags);
- printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
- (data_key->algorithm < kNumAlgorithms ?
- algo_strings[data_key->algorithm] : "(invalid)"));
- printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
- printf(" Data key sha1sum: ");
- PrintPubKeySha1Sum(data_key);
- printf("\n");
-
- preamble = (VbECPreambleHeader*)
- ((uint8_t *)key_block + key_block->key_block_size);
-
- rsa = PublicKeyToRSA(&key_block->data_key);
- if (!rsa) {
- printf("Error parsing data key.\n");
- errorcnt++;
- }
- /* Verify preamble */
- if (0 != VerifyECPreamble(preamble,
- key_block_size - key_block->key_block_size,
- rsa)) {
- printf("Error verifying preamble.\n");
- errorcnt++;
- free(rsa);
- continue;
- }
- printf(" Preamble:\n");
- printf(" Size: %" PRIu64 "\n",
- preamble->preamble_size);
- printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
- preamble->header_version_major,
- preamble->header_version_minor);
- printf(" Firmware version: %" PRIu64 "\n",
- preamble->firmware_version);
- printf(" Firmware body size: %" PRIu64 "\n",
- preamble->body_digest.data_size);
- printf(" Preamble flags: %" PRIu32 "\n", preamble->flags);
- printf(" Preamble name: %s\n", preamble->name);
-
- /* TODO: verify body size same as signature size */
-
- /* Verify body */
- if (preamble->flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
- printf("Preamble requests USE_RO_NORMAL; skipping verification.\n");
- } else {
- if (0 != EqualData(fv_data, fv_size,
- &preamble->body_digest, rsa)) {
- printf("Error verifying firmware body.\n");
- errorcnt++;
- }
- }
- free(rsa);
- }
-
- /* Done */
- if (0 != munmap(image, sb.st_size))
- VbExError("Can't munmap %s: %s\n", filename, strerror(errno));
-
- printf("Done\n");
- return errorcnt;
-}
-
-int main(int argc, char* argv[]) {
-
- char* filename = NULL;
- uint64_t version = 0;
- int got_version = 0;
- uint32_t preamble_flags = 0;
- char *name = NULL;
- int mode = 0;
- VbKeyBlockHeader* key_block = 0;
- VbPrivateKey* privkey = 0;
- VbPublicKey* pubkey = 0;
- uint64_t key_block_size;
- int errorcnt = 0;
- char* e;
- int i;
-
- while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
- switch (i) {
- case '?':
- /* Unhandled option */
- printf("Unknown option\n");
- errorcnt++;
- break;
-
- case OPT_MODE_SIGN:
- case OPT_MODE_VERIFY:
- mode = i;
- filename = optarg;
- break;
-
- case OPT_KEYBLOCK:
- /* Read the key block and keys */
- key_block = (VbKeyBlockHeader*)ReadFile(optarg, &key_block_size);
- if (!key_block) {
- printf("Error reading key block from %s\n", optarg);
- errorcnt++;
- }
- break;
-
- case OPT_SIGNPUBKEY:
- pubkey = PublicKeyRead(optarg);
- if (!pubkey) {
- printf("Error reading public key from %s\n", optarg);
- errorcnt++;
- }
- break;
-
- case OPT_SIGNPRIVATE:
- privkey = PrivateKeyRead(optarg);
- if (!privkey) {
- printf("Error reading private key from %s\n", optarg);
- errorcnt++;
- }
- break;
-
- case OPT_VERSION:
- version = strtoul(optarg, &e, 0);
- if (!*optarg || (e && *e)) {
- printf("Invalid --version argument: \"%s\"\n", optarg);
- errorcnt++;
- }
- got_version = 1;
- break;
-
- case OPT_FLAGS:
- preamble_flags = strtoul(optarg, &e, 0);
- if (!*optarg || (e && *e)) {
- printf("Invalid --flags argument: \"%s\"\n", optarg);
- errorcnt++;
- }
- break;
-
- case OPT_NAME:
- name = optarg;
- break;
- }
- }
-
- switch(mode) {
-
- case OPT_MODE_SIGN:
- /* Check required args */
- if (!key_block) {
- printf("The ----keyblock arg is required when signing\n");
- errorcnt++;
- }
- if (!privkey) {
- printf("The --signprivate arg is required when signing\n");
- errorcnt++;
- }
- if (!got_version) {
- printf("The --version arg is required when signing\n");
- errorcnt++;
- }
-
- if (errorcnt)
- return PrintHelp();
-
- /* Sign or die */
- SignImage(filename, key_block, key_block_size,
- privkey, version, pubkey, preamble_flags, name);
-
- /* fall through and verify what we've just done */
-
- case OPT_MODE_VERIFY:
- return Verify(filename);
-
- default:
- printf("\nMust specify a mode, either --sign or --verify.\n\n");
- return PrintHelp();
- }
-}