From 110df5cafaa55eb0e78f379be7731f8d7b3914b7 Mon Sep 17 00:00:00 2001 From: Joel Kitching Date: Thu, 29 Aug 2019 13:27:23 +0800 Subject: vboot/secdata: rename rollback_index to secdata_tpm These secure spaces are now used for more than just rollback versions and should be renamed thus. Note: Originally this rename operation was batched into the CL which rewrites the functions in rollback_index/secdata_tpm, but it made reviewing in Gerrit a pain, since it couldn't pick up on the file renames, and instead showed them as deletes/adds. Doing the rename separately helps ensure all references to rollback_index are updated, and gives us a better review experience in Gerrit. BUG=b:124141368, chromium:972956 TEST=make clean && make runtests BRANCH=none Change-Id: I51e5c731e0d7a071d384c28da56e7adce64ba943 Signed-off-by: Joel Kitching Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/1776279 Commit-Queue: Joel Kitching Tested-by: Joel Kitching Reviewed-by: Julius Werner --- Makefile | 14 +- firmware/lib/include/rollback_index.h | 173 ----------- firmware/lib/include/secdata_tpm.h | 173 +++++++++++ firmware/lib/mocked_rollback_index.c | 38 --- firmware/lib/mocked_secdata_tpm.c | 38 +++ firmware/lib/rollback_index.c | 290 ------------------ firmware/lib/secdata_tpm.c | 290 ++++++++++++++++++ firmware/lib/tpm2_lite/tlcl.c | 2 +- firmware/lib/vboot_api_kernel.c | 2 +- firmware/lib/vboot_kernel.c | 2 +- firmware/lib/vboot_ui.c | 2 +- firmware/lib/vboot_ui_common.c | 2 +- firmware/lib/vboot_ui_menu.c | 2 +- firmware/linktest/main.c | 4 +- tests/ec_sync_tests.c | 2 +- tests/rbtest.conf | 34 --- tests/rollback_index2_tests.c | 547 ---------------------------------- tests/secdata_tpm_tests.c | 547 ++++++++++++++++++++++++++++++++++ tests/vboot_api_devmode_tests.c | 2 +- tests/vboot_api_kernel2_tests.c | 2 +- tests/vboot_api_kernel4_tests.c | 2 +- tests/vboot_api_kernel5_tests.c | 2 +- tests/vboot_api_kernel_tests.c | 2 +- tests/vboot_detach_menu_tests.c | 2 +- tests/vboot_kernel_tests.c | 2 +- utility/load_kernel_test.c | 2 +- 26 files changed, 1072 insertions(+), 1106 deletions(-) delete mode 100644 firmware/lib/include/rollback_index.h create mode 100644 firmware/lib/include/secdata_tpm.h delete mode 100644 firmware/lib/mocked_rollback_index.c create mode 100644 firmware/lib/mocked_secdata_tpm.c delete mode 100644 firmware/lib/rollback_index.c create mode 100644 firmware/lib/secdata_tpm.c delete mode 100644 tests/rbtest.conf delete mode 100644 tests/rollback_index2_tests.c create mode 100644 tests/secdata_tpm_tests.c diff --git a/Makefile b/Makefile index e6c62846..fa63773b 100644 --- a/Makefile +++ b/Makefile @@ -395,11 +395,11 @@ endif # Support real TPM unless BIOS sets MOCK_TPM ifeq (${MOCK_TPM},) FWLIB_SRCS += \ - firmware/lib/rollback_index.c \ + firmware/lib/secdata_tpm.c \ ${TLCL_SRCS} else FWLIB_SRCS += \ - firmware/lib/mocked_rollback_index.c \ + firmware/lib/mocked_secdata_tpm.c \ firmware/lib/tpm_lite/mocked_tlcl.c endif @@ -691,10 +691,10 @@ TEST_NAMES = \ ifeq (${TPM2_MODE}${MOCK_TPM},) # TODO(apronin): tests for TPM2 case? -# tlcl_tests and rollback_index2_tests only work when MOCK_TPM is disabled +# secdata_tpm_tests and tlcl_tests only work when MOCK_TPM is disabled TEST_NAMES += \ - tests/tlcl_tests \ - tests/rollback_index2_tests + tests/secdata_tpm_tests \ + tests/tlcl_tests endif TEST_FUTIL_NAMES = \ @@ -1255,9 +1255,9 @@ runmisctests: test_setup ${RUNTEST} ${BUILD_RUN}/tests/ec_sync_tests ifeq (${TPM2_MODE}${MOCK_TPM},) # TODO(apronin): tests for TPM2 case? -# tlcl_tests and rollback_index2_tests only work when MOCK_TPM is disabled +# secdata_tpm_tests and tlcl_tests only work when MOCK_TPM is disabled + ${RUNTEST} ${BUILD_RUN}/tests/secdata_tpm_tests ${RUNTEST} ${BUILD_RUN}/tests/tlcl_tests - ${RUNTEST} ${BUILD_RUN}/tests/rollback_index2_tests endif ${RUNTEST} ${BUILD_RUN}/tests/utility_string_tests ${RUNTEST} ${BUILD_RUN}/tests/vboot_api_devmode_tests diff --git a/firmware/lib/include/rollback_index.h b/firmware/lib/include/rollback_index.h deleted file mode 100644 index cfa7a265..00000000 --- a/firmware/lib/include/rollback_index.h +++ /dev/null @@ -1,173 +0,0 @@ -/* 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. - * - * Functions for querying, manipulating and locking rollback indices - * stored in the TPM NVRAM. - */ - -#ifndef VBOOT_REFERENCE_ROLLBACK_INDEX_H_ -#define VBOOT_REFERENCE_ROLLBACK_INDEX_H_ - -#include "2return_codes.h" -#include "2sysincludes.h" -#include "tss_constants.h" - -/* TPM NVRAM location indices. */ -#define FIRMWARE_NV_INDEX 0x1007 -#define KERNEL_NV_INDEX 0x1008 -/* This is just an opaque space for backup purposes */ -#define BACKUP_NV_INDEX 0x1009 -#define BACKUP_NV_SIZE 16 -#define FWMP_NV_INDEX 0x100a -#define FWMP_NV_MAX_SIZE 128 -#define REC_HASH_NV_INDEX 0x100b -#define REC_HASH_NV_SIZE VB2_SHA256_DIGEST_SIZE -/* Space to hold a temporary SHA256 digest of a public key for USB autoconfig; - * see crbug.com/845589. */ -#define OOBE_USB_AUTOCONFIG_KEY_DIGEST_NV_INDEX 0x100c -#define OOBE_USB_AUTOCONFIG_KEY_DIGEST_NV_SIZE VB2_SHA256_DIGEST_SIZE - -/* Structure definitions for TPM spaces */ - -/* Kernel space - KERNEL_NV_INDEX, locked with physical presence. */ -#define ROLLBACK_SPACE_KERNEL_VERSION 2 -#define ROLLBACK_SPACE_KERNEL_UID 0x4752574C /* 'GRWL' */ - -typedef struct RollbackSpaceKernel { - /* Struct version, for backwards compatibility */ - uint8_t struct_version; - /* Unique ID to detect space redefinition */ - uint32_t uid; - /* Kernel versions */ - uint32_t kernel_versions; - /* Reserved for future expansion */ - uint8_t reserved[3]; - /* Checksum (v2 and later only) */ - uint8_t crc8; -} __attribute__((packed)) RollbackSpaceKernel; - -/* Flags for firmware space */ -/* - * Last boot was developer mode. TPM ownership is cleared when transitioning - * to/from developer mode. - */ -#define FLAG_LAST_BOOT_DEVELOPER 0x01 -/* - * Some systems may not have a dedicated dev-mode switch, but enter and leave - * dev-mode through some recovery-mode magic keypresses. For those systems, the - * dev-mode "switch" state is in this bit (0=normal, 1=dev). To make it work, a - * new flag is passed to VbInit(), indicating that the system lacks a physical - * dev-mode switch. If a physical switch is present, this bit is ignored. - */ -#define FLAG_VIRTUAL_DEV_MODE_ON 0x02 - -/* Firmware space - FIRMWARE_NV_INDEX, locked with global lock. */ -#define ROLLBACK_SPACE_FIRMWARE_VERSION 2 - -typedef struct RollbackSpaceFirmware { - /* Struct version, for backwards compatibility */ - uint8_t struct_version; - /* Flags (see FLAG_* above) */ - uint8_t flags; - /* Firmware versions */ - uint32_t fw_versions; - /* Reserved for future expansion */ - uint8_t reserved[3]; - /* Checksum (v2 and later only) */ - uint8_t crc8; -} __attribute__((packed)) RollbackSpaceFirmware; - -#define FWMP_HASH_SIZE 32 /* Enough for SHA-256 */ - -/* Firmware management parameters */ -struct RollbackSpaceFwmp { - /* CRC-8 of fields following struct_size */ - uint8_t crc; - /* Structure size in bytes */ - uint8_t struct_size; - /* Structure version */ - uint8_t struct_version; - /* Reserved; ignored by current reader */ - uint8_t reserved0; - /* Flags; see enum fwmp_flags */ - uint32_t flags; - /* Hash of developer kernel key */ - uint8_t dev_key_hash[FWMP_HASH_SIZE]; -} __attribute__((packed)); - -#define ROLLBACK_SPACE_FWMP_VERSION 0x10 /* 1.0 */ - -enum fwmp_flags { - FWMP_DEV_DISABLE_BOOT = (1 << 0), - FWMP_DEV_DISABLE_RECOVERY = (1 << 1), - FWMP_DEV_ENABLE_USB = (1 << 2), - FWMP_DEV_ENABLE_LEGACY = (1 << 3), - FWMP_DEV_ENABLE_OFFICIAL_ONLY = (1 << 4), - FWMP_DEV_USE_KEY_HASH = (1 << 5), - /* CCD = case-closed debugging on cr50; flag implemented on cr50 */ - FWMP_DEV_DISABLE_CCD_UNLOCK = (1 << 6), -}; - -/* All functions return TPM_SUCCESS (zero) if successful, non-zero if error */ - -/* - * These functions are callable from VbSelectAndLoadKernel(). They may use - * global variables. - */ - -uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf); -uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf); -uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk); -uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk); - -/** - * Read stored kernel version. - */ -uint32_t RollbackKernelRead(uint32_t *version); - -/** - * Write stored kernel version. - */ -uint32_t RollbackKernelWrite(uint32_t version); - -/** - * Lock must be called. Internally, it's ignored in recovery mode. - */ -uint32_t RollbackKernelLock(int recovery_mode); - -/** - * Read and validate firmware management parameters. - * - * Absence of a FWMP is not an error; in this case, fwmp will be cleared. - * - * Returns non-zero if error. - */ -uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp); - -/****************************************************************************/ - -/* - * The following functions are internal apis, listed here for use by unit tests - * only. - */ - -/** - * Issue a TPM_Clear and reenable/reactivate the TPM. - */ -uint32_t TPMClearAndReenable(void); - -/** - * Like TlclWrite(), but checks for write errors due to hitting the 64-write - * limit and clears the TPM when that happens. This can only happen when the - * TPM is unowned, so it is OK to clear it (and we really have no choice). - * This is not expected to happen frequently, but it could happen. - */ -uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length); - -/** - * Utility function to turn the virtual dev-mode flag on or off. 0=off, 1=on. - */ -vb2_error_t SetVirtualDevMode(int val); - -#endif /* VBOOT_REFERENCE_ROLLBACK_INDEX_H_ */ diff --git a/firmware/lib/include/secdata_tpm.h b/firmware/lib/include/secdata_tpm.h new file mode 100644 index 00000000..6e31e71c --- /dev/null +++ b/firmware/lib/include/secdata_tpm.h @@ -0,0 +1,173 @@ +/* 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. + * + * Functions for querying, manipulating and locking secure data spaces + * stored in the TPM NVRAM. + */ + +#ifndef VBOOT_REFERENCE_SECDATA_TPM_H_ +#define VBOOT_REFERENCE_SECDATA_TPM_H_ + +#include "2return_codes.h" +#include "2sysincludes.h" +#include "tss_constants.h" + +/* TPM NVRAM location indices. */ +#define FIRMWARE_NV_INDEX 0x1007 +#define KERNEL_NV_INDEX 0x1008 +/* This is just an opaque space for backup purposes */ +#define BACKUP_NV_INDEX 0x1009 +#define BACKUP_NV_SIZE 16 +#define FWMP_NV_INDEX 0x100a +#define FWMP_NV_MAX_SIZE 128 +#define REC_HASH_NV_INDEX 0x100b +#define REC_HASH_NV_SIZE VB2_SHA256_DIGEST_SIZE +/* Space to hold a temporary SHA256 digest of a public key for USB autoconfig; + * see crbug.com/845589. */ +#define OOBE_USB_AUTOCONFIG_KEY_DIGEST_NV_INDEX 0x100c +#define OOBE_USB_AUTOCONFIG_KEY_DIGEST_NV_SIZE VB2_SHA256_DIGEST_SIZE + +/* Structure definitions for TPM spaces */ + +/* Kernel space - KERNEL_NV_INDEX, locked with physical presence. */ +#define ROLLBACK_SPACE_KERNEL_VERSION 2 +#define ROLLBACK_SPACE_KERNEL_UID 0x4752574C /* 'GRWL' */ + +typedef struct RollbackSpaceKernel { + /* Struct version, for backwards compatibility */ + uint8_t struct_version; + /* Unique ID to detect space redefinition */ + uint32_t uid; + /* Kernel versions */ + uint32_t kernel_versions; + /* Reserved for future expansion */ + uint8_t reserved[3]; + /* Checksum (v2 and later only) */ + uint8_t crc8; +} __attribute__((packed)) RollbackSpaceKernel; + +/* Flags for firmware space */ +/* + * Last boot was developer mode. TPM ownership is cleared when transitioning + * to/from developer mode. + */ +#define FLAG_LAST_BOOT_DEVELOPER 0x01 +/* + * Some systems may not have a dedicated dev-mode switch, but enter and leave + * dev-mode through some recovery-mode magic keypresses. For those systems, the + * dev-mode "switch" state is in this bit (0=normal, 1=dev). To make it work, a + * new flag is passed to VbInit(), indicating that the system lacks a physical + * dev-mode switch. If a physical switch is present, this bit is ignored. + */ +#define FLAG_VIRTUAL_DEV_MODE_ON 0x02 + +/* Firmware space - FIRMWARE_NV_INDEX, locked with global lock. */ +#define ROLLBACK_SPACE_FIRMWARE_VERSION 2 + +typedef struct RollbackSpaceFirmware { + /* Struct version, for backwards compatibility */ + uint8_t struct_version; + /* Flags (see FLAG_* above) */ + uint8_t flags; + /* Firmware versions */ + uint32_t fw_versions; + /* Reserved for future expansion */ + uint8_t reserved[3]; + /* Checksum (v2 and later only) */ + uint8_t crc8; +} __attribute__((packed)) RollbackSpaceFirmware; + +#define FWMP_HASH_SIZE 32 /* Enough for SHA-256 */ + +/* Firmware management parameters */ +struct RollbackSpaceFwmp { + /* CRC-8 of fields following struct_size */ + uint8_t crc; + /* Structure size in bytes */ + uint8_t struct_size; + /* Structure version */ + uint8_t struct_version; + /* Reserved; ignored by current reader */ + uint8_t reserved0; + /* Flags; see enum fwmp_flags */ + uint32_t flags; + /* Hash of developer kernel key */ + uint8_t dev_key_hash[FWMP_HASH_SIZE]; +} __attribute__((packed)); + +#define ROLLBACK_SPACE_FWMP_VERSION 0x10 /* 1.0 */ + +enum fwmp_flags { + FWMP_DEV_DISABLE_BOOT = (1 << 0), + FWMP_DEV_DISABLE_RECOVERY = (1 << 1), + FWMP_DEV_ENABLE_USB = (1 << 2), + FWMP_DEV_ENABLE_LEGACY = (1 << 3), + FWMP_DEV_ENABLE_OFFICIAL_ONLY = (1 << 4), + FWMP_DEV_USE_KEY_HASH = (1 << 5), + /* CCD = case-closed debugging on cr50; flag implemented on cr50 */ + FWMP_DEV_DISABLE_CCD_UNLOCK = (1 << 6), +}; + +/* All functions return TPM_SUCCESS (zero) if successful, non-zero if error */ + +/* + * These functions are callable from VbSelectAndLoadKernel(). They may use + * global variables. + */ + +uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf); +uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf); +uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk); +uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk); + +/** + * Read stored kernel version. + */ +uint32_t RollbackKernelRead(uint32_t *version); + +/** + * Write stored kernel version. + */ +uint32_t RollbackKernelWrite(uint32_t version); + +/** + * Lock must be called. Internally, it's ignored in recovery mode. + */ +uint32_t RollbackKernelLock(int recovery_mode); + +/** + * Read and validate firmware management parameters. + * + * Absence of a FWMP is not an error; in this case, fwmp will be cleared. + * + * Returns non-zero if error. + */ +uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp); + +/****************************************************************************/ + +/* + * The following functions are internal apis, listed here for use by unit tests + * only. + */ + +/** + * Issue a TPM_Clear and reenable/reactivate the TPM. + */ +uint32_t TPMClearAndReenable(void); + +/** + * Like TlclWrite(), but checks for write errors due to hitting the 64-write + * limit and clears the TPM when that happens. This can only happen when the + * TPM is unowned, so it is OK to clear it (and we really have no choice). + * This is not expected to happen frequently, but it could happen. + */ +uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length); + +/** + * Utility function to turn the virtual dev-mode flag on or off. 0=off, 1=on. + */ +vb2_error_t SetVirtualDevMode(int val); + +#endif /* VBOOT_REFERENCE_SECDATA_TPM_H_ */ diff --git a/firmware/lib/mocked_rollback_index.c b/firmware/lib/mocked_rollback_index.c deleted file mode 100644 index 324660ff..00000000 --- a/firmware/lib/mocked_rollback_index.c +++ /dev/null @@ -1,38 +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. - * - * Functions for querying, manipulating and locking rollback indices - * stored in the TPM NVRAM. - */ - -#include "utility.h" -#include "rollback_index.h" -#include "tss_constants.h" - -vb2_error_t SetVirtualDevMode(int val) -{ - return VB2_SUCCESS; -} - -uint32_t RollbackKernelRead(uint32_t *version) -{ - *version = 0; - return TPM_SUCCESS; -} - -uint32_t RollbackKernelWrite(uint32_t version) -{ - return TPM_SUCCESS; -} - -uint32_t RollbackKernelLock(int recovery_mode) -{ - return TPM_SUCCESS; -} - -uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp) -{ - memset(fwmp, 0, sizeof(*fwmp)); - return TPM_SUCCESS; -} diff --git a/firmware/lib/mocked_secdata_tpm.c b/firmware/lib/mocked_secdata_tpm.c new file mode 100644 index 00000000..4271f768 --- /dev/null +++ b/firmware/lib/mocked_secdata_tpm.c @@ -0,0 +1,38 @@ +/* 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. + * + * Functions for querying, manipulating and locking secure data spaces + * stored in the TPM NVRAM. + */ + +#include "utility.h" +#include "secdata_tpm.h" +#include "tss_constants.h" + +vb2_error_t SetVirtualDevMode(int val) +{ + return VB2_SUCCESS; +} + +uint32_t RollbackKernelRead(uint32_t *version) +{ + *version = 0; + return TPM_SUCCESS; +} + +uint32_t RollbackKernelWrite(uint32_t version) +{ + return TPM_SUCCESS; +} + +uint32_t RollbackKernelLock(int recovery_mode) +{ + return TPM_SUCCESS; +} + +uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp) +{ + memset(fwmp, 0, sizeof(*fwmp)); + return TPM_SUCCESS; +} diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c deleted file mode 100644 index b273d23d..00000000 --- a/firmware/lib/rollback_index.c +++ /dev/null @@ -1,290 +0,0 @@ -/* 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. - * - * Functions for querying, manipulating and locking rollback indices - * stored in the TPM NVRAM. - */ - -#include "2sysincludes.h" -#include "2common.h" -#include "2crc8.h" -#include "rollback_index.h" -#include "tlcl.h" -#include "tss_constants.h" -#include "vboot_api.h" - -#define RETURN_ON_FAILURE(tpm_command) do { \ - uint32_t result_; \ - if ((result_ = (tpm_command)) != TPM_SUCCESS) { \ - VB2_DEBUG("Rollback: %08x returned by " #tpm_command \ - "\n", (int)result_); \ - return result_; \ - } \ - } while (0) - -#define PRINT_BYTES(title, value) do { \ - int i; \ - VB2_DEBUG(title); \ - VB2_DEBUG_RAW(":"); \ - for (i = 0; i < sizeof(*(value)); i++) \ - VB2_DEBUG_RAW(" %02x", *((uint8_t *)(value) + i)); \ - VB2_DEBUG_RAW("\n"); \ - } while (0) - -uint32_t TPMClearAndReenable(void) -{ - VB2_DEBUG("TPM: clear and re-enable\n"); - RETURN_ON_FAILURE(TlclForceClear()); - RETURN_ON_FAILURE(TlclSetEnable()); - RETURN_ON_FAILURE(TlclSetDeactivated(0)); - - 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; - } -} - -/* Functions to read and write firmware and kernel spaces. */ -uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf) -{ - uint32_t r; - - r = TlclRead(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware)); - if (TPM_SUCCESS != r) { - VB2_DEBUG("TPM: read secdata_firmware returned 0x%x\n", r); - return r; - } - PRINT_BYTES("TPM: read secdata_firmware", rsf); - - if (rsf->struct_version < ROLLBACK_SPACE_FIRMWARE_VERSION) - return TPM_E_STRUCT_VERSION; - - if (rsf->crc8 != vb2_crc8(rsf, offsetof(RollbackSpaceFirmware, crc8))) { - VB2_DEBUG("TPM: bad secdata_firmware CRC\n"); - return TPM_E_CORRUPTED_STATE; - } - - return TPM_SUCCESS; -} - -uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf) -{ - uint32_t r; - - rsf->crc8 = vb2_crc8(rsf, offsetof(RollbackSpaceFirmware, crc8)); - - PRINT_BYTES("TPM: write secdata", rsf); - r = SafeWrite(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware)); - if (TPM_SUCCESS != r) { - VB2_DEBUG("TPM: write secdata_firmware failure\n"); - return r; - } - - return TPM_SUCCESS; -} - -vb2_error_t SetVirtualDevMode(int val) -{ - RollbackSpaceFirmware rsf; - - VB2_DEBUG("Enabling developer mode...\n"); - - if (TPM_SUCCESS != ReadSpaceFirmware(&rsf)) - return VBERROR_TPM_FIRMWARE_SETUP; - - VB2_DEBUG("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 on the next boot. - */ - VB2_DEBUG("TPM: flags are now 0x%02x\n", rsf.flags); - - if (TPM_SUCCESS != WriteSpaceFirmware(&rsf)) - return VBERROR_TPM_SET_BOOT_MODE_STATE; - - VB2_DEBUG("Mode change will take effect on next reboot\n"); - - return VB2_SUCCESS; -} - -uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk) -{ -#ifndef TPM2_MODE - /* - * Before reading the kernel space, verify its permissions. If the - * kernel space has the wrong permission, we give up. This will need - * to be fixed by the recovery kernel. We will 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). - */ - uint32_t perms; - - RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms)); - - if (perms != TPM_NV_PER_PPWRITE) - return TPM_E_CORRUPTED_STATE; -#endif - - uint32_t r; - - r = TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel)); - if (TPM_SUCCESS != r) { - VB2_DEBUG("TPM: read secdata_kernel returned 0x%x\n", r); - return r; - } - PRINT_BYTES("TPM: read secdata_kernel", rsk); - - if (rsk->struct_version < ROLLBACK_SPACE_FIRMWARE_VERSION) - return TPM_E_STRUCT_VERSION; - - if (rsk->uid != ROLLBACK_SPACE_KERNEL_UID) - return TPM_E_CORRUPTED_STATE; - - if (rsk->crc8 != vb2_crc8(rsk, offsetof(RollbackSpaceKernel, crc8))) { - VB2_DEBUG("TPM: bad secdata_kernel CRC\n"); - return TPM_E_CORRUPTED_STATE; - } - - return TPM_SUCCESS; -} - -uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk) -{ - uint32_t r; - - rsk->crc8 = vb2_crc8(rsk, offsetof(RollbackSpaceKernel, crc8)); - - PRINT_BYTES("TPM: write secdata_kernel", rsk); - r = SafeWrite(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel)); - if (TPM_SUCCESS != r) { - VB2_DEBUG("TPM: write secdata_kernel failure\n"); - return r; - } - - return TPM_SUCCESS; -} - -uint32_t RollbackKernelRead(uint32_t* version) -{ - RollbackSpaceKernel rsk; - RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); - memcpy(version, &rsk.kernel_versions, sizeof(*version)); - VB2_DEBUG("TPM: RollbackKernelRead 0x%x\n", (int)*version); - return TPM_SUCCESS; -} - -uint32_t RollbackKernelWrite(uint32_t version) -{ - RollbackSpaceKernel rsk; - uint32_t old_version; - RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); - memcpy(&old_version, &rsk.kernel_versions, sizeof(old_version)); - VB2_DEBUG("TPM: RollbackKernelWrite 0x%x --> 0x%x\n", - (int)old_version, (int)version); - memcpy(&rsk.kernel_versions, &version, sizeof(version)); - return WriteSpaceKernel(&rsk); -} - -uint32_t RollbackKernelLock(int recovery_mode) -{ - static int kernel_locked = 0; - uint32_t r; - - if (recovery_mode || kernel_locked) - return TPM_SUCCESS; - - r = TlclLockPhysicalPresence(); - if (TPM_SUCCESS == r) - kernel_locked = 1; - - VB2_DEBUG("TPM: lock secdata_kernel returned 0x%x\n", r); - return r; -} - -uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp) -{ - union { - /* - * Use a union for buf and fwmp, rather than making fwmp a - * pointer to a bare uint8_t[] buffer. This ensures fwmp will - * be aligned if necesssary for the target platform. - */ - uint8_t buf[FWMP_NV_MAX_SIZE]; - struct RollbackSpaceFwmp fwmp; - } u; - uint32_t r; - - /* Clear destination in case error or FWMP not present */ - memset(fwmp, 0, sizeof(*fwmp)); - - /* Try to read entire 1.0 struct */ - r = TlclRead(FWMP_NV_INDEX, u.buf, sizeof(u.fwmp)); - if (TPM_E_BADINDEX == r) { - /* Missing space is not an error; use defaults */ - VB2_DEBUG("TPM: no FWMP space\n"); - return TPM_SUCCESS; - } else if (TPM_SUCCESS != r) { - VB2_DEBUG("TPM: read FWMP returned 0x%x\n", r); - return r; - } - - /* - * Struct must be at least big enough for 1.0, but not bigger - * than our buffer size. - */ - if (u.fwmp.struct_size < sizeof(u.fwmp) || - u.fwmp.struct_size > sizeof(u.buf)) { - VB2_DEBUG("TPM: FWMP size invalid: 0x%x\n", u.fwmp.struct_size); - return TPM_E_STRUCT_SIZE; - } - - /* - * If space is bigger than we expect, re-read so we properly - * compute the CRC. - */ - if (u.fwmp.struct_size > sizeof(u.fwmp)) { - r = TlclRead(FWMP_NV_INDEX, u.buf, u.fwmp.struct_size); - if (TPM_SUCCESS != r) { - VB2_DEBUG("TPM: re-read FWMP returned 0x%x\n", r); - return r; - } - } - - /* Verify CRC */ - if (u.fwmp.crc != vb2_crc8(u.buf + 2, u.fwmp.struct_size - 2)) { - VB2_DEBUG("TPM: bad FWMP CRC\n"); - return TPM_E_CORRUPTED_STATE; - } - - /* Verify major version is compatible */ - if ((u.fwmp.struct_version >> 4) != - (ROLLBACK_SPACE_FWMP_VERSION >> 4)) { - VB2_DEBUG("TPM: FWMP major version incompatible\n"); - return TPM_E_STRUCT_VERSION; - } - - /* - * Copy to destination. Note that if the space is bigger than - * we expect (due to a minor version change), we only copy the - * part of the FWMP that we know what to do with. - * - * If this were a 1.1+ reader and the source was a 1.0 struct, - * we would need to take care of initializing the extra fields - * added in 1.1+. But that's not an issue yet. - */ - memcpy(fwmp, &u.fwmp, sizeof(*fwmp)); - return TPM_SUCCESS; -} diff --git a/firmware/lib/secdata_tpm.c b/firmware/lib/secdata_tpm.c new file mode 100644 index 00000000..5ddb16cd --- /dev/null +++ b/firmware/lib/secdata_tpm.c @@ -0,0 +1,290 @@ +/* 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. + * + * Functions for querying, manipulating and locking secure data spaces + * stored in the TPM NVRAM. + */ + +#include "2sysincludes.h" +#include "2common.h" +#include "2crc8.h" +#include "secdata_tpm.h" +#include "tlcl.h" +#include "tss_constants.h" +#include "vboot_api.h" + +#define RETURN_ON_FAILURE(tpm_command) do { \ + uint32_t result_; \ + if ((result_ = (tpm_command)) != TPM_SUCCESS) { \ + VB2_DEBUG("TPM: 0x%x returned by " #tpm_command \ + "\n", (int)result_); \ + return result_; \ + } \ + } while (0) + +#define PRINT_BYTES(title, value) do { \ + int i; \ + VB2_DEBUG(title); \ + VB2_DEBUG_RAW(":"); \ + for (i = 0; i < sizeof(*(value)); i++) \ + VB2_DEBUG_RAW(" %02x", *((uint8_t *)(value) + i)); \ + VB2_DEBUG_RAW("\n"); \ + } while (0) + +uint32_t TPMClearAndReenable(void) +{ + VB2_DEBUG("TPM: clear and re-enable\n"); + RETURN_ON_FAILURE(TlclForceClear()); + RETURN_ON_FAILURE(TlclSetEnable()); + RETURN_ON_FAILURE(TlclSetDeactivated(0)); + + 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; + } +} + +/* Functions to read and write firmware and kernel spaces. */ +uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf) +{ + uint32_t r; + + r = TlclRead(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware)); + if (TPM_SUCCESS != r) { + VB2_DEBUG("TPM: read secdata_firmware returned 0x%x\n", r); + return r; + } + PRINT_BYTES("TPM: read secdata_firmware", rsf); + + if (rsf->struct_version < ROLLBACK_SPACE_FIRMWARE_VERSION) + return TPM_E_STRUCT_VERSION; + + if (rsf->crc8 != vb2_crc8(rsf, offsetof(RollbackSpaceFirmware, crc8))) { + VB2_DEBUG("TPM: bad secdata_firmware CRC\n"); + return TPM_E_CORRUPTED_STATE; + } + + return TPM_SUCCESS; +} + +uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf) +{ + uint32_t r; + + rsf->crc8 = vb2_crc8(rsf, offsetof(RollbackSpaceFirmware, crc8)); + + PRINT_BYTES("TPM: write secdata", rsf); + r = SafeWrite(FIRMWARE_NV_INDEX, rsf, sizeof(RollbackSpaceFirmware)); + if (TPM_SUCCESS != r) { + VB2_DEBUG("TPM: write secdata_firmware failure\n"); + return r; + } + + return TPM_SUCCESS; +} + +vb2_error_t SetVirtualDevMode(int val) +{ + RollbackSpaceFirmware rsf; + + VB2_DEBUG("Enabling developer mode...\n"); + + if (TPM_SUCCESS != ReadSpaceFirmware(&rsf)) + return VBERROR_TPM_FIRMWARE_SETUP; + + VB2_DEBUG("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 on the next boot. + */ + VB2_DEBUG("TPM: flags are now 0x%02x\n", rsf.flags); + + if (TPM_SUCCESS != WriteSpaceFirmware(&rsf)) + return VBERROR_TPM_SET_BOOT_MODE_STATE; + + VB2_DEBUG("Mode change will take effect on next reboot\n"); + + return VB2_SUCCESS; +} + +uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk) +{ +#ifndef TPM2_MODE + /* + * Before reading the kernel space, verify its permissions. If the + * kernel space has the wrong permission, we give up. This will need + * to be fixed by the recovery kernel. We will 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). + */ + uint32_t perms; + + RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms)); + + if (perms != TPM_NV_PER_PPWRITE) + return TPM_E_CORRUPTED_STATE; +#endif + + uint32_t r; + + r = TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel)); + if (TPM_SUCCESS != r) { + VB2_DEBUG("TPM: read secdata_kernel returned 0x%x\n", r); + return r; + } + PRINT_BYTES("TPM: read secdata_kernel", rsk); + + if (rsk->struct_version < ROLLBACK_SPACE_FIRMWARE_VERSION) + return TPM_E_STRUCT_VERSION; + + if (rsk->uid != ROLLBACK_SPACE_KERNEL_UID) + return TPM_E_CORRUPTED_STATE; + + if (rsk->crc8 != vb2_crc8(rsk, offsetof(RollbackSpaceKernel, crc8))) { + VB2_DEBUG("TPM: bad secdata_kernel CRC\n"); + return TPM_E_CORRUPTED_STATE; + } + + return TPM_SUCCESS; +} + +uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk) +{ + uint32_t r; + + rsk->crc8 = vb2_crc8(rsk, offsetof(RollbackSpaceKernel, crc8)); + + PRINT_BYTES("TPM: write secdata_kernel", rsk); + r = SafeWrite(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel)); + if (TPM_SUCCESS != r) { + VB2_DEBUG("TPM: write secdata_kernel failure\n"); + return r; + } + + return TPM_SUCCESS; +} + +uint32_t RollbackKernelRead(uint32_t* version) +{ + RollbackSpaceKernel rsk; + RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); + memcpy(version, &rsk.kernel_versions, sizeof(*version)); + VB2_DEBUG("TPM: RollbackKernelRead 0x%x\n", (int)*version); + return TPM_SUCCESS; +} + +uint32_t RollbackKernelWrite(uint32_t version) +{ + RollbackSpaceKernel rsk; + uint32_t old_version; + RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); + memcpy(&old_version, &rsk.kernel_versions, sizeof(old_version)); + VB2_DEBUG("TPM: RollbackKernelWrite 0x%x --> 0x%x\n", + (int)old_version, (int)version); + memcpy(&rsk.kernel_versions, &version, sizeof(version)); + return WriteSpaceKernel(&rsk); +} + +uint32_t RollbackKernelLock(int recovery_mode) +{ + static int kernel_locked = 0; + uint32_t r; + + if (recovery_mode || kernel_locked) + return TPM_SUCCESS; + + r = TlclLockPhysicalPresence(); + if (TPM_SUCCESS == r) + kernel_locked = 1; + + VB2_DEBUG("TPM: lock secdata_kernel returned 0x%x\n", r); + return r; +} + +uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp) +{ + union { + /* + * Use a union for buf and fwmp, rather than making fwmp a + * pointer to a bare uint8_t[] buffer. This ensures fwmp will + * be aligned if necesssary for the target platform. + */ + uint8_t buf[FWMP_NV_MAX_SIZE]; + struct RollbackSpaceFwmp fwmp; + } u; + uint32_t r; + + /* Clear destination in case error or FWMP not present */ + memset(fwmp, 0, sizeof(*fwmp)); + + /* Try to read entire 1.0 struct */ + r = TlclRead(FWMP_NV_INDEX, u.buf, sizeof(u.fwmp)); + if (TPM_E_BADINDEX == r) { + /* Missing space is not an error; use defaults */ + VB2_DEBUG("TPM: no FWMP space\n"); + return TPM_SUCCESS; + } else if (TPM_SUCCESS != r) { + VB2_DEBUG("TPM: read FWMP returned 0x%x\n", r); + return r; + } + + /* + * Struct must be at least big enough for 1.0, but not bigger + * than our buffer size. + */ + if (u.fwmp.struct_size < sizeof(u.fwmp) || + u.fwmp.struct_size > sizeof(u.buf)) { + VB2_DEBUG("TPM: FWMP size invalid: 0x%x\n", u.fwmp.struct_size); + return TPM_E_STRUCT_SIZE; + } + + /* + * If space is bigger than we expect, re-read so we properly + * compute the CRC. + */ + if (u.fwmp.struct_size > sizeof(u.fwmp)) { + r = TlclRead(FWMP_NV_INDEX, u.buf, u.fwmp.struct_size); + if (TPM_SUCCESS != r) { + VB2_DEBUG("TPM: re-read FWMP returned 0x%x\n", r); + return r; + } + } + + /* Verify CRC */ + if (u.fwmp.crc != vb2_crc8(u.buf + 2, u.fwmp.struct_size - 2)) { + VB2_DEBUG("TPM: bad FWMP CRC\n"); + return TPM_E_CORRUPTED_STATE; + } + + /* Verify major version is compatible */ + if ((u.fwmp.struct_version >> 4) != + (ROLLBACK_SPACE_FWMP_VERSION >> 4)) { + VB2_DEBUG("TPM: FWMP major version incompatible\n"); + return TPM_E_STRUCT_VERSION; + } + + /* + * Copy to destination. Note that if the space is bigger than + * we expect (due to a minor version change), we only copy the + * part of the FWMP that we know what to do with. + * + * If this were a 1.1+ reader and the source was a 1.0 struct, + * we would need to take care of initializing the extra fields + * added in 1.1+. But that's not an issue yet. + */ + memcpy(fwmp, &u.fwmp, sizeof(*fwmp)); + return TPM_SUCCESS; +} diff --git a/firmware/lib/tpm2_lite/tlcl.c b/firmware/lib/tpm2_lite/tlcl.c index 02d1a91b..37034c99 100644 --- a/firmware/lib/tpm2_lite/tlcl.c +++ b/firmware/lib/tpm2_lite/tlcl.c @@ -7,7 +7,7 @@ */ #include "2common.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "2sysincludes.h" #include "tlcl.h" #include "tpm2_marshaling.h" diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index dbaf93f3..eb05109b 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -14,7 +14,7 @@ #include "2sysincludes.h" #include "ec_sync.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "utility.h" #include "vb2_common.h" #include "vboot_api.h" diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c index e2ca910f..e2075e22 100644 --- a/firmware/lib/vboot_kernel.c +++ b/firmware/lib/vboot_kernel.c @@ -17,7 +17,7 @@ #include "cgptlib_internal.h" #include "gpt_misc.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "utility.h" #include "vb2_common.h" #include "vboot_api.h" diff --git a/firmware/lib/vboot_ui.c b/firmware/lib/vboot_ui.c index 22035952..35dafe97 100644 --- a/firmware/lib/vboot_ui.c +++ b/firmware/lib/vboot_ui.c @@ -13,7 +13,7 @@ #include "2secdata.h" #include "ec_sync.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "tlcl.h" #include "utility.h" #include "vb2_common.h" diff --git a/firmware/lib/vboot_ui_common.c b/firmware/lib/vboot_ui_common.c index 4255deb0..376e1a67 100644 --- a/firmware/lib/vboot_ui_common.c +++ b/firmware/lib/vboot_ui_common.c @@ -6,7 +6,7 @@ */ #include "2common.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "2sysincludes.h" #include "vboot_api.h" #include "vboot_kernel.h" diff --git a/firmware/lib/vboot_ui_menu.c b/firmware/lib/vboot_ui_menu.c index 24b7de8f..58349ca3 100644 --- a/firmware/lib/vboot_ui_menu.c +++ b/firmware/lib/vboot_ui_menu.c @@ -13,7 +13,7 @@ #include "2sysincludes.h" #include "ec_sync.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "utility.h" #include "vb2_common.h" #include "vboot_api.h" diff --git a/firmware/linktest/main.c b/firmware/linktest/main.c index 75dda291..bc120c3d 100644 --- a/firmware/linktest/main.c +++ b/firmware/linktest/main.c @@ -6,7 +6,7 @@ #include "2sysincludes.h" #include "cgptlib.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "tlcl.h" #include "vboot_common.h" #include "vboot_kernel.h" @@ -22,7 +22,7 @@ int main(void) /* load_kernel_fw.h */ LoadKernel(0, 0); - /* rollback_index.h */ + /* secdata_tpm.h */ RollbackKernelRead(0); RollbackKernelWrite(0); RollbackKernelLock(0); diff --git a/tests/ec_sync_tests.c b/tests/ec_sync_tests.c index 9249b11a..9f4dad89 100644 --- a/tests/ec_sync_tests.c +++ b/tests/ec_sync_tests.c @@ -16,7 +16,7 @@ #include "ec_sync.h" #include "host_common.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "test_common.h" #include "vboot_audio.h" #include "vboot_common.h" diff --git a/tests/rbtest.conf b/tests/rbtest.conf deleted file mode 100644 index 6fd30bab..00000000 --- a/tests/rbtest.conf +++ /dev/null @@ -1,34 +0,0 @@ -# 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. - -# Rollback code exhaustive test. -# -# INSTRUCTIONS. Put this file in /etc/init. Move /etc/init/tcsd.conf to -# /etc/init/tcsd.confxxx to disable it. Then boot with the device connected by -# wired ethernet. The test will start and reboot the host after every cycle. -# Unplug the ethernet cable to stop testing. If left alone, the test will stop -# at the first failure or when all the states have been tested. -# -# Reminder: rollback_index_test only works with TPM-agnostic firmware. - -# Connecting to tcsd requires that "localhost" be reachable, so we wait for -# shill to start, but that's not enough, and in the while loop below we also -# wait for pinging to localhost to succeed. - -start on started shill - -script - cable="" - while [ "$cable" != "yes" ]; do - cable=$(/usr/sbin/ethtool eth0 | grep Link | cut -f 3 -d ' ') - logger "rbtest: cable is $cable" - ping -c 1 localhost || cable="" - sleep 2 - done - # ideally we would like to issue a "stop tcsd", but this doesn't work - # (upstart race?) so we must manually disable tcsd.conf - ### stop tcsd - logger "starting rbtest" - /usr/bin/rollback_index_test > /tmp/rbtest.out 2>&1 -end script diff --git a/tests/rollback_index2_tests.c b/tests/rollback_index2_tests.c deleted file mode 100644 index b8ebc80e..00000000 --- a/tests/rollback_index2_tests.c +++ /dev/null @@ -1,547 +0,0 @@ -/* 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 rollback_index functions - */ - -#include -#include -#include -#include - -#include "2crc8.h" -#include "rollback_index.h" -#include "test_common.h" -#include "tlcl.h" - -_Static_assert(ROLLBACK_SPACE_FIRMWARE_VERSION > 0, - "ROLLBACK_SPACE_FIRMWARE_VERSION must be greater than 0"); - -_Static_assert(ROLLBACK_SPACE_KERNEL_VERSION > 0, - "ROLLBACK_SPACE_KERNEL_VERSION must be greater than 0"); - -/* - * 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 - * call sequences; 16KB should be plenty since none of the sequences - * below is more than a few hundred bytes. We could be more clever - * and use snprintf() with length checking below, at the expense of - * 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. - */ -static char mock_calls[16384]; -static char *mock_cnext = mock_calls; - -/* - * 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. - */ -static int mock_count = 0; -static int fail_at_count = 0; -static uint32_t fail_with_error = TPM_SUCCESS; - -/* Params / backing store for mocked Tlcl functions. */ -static TPM_PERMANENT_FLAGS mock_pflags; -static RollbackSpaceFirmware mock_rsf; -static RollbackSpaceKernel mock_rsk; - -static union { - struct RollbackSpaceFwmp fwmp; - uint8_t buf[FWMP_NV_MAX_SIZE]; -} mock_fwmp; - -static uint32_t mock_permissions; - -/* Recalculate CRC of FWMP data */ -static void RecalcFwmpCrc(void) -{ - mock_fwmp.fwmp.crc = vb2_crc8(mock_fwmp.buf + 2, - mock_fwmp.fwmp.struct_size - 2); -} - -/* 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; - - memset(&mock_pflags, 0, sizeof(mock_pflags)); - - memset(&mock_rsf, 0, sizeof(mock_rsf)); - mock_rsf.struct_version = ROLLBACK_SPACE_FIRMWARE_VERSION; - mock_rsf.crc8 = vb2_crc8(&mock_rsf, - offsetof(RollbackSpaceFirmware, crc8)); - - memset(&mock_rsk, 0, sizeof(mock_rsk)); - mock_rsk.uid = ROLLBACK_SPACE_KERNEL_UID; - mock_rsk.struct_version = ROLLBACK_SPACE_KERNEL_VERSION; - mock_rsk.kernel_versions = 0x87654321; - mock_rsk.crc8 = vb2_crc8(&mock_rsk, - offsetof(RollbackSpaceKernel, crc8)); - - mock_permissions = TPM_NV_PER_PPWRITE; - - memset(mock_fwmp.buf, 0, sizeof(mock_fwmp.buf)); - mock_fwmp.fwmp.struct_size = sizeof(mock_fwmp.fwmp); - mock_fwmp.fwmp.struct_version = ROLLBACK_SPACE_FWMP_VERSION; - mock_fwmp.fwmp.flags = 0x1234; - /* Put some data in the hash */ - mock_fwmp.fwmp.dev_key_hash[0] = 0xaa; - mock_fwmp.fwmp.dev_key_hash[FWMP_HASH_SIZE - 1] = 0xbb; - RecalcFwmpCrc(); -} - -/****************************************************************************/ -/* 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 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 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 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); - } else if (KERNEL_NV_INDEX == index) { - TEST_EQ(length, sizeof(mock_rsk), "TlclRead rsk size"); - memcpy(data, &mock_rsk, length); - } else if (FWMP_NV_INDEX == index) { - memset(data, 0, length); - if (length > sizeof(mock_fwmp)) - length = sizeof(mock_fwmp); - memcpy(data, &mock_fwmp, 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); - } else if (KERNEL_NV_INDEX == index) { - TEST_EQ(length, sizeof(mock_rsk), "TlclWrite rsk size"); - memcpy(&mock_rsk, data, 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 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 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 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 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 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; -} - -/****************************************************************************/ -/* Tests for CRC errors */ - -static void FirmwareSpaceTest(void) -{ - RollbackSpaceFirmware rsf; - - /* Old version, valid CRC */ - ResetMocks(0, 0); - mock_rsf.struct_version -= 1; - mock_rsf.crc8 = vb2_crc8(&mock_rsf, - offsetof(RollbackSpaceFirmware, crc8)); - TEST_EQ(ReadSpaceFirmware(&rsf), TPM_E_STRUCT_VERSION, - "ReadSpaceFirmware(), old version"); - TEST_STR_EQ(mock_calls, - "TlclRead(0x1007, 10)\n", - "tlcl calls"); - - /* Current version, bad CRC */ - ResetMocks(0, 0); - mock_rsf.crc8 = 0; - TEST_EQ(ReadSpaceFirmware(&rsf), TPM_E_CORRUPTED_STATE, - "ReadSpaceFirmware(), bad CRC"); - TEST_STR_EQ(mock_calls, - "TlclRead(0x1007, 10)\n", - "tlcl calls"); - - /* Current version, valid CRC */ - ResetMocks(0, 0); - TEST_EQ(ReadSpaceFirmware(&rsf), 0, - "ReadSpaceFirmware(), successful read"); - TEST_STR_EQ(mock_calls, - "TlclRead(0x1007, 10)\n", - "tlcl calls"); -} - -static void KernelSpaceTest(void) -{ - RollbackSpaceKernel rsk; - - /* Current version, bad perms, valid CRC, valid UID */ - ResetMocks(0, 0); - mock_permissions = 0; - TEST_EQ(ReadSpaceKernel(&rsk), TPM_E_CORRUPTED_STATE, - "ReadSpaceKernel(), bad permissions"); - TEST_STR_EQ(mock_calls, - "TlclGetPermissions(0x1008)\n", - "tlcl calls"); - - /* Old version, good perms, valid CRC, valid UID */ - ResetMocks(0, 0); - mock_rsk.struct_version -= 1; - mock_rsk.crc8 = vb2_crc8(&mock_rsk, - offsetof(RollbackSpaceKernel, crc8)); - TEST_EQ(ReadSpaceKernel(&rsk), TPM_E_STRUCT_VERSION, - "ReadSpaceKernel(), old version"); - TEST_STR_EQ(mock_calls, - "TlclGetPermissions(0x1008)\n" - "TlclRead(0x1008, 13)\n", - "tlcl calls"); - - /* Current version, good perms, bad CRC, valid UID */ - ResetMocks(0, 0); - mock_rsk.crc8 = 0; - TEST_EQ(ReadSpaceKernel(&rsk), TPM_E_CORRUPTED_STATE, - "ReadSpaceKernel(), bad CRC"); - TEST_STR_EQ(mock_calls, - "TlclGetPermissions(0x1008)\n" - "TlclRead(0x1008, 13)\n", - "tlcl calls"); - - /* Current version, good perms, valid CRC, bad UID */ - ResetMocks(0, 0); - mock_rsk.uid = 0; - mock_rsk.crc8 = vb2_crc8(&mock_rsk, - offsetof(RollbackSpaceKernel, crc8)); - TEST_EQ(ReadSpaceKernel(&rsk), TPM_E_CORRUPTED_STATE, - "ReadSpaceKernel(), bad UID"); - TEST_STR_EQ(mock_calls, - "TlclGetPermissions(0x1008)\n" - "TlclRead(0x1008, 13)\n", - "tlcl calls"); - - /* Current version, good perms, valid CRC, valid UID */ - ResetMocks(0, 0); - TEST_EQ(ReadSpaceKernel(&rsk), 0, - "ReadSpaceKernel(), successful read"); - TEST_STR_EQ(mock_calls, - "TlclGetPermissions(0x1008)\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"); -} - -/****************************************************************************/ -/* Tests for RollbackKernel() calls */ - -static void RollbackKernelTest(void) -{ - uint32_t version = 0; - - /* Normal read */ - ResetMocks(0, 0); - TEST_EQ(RollbackKernelRead(&version), 0, "RollbackKernelRead()"); - TEST_STR_EQ(mock_calls, - "TlclGetPermissions(0x1008)\n" - "TlclRead(0x1008, 13)\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"); - - /* Wrong permission or UID will return error */ - ResetMocks(0, 0); - mock_rsk.uid = 0; - mock_rsk.crc8 = vb2_crc8(&mock_rsk, - offsetof(RollbackSpaceKernel, crc8)); - TEST_EQ(RollbackKernelRead(&version), TPM_E_CORRUPTED_STATE, - "RollbackKernelRead() bad uid"); - - ResetMocks(0, 0); - mock_permissions = 0; - 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, - "TlclGetPermissions(0x1008)\n" - "TlclRead(0x1008, 13)\n" - "TlclWrite(0x1008, 13)\n", - "tlcl calls"); - - ResetMocks(1, TPM_E_IOERROR); - TEST_EQ(RollbackKernelWrite(123), TPM_E_IOERROR, - "RollbackKernelWrite() error"); - - /* Test lock (recovery off) */ - ResetMocks(1, TPM_E_IOERROR); - TEST_EQ(RollbackKernelLock(0), TPM_E_IOERROR, - "RollbackKernelLock() error"); - - /* Test lock with recovery on; shouldn't lock PP */ - ResetMocks(0, 0); - TEST_EQ(RollbackKernelLock(1), 0, "RollbackKernelLock() in recovery"); - TEST_STR_EQ(mock_calls, "", "no tlcl calls"); - - ResetMocks(0, 0); - TEST_EQ(RollbackKernelLock(0), 0, "RollbackKernelLock()"); - TEST_STR_EQ(mock_calls, - "TlclLockPhysicalPresence()\n", - "tlcl calls"); -} - -/****************************************************************************/ -/* Tests for RollbackFwmpRead() calls */ - -static void RollbackFwmpTest(void) -{ - struct RollbackSpaceFwmp fwmp; - struct RollbackSpaceFwmp fwmp_zero = {0}; - - /* Normal read */ - ResetMocks(0, 0); - TEST_EQ(RollbackFwmpRead(&fwmp), 0, "RollbackFwmpRead()"); - TEST_STR_EQ(mock_calls, - "TlclRead(0x100a, 40)\n", - " tlcl calls"); - TEST_EQ(0, memcmp(&fwmp, &mock_fwmp, sizeof(fwmp)), " data"); - - /* Read error */ - ResetMocks(1, TPM_E_IOERROR); - TEST_EQ(RollbackFwmpRead(&fwmp), TPM_E_IOERROR, - "RollbackFwmpRead() error"); - TEST_STR_EQ(mock_calls, - "TlclRead(0x100a, 40)\n", - " tlcl calls"); - TEST_EQ(0, memcmp(&fwmp, &fwmp_zero, sizeof(fwmp)), " data clear"); - - /* Not present isn't an error; just returns empty data */ - ResetMocks(1, TPM_E_BADINDEX); - TEST_EQ(RollbackFwmpRead(&fwmp), 0, "RollbackFwmpRead() not present"); - TEST_STR_EQ(mock_calls, - "TlclRead(0x100a, 40)\n", - " tlcl calls"); - TEST_EQ(0, memcmp(&fwmp, &fwmp_zero, sizeof(fwmp)), " data clear"); - - /* Struct size too small */ - ResetMocks(0, 0); - mock_fwmp.fwmp.struct_size--; - TEST_EQ(RollbackFwmpRead(&fwmp), TPM_E_STRUCT_SIZE, - "RollbackFwmpRead() too small"); - - /* Struct size too large with good CRC */ - ResetMocks(0, 0); - mock_fwmp.fwmp.struct_size += 4; - RecalcFwmpCrc(); - TEST_EQ(RollbackFwmpRead(&fwmp), 0, "RollbackFwmpRead() bigger"); - TEST_STR_EQ(mock_calls, - "TlclRead(0x100a, 40)\n" - "TlclRead(0x100a, 44)\n", - " tlcl calls"); - TEST_EQ(0, memcmp(&fwmp, &mock_fwmp, sizeof(fwmp)), " data"); - - /* Bad CRC causes retry, then eventual failure */ - ResetMocks(0, 0); - mock_fwmp.fwmp.crc++; - TEST_EQ(RollbackFwmpRead(&fwmp), TPM_E_CORRUPTED_STATE, - "RollbackFwmpRead() crc"); - TEST_STR_EQ(mock_calls, - "TlclRead(0x100a, 40)\n", - " tlcl calls"); - - /* Struct size too large with bad CRC */ - ResetMocks(0, 0); - mock_fwmp.fwmp.struct_size += 4; - RecalcFwmpCrc(); - mock_fwmp.fwmp.crc++; - TEST_EQ(RollbackFwmpRead(&fwmp), TPM_E_CORRUPTED_STATE, - "RollbackFwmpRead() bigger crc"); - TEST_STR_EQ(mock_calls, - "TlclRead(0x100a, 40)\n" - "TlclRead(0x100a, 44)\n", - " tlcl calls"); - TEST_EQ(0, memcmp(&fwmp, &fwmp_zero, sizeof(fwmp)), " data"); - - /* Minor version difference ok */ - ResetMocks(0, 0); - mock_fwmp.fwmp.struct_version++; - RecalcFwmpCrc(); - TEST_EQ(RollbackFwmpRead(&fwmp), 0, "RollbackFwmpRead() minor version"); - TEST_EQ(0, memcmp(&fwmp, &mock_fwmp, sizeof(fwmp)), " data"); - - /* Major version difference not ok */ - ResetMocks(0, 0); - mock_fwmp.fwmp.struct_version += 0x10; - RecalcFwmpCrc(); - TEST_EQ(RollbackFwmpRead(&fwmp), TPM_E_STRUCT_VERSION, - "RollbackFwmpRead() major version"); -} - -int main(int argc, char* argv[]) -{ - FirmwareSpaceTest(); - KernelSpaceTest(); - MiscTest(); - RollbackKernelTest(); - RollbackFwmpTest(); - - return gTestSuccess ? 0 : 255; -} diff --git a/tests/secdata_tpm_tests.c b/tests/secdata_tpm_tests.c new file mode 100644 index 00000000..cac51338 --- /dev/null +++ b/tests/secdata_tpm_tests.c @@ -0,0 +1,547 @@ +/* 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 secdata_tpm functions + */ + +#include +#include +#include +#include + +#include "2crc8.h" +#include "secdata_tpm.h" +#include "test_common.h" +#include "tlcl.h" + +_Static_assert(ROLLBACK_SPACE_FIRMWARE_VERSION > 0, + "ROLLBACK_SPACE_FIRMWARE_VERSION must be greater than 0"); + +_Static_assert(ROLLBACK_SPACE_KERNEL_VERSION > 0, + "ROLLBACK_SPACE_KERNEL_VERSION must be greater than 0"); + +/* + * 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 + * call sequences; 16KB should be plenty since none of the sequences + * below is more than a few hundred bytes. We could be more clever + * and use snprintf() with length checking below, at the expense of + * 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. + */ +static char mock_calls[16384]; +static char *mock_cnext = mock_calls; + +/* + * 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. + */ +static int mock_count = 0; +static int fail_at_count = 0; +static uint32_t fail_with_error = TPM_SUCCESS; + +/* Params / backing store for mocked Tlcl functions. */ +static TPM_PERMANENT_FLAGS mock_pflags; +static RollbackSpaceFirmware mock_rsf; +static RollbackSpaceKernel mock_rsk; + +static union { + struct RollbackSpaceFwmp fwmp; + uint8_t buf[FWMP_NV_MAX_SIZE]; +} mock_fwmp; + +static uint32_t mock_permissions; + +/* Recalculate CRC of FWMP data */ +static void RecalcFwmpCrc(void) +{ + mock_fwmp.fwmp.crc = vb2_crc8(mock_fwmp.buf + 2, + mock_fwmp.fwmp.struct_size - 2); +} + +/* 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; + + memset(&mock_pflags, 0, sizeof(mock_pflags)); + + memset(&mock_rsf, 0, sizeof(mock_rsf)); + mock_rsf.struct_version = ROLLBACK_SPACE_FIRMWARE_VERSION; + mock_rsf.crc8 = vb2_crc8(&mock_rsf, + offsetof(RollbackSpaceFirmware, crc8)); + + memset(&mock_rsk, 0, sizeof(mock_rsk)); + mock_rsk.uid = ROLLBACK_SPACE_KERNEL_UID; + mock_rsk.struct_version = ROLLBACK_SPACE_KERNEL_VERSION; + mock_rsk.kernel_versions = 0x87654321; + mock_rsk.crc8 = vb2_crc8(&mock_rsk, + offsetof(RollbackSpaceKernel, crc8)); + + mock_permissions = TPM_NV_PER_PPWRITE; + + memset(mock_fwmp.buf, 0, sizeof(mock_fwmp.buf)); + mock_fwmp.fwmp.struct_size = sizeof(mock_fwmp.fwmp); + mock_fwmp.fwmp.struct_version = ROLLBACK_SPACE_FWMP_VERSION; + mock_fwmp.fwmp.flags = 0x1234; + /* Put some data in the hash */ + mock_fwmp.fwmp.dev_key_hash[0] = 0xaa; + mock_fwmp.fwmp.dev_key_hash[FWMP_HASH_SIZE - 1] = 0xbb; + RecalcFwmpCrc(); +} + +/****************************************************************************/ +/* 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 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 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 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); + } else if (KERNEL_NV_INDEX == index) { + TEST_EQ(length, sizeof(mock_rsk), "TlclRead rsk size"); + memcpy(data, &mock_rsk, length); + } else if (FWMP_NV_INDEX == index) { + memset(data, 0, length); + if (length > sizeof(mock_fwmp)) + length = sizeof(mock_fwmp); + memcpy(data, &mock_fwmp, 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); + } else if (KERNEL_NV_INDEX == index) { + TEST_EQ(length, sizeof(mock_rsk), "TlclWrite rsk size"); + memcpy(&mock_rsk, data, 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 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 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 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 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 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; +} + +/****************************************************************************/ +/* Tests for CRC errors */ + +static void FirmwareSpaceTest(void) +{ + RollbackSpaceFirmware rsf; + + /* Old version, valid CRC */ + ResetMocks(0, 0); + mock_rsf.struct_version -= 1; + mock_rsf.crc8 = vb2_crc8(&mock_rsf, + offsetof(RollbackSpaceFirmware, crc8)); + TEST_EQ(ReadSpaceFirmware(&rsf), TPM_E_STRUCT_VERSION, + "ReadSpaceFirmware(), old version"); + TEST_STR_EQ(mock_calls, + "TlclRead(0x1007, 10)\n", + "tlcl calls"); + + /* Current version, bad CRC */ + ResetMocks(0, 0); + mock_rsf.crc8 = 0; + TEST_EQ(ReadSpaceFirmware(&rsf), TPM_E_CORRUPTED_STATE, + "ReadSpaceFirmware(), bad CRC"); + TEST_STR_EQ(mock_calls, + "TlclRead(0x1007, 10)\n", + "tlcl calls"); + + /* Current version, valid CRC */ + ResetMocks(0, 0); + TEST_EQ(ReadSpaceFirmware(&rsf), 0, + "ReadSpaceFirmware(), successful read"); + TEST_STR_EQ(mock_calls, + "TlclRead(0x1007, 10)\n", + "tlcl calls"); +} + +static void KernelSpaceTest(void) +{ + RollbackSpaceKernel rsk; + + /* Current version, bad perms, valid CRC, valid UID */ + ResetMocks(0, 0); + mock_permissions = 0; + TEST_EQ(ReadSpaceKernel(&rsk), TPM_E_CORRUPTED_STATE, + "ReadSpaceKernel(), bad permissions"); + TEST_STR_EQ(mock_calls, + "TlclGetPermissions(0x1008)\n", + "tlcl calls"); + + /* Old version, good perms, valid CRC, valid UID */ + ResetMocks(0, 0); + mock_rsk.struct_version -= 1; + mock_rsk.crc8 = vb2_crc8(&mock_rsk, + offsetof(RollbackSpaceKernel, crc8)); + TEST_EQ(ReadSpaceKernel(&rsk), TPM_E_STRUCT_VERSION, + "ReadSpaceKernel(), old version"); + TEST_STR_EQ(mock_calls, + "TlclGetPermissions(0x1008)\n" + "TlclRead(0x1008, 13)\n", + "tlcl calls"); + + /* Current version, good perms, bad CRC, valid UID */ + ResetMocks(0, 0); + mock_rsk.crc8 = 0; + TEST_EQ(ReadSpaceKernel(&rsk), TPM_E_CORRUPTED_STATE, + "ReadSpaceKernel(), bad CRC"); + TEST_STR_EQ(mock_calls, + "TlclGetPermissions(0x1008)\n" + "TlclRead(0x1008, 13)\n", + "tlcl calls"); + + /* Current version, good perms, valid CRC, bad UID */ + ResetMocks(0, 0); + mock_rsk.uid = 0; + mock_rsk.crc8 = vb2_crc8(&mock_rsk, + offsetof(RollbackSpaceKernel, crc8)); + TEST_EQ(ReadSpaceKernel(&rsk), TPM_E_CORRUPTED_STATE, + "ReadSpaceKernel(), bad UID"); + TEST_STR_EQ(mock_calls, + "TlclGetPermissions(0x1008)\n" + "TlclRead(0x1008, 13)\n", + "tlcl calls"); + + /* Current version, good perms, valid CRC, valid UID */ + ResetMocks(0, 0); + TEST_EQ(ReadSpaceKernel(&rsk), 0, + "ReadSpaceKernel(), successful read"); + TEST_STR_EQ(mock_calls, + "TlclGetPermissions(0x1008)\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"); +} + +/****************************************************************************/ +/* Tests for RollbackKernel() calls */ + +static void RollbackKernelTest(void) +{ + uint32_t version = 0; + + /* Normal read */ + ResetMocks(0, 0); + TEST_EQ(RollbackKernelRead(&version), 0, "RollbackKernelRead()"); + TEST_STR_EQ(mock_calls, + "TlclGetPermissions(0x1008)\n" + "TlclRead(0x1008, 13)\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"); + + /* Wrong permission or UID will return error */ + ResetMocks(0, 0); + mock_rsk.uid = 0; + mock_rsk.crc8 = vb2_crc8(&mock_rsk, + offsetof(RollbackSpaceKernel, crc8)); + TEST_EQ(RollbackKernelRead(&version), TPM_E_CORRUPTED_STATE, + "RollbackKernelRead() bad uid"); + + ResetMocks(0, 0); + mock_permissions = 0; + 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, + "TlclGetPermissions(0x1008)\n" + "TlclRead(0x1008, 13)\n" + "TlclWrite(0x1008, 13)\n", + "tlcl calls"); + + ResetMocks(1, TPM_E_IOERROR); + TEST_EQ(RollbackKernelWrite(123), TPM_E_IOERROR, + "RollbackKernelWrite() error"); + + /* Test lock (recovery off) */ + ResetMocks(1, TPM_E_IOERROR); + TEST_EQ(RollbackKernelLock(0), TPM_E_IOERROR, + "RollbackKernelLock() error"); + + /* Test lock with recovery on; shouldn't lock PP */ + ResetMocks(0, 0); + TEST_EQ(RollbackKernelLock(1), 0, "RollbackKernelLock() in recovery"); + TEST_STR_EQ(mock_calls, "", "no tlcl calls"); + + ResetMocks(0, 0); + TEST_EQ(RollbackKernelLock(0), 0, "RollbackKernelLock()"); + TEST_STR_EQ(mock_calls, + "TlclLockPhysicalPresence()\n", + "tlcl calls"); +} + +/****************************************************************************/ +/* Tests for RollbackFwmpRead() calls */ + +static void RollbackFwmpTest(void) +{ + struct RollbackSpaceFwmp fwmp; + struct RollbackSpaceFwmp fwmp_zero = {0}; + + /* Normal read */ + ResetMocks(0, 0); + TEST_EQ(RollbackFwmpRead(&fwmp), 0, "RollbackFwmpRead()"); + TEST_STR_EQ(mock_calls, + "TlclRead(0x100a, 40)\n", + " tlcl calls"); + TEST_EQ(0, memcmp(&fwmp, &mock_fwmp, sizeof(fwmp)), " data"); + + /* Read error */ + ResetMocks(1, TPM_E_IOERROR); + TEST_EQ(RollbackFwmpRead(&fwmp), TPM_E_IOERROR, + "RollbackFwmpRead() error"); + TEST_STR_EQ(mock_calls, + "TlclRead(0x100a, 40)\n", + " tlcl calls"); + TEST_EQ(0, memcmp(&fwmp, &fwmp_zero, sizeof(fwmp)), " data clear"); + + /* Not present isn't an error; just returns empty data */ + ResetMocks(1, TPM_E_BADINDEX); + TEST_EQ(RollbackFwmpRead(&fwmp), 0, "RollbackFwmpRead() not present"); + TEST_STR_EQ(mock_calls, + "TlclRead(0x100a, 40)\n", + " tlcl calls"); + TEST_EQ(0, memcmp(&fwmp, &fwmp_zero, sizeof(fwmp)), " data clear"); + + /* Struct size too small */ + ResetMocks(0, 0); + mock_fwmp.fwmp.struct_size--; + TEST_EQ(RollbackFwmpRead(&fwmp), TPM_E_STRUCT_SIZE, + "RollbackFwmpRead() too small"); + + /* Struct size too large with good CRC */ + ResetMocks(0, 0); + mock_fwmp.fwmp.struct_size += 4; + RecalcFwmpCrc(); + TEST_EQ(RollbackFwmpRead(&fwmp), 0, "RollbackFwmpRead() bigger"); + TEST_STR_EQ(mock_calls, + "TlclRead(0x100a, 40)\n" + "TlclRead(0x100a, 44)\n", + " tlcl calls"); + TEST_EQ(0, memcmp(&fwmp, &mock_fwmp, sizeof(fwmp)), " data"); + + /* Bad CRC causes retry, then eventual failure */ + ResetMocks(0, 0); + mock_fwmp.fwmp.crc++; + TEST_EQ(RollbackFwmpRead(&fwmp), TPM_E_CORRUPTED_STATE, + "RollbackFwmpRead() crc"); + TEST_STR_EQ(mock_calls, + "TlclRead(0x100a, 40)\n", + " tlcl calls"); + + /* Struct size too large with bad CRC */ + ResetMocks(0, 0); + mock_fwmp.fwmp.struct_size += 4; + RecalcFwmpCrc(); + mock_fwmp.fwmp.crc++; + TEST_EQ(RollbackFwmpRead(&fwmp), TPM_E_CORRUPTED_STATE, + "RollbackFwmpRead() bigger crc"); + TEST_STR_EQ(mock_calls, + "TlclRead(0x100a, 40)\n" + "TlclRead(0x100a, 44)\n", + " tlcl calls"); + TEST_EQ(0, memcmp(&fwmp, &fwmp_zero, sizeof(fwmp)), " data"); + + /* Minor version difference ok */ + ResetMocks(0, 0); + mock_fwmp.fwmp.struct_version++; + RecalcFwmpCrc(); + TEST_EQ(RollbackFwmpRead(&fwmp), 0, "RollbackFwmpRead() minor version"); + TEST_EQ(0, memcmp(&fwmp, &mock_fwmp, sizeof(fwmp)), " data"); + + /* Major version difference not ok */ + ResetMocks(0, 0); + mock_fwmp.fwmp.struct_version += 0x10; + RecalcFwmpCrc(); + TEST_EQ(RollbackFwmpRead(&fwmp), TPM_E_STRUCT_VERSION, + "RollbackFwmpRead() major version"); +} + +int main(int argc, char* argv[]) +{ + FirmwareSpaceTest(); + KernelSpaceTest(); + MiscTest(); + RollbackKernelTest(); + RollbackFwmpTest(); + + return gTestSuccess ? 0 : 255; +} diff --git a/tests/vboot_api_devmode_tests.c b/tests/vboot_api_devmode_tests.c index 011a3616..dc9da890 100644 --- a/tests/vboot_api_devmode_tests.c +++ b/tests/vboot_api_devmode_tests.c @@ -18,7 +18,7 @@ #include "crc32.h" #include "host_common.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "test_common.h" #include "vboot_common.h" #include "vboot_display.h" diff --git a/tests/vboot_api_kernel2_tests.c b/tests/vboot_api_kernel2_tests.c index 43cc399f..988d3e4b 100644 --- a/tests/vboot_api_kernel2_tests.c +++ b/tests/vboot_api_kernel2_tests.c @@ -15,7 +15,7 @@ #include "2secdata.h" #include "host_common.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "test_common.h" #include "vboot_audio.h" #include "vboot_common.h" diff --git a/tests/vboot_api_kernel4_tests.c b/tests/vboot_api_kernel4_tests.c index 1304aaf0..03194b56 100644 --- a/tests/vboot_api_kernel4_tests.c +++ b/tests/vboot_api_kernel4_tests.c @@ -17,7 +17,7 @@ #include "ec_sync.h" #include "host_common.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "test_common.h" #include "vboot_audio.h" #include "vboot_common.h" diff --git a/tests/vboot_api_kernel5_tests.c b/tests/vboot_api_kernel5_tests.c index 86195e3c..cd641e7a 100644 --- a/tests/vboot_api_kernel5_tests.c +++ b/tests/vboot_api_kernel5_tests.c @@ -19,7 +19,7 @@ #include "2struct.h" #include "host_common.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "test_common.h" #include "vb2_common.h" #include "vboot_api.h" diff --git a/tests/vboot_api_kernel_tests.c b/tests/vboot_api_kernel_tests.c index 5b1e71b9..c5636a94 100644 --- a/tests/vboot_api_kernel_tests.c +++ b/tests/vboot_api_kernel_tests.c @@ -14,7 +14,7 @@ #include "2common.h" #include "2nvstorage.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "test_common.h" #include "utility.h" #include "vboot_api.h" diff --git a/tests/vboot_detach_menu_tests.c b/tests/vboot_detach_menu_tests.c index 39bf29dc..bca2cf6f 100644 --- a/tests/vboot_detach_menu_tests.c +++ b/tests/vboot_detach_menu_tests.c @@ -15,7 +15,7 @@ #include "2secdata.h" #include "host_common.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "test_common.h" #include "vboot_api.h" #include "vboot_audio.h" diff --git a/tests/vboot_kernel_tests.c b/tests/vboot_kernel_tests.c index 69789105..25be6fe0 100644 --- a/tests/vboot_kernel_tests.c +++ b/tests/vboot_kernel_tests.c @@ -22,7 +22,7 @@ #include "gpt.h" #include "host_common.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "test_common.h" #include "vb2_common.h" #include "vb2_struct.h" diff --git a/utility/load_kernel_test.c b/utility/load_kernel_test.c index b8f54315..34bee188 100644 --- a/utility/load_kernel_test.c +++ b/utility/load_kernel_test.c @@ -15,7 +15,7 @@ #include "2misc.h" #include "host_common.h" #include "load_kernel_fw.h" -#include "rollback_index.h" +#include "secdata_tpm.h" #include "vboot_common.h" #include "vboot_kernel.h" -- cgit v1.2.1