diff options
author | Joel Kitching <kitching@google.com> | 2019-09-23 22:53:49 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-11-28 20:49:25 +0000 |
commit | adb418310d2e51e2f2a0f22607989fd3f66c4433 (patch) | |
tree | 52fd1dd508adead50871a3cd87cf7cb2ee3d226a | |
parent | 6ef33b990578a9583a3ac53f2c835d4e16219b25 (diff) | |
download | vboot-adb418310d2e51e2f2a0f22607989fd3f66c4433.tar.gz |
vboot/secdata: rewrite rollback_index and centralize reads/writes
In current kernel verification code, secdata reads and writes
are spread throughout the code. vboot2's design is to use
vb2_context.secdata_* for storing the state of secdata spaces,
and have the caller (depthcharge) read/save this field when
necessary.
Centralize secdata reads/writes into the functions of
secdata_tpm.c, previously known as rollback_index.c.
Functions which directly read/write to the TPM space are modified
to use vb2_secdata_*_get and vb2_secdata_*_set.
The secure spaces get read/flushed by functions in
vboot_api_kernel.c. These calls and the underlying functions
from secdata_tpm.c will eventually be relocated to depthcharge.
Create a new external function vb2ex_commit_data, which commits
any modified nvdata/secdata. Currently the depthcharge
implementation of this function only writes nvdata, but once
secdata TPM drivers have been migrated from vboot_reference to
depthcharge, it will also commit these data spaces.
This CL also removes the VbExNvStorageRead call from
vb2_kernel_setup, and the data is instead read in depthcharge
CL:1819379, right before calling VbSelectAndLoadKernel.
As such, both the VbExNvStorageRead and VbExNvStorageWrite
functions may be removed.
Finally, create a vb2_secdata_kernel_lock function, which should
be used right before attempting to leave vboot (by booting an OS
or chainloading to another firmware). This should eventually be
exposed as a vb2ex_ API function and relocated to depthcharge.
BUG=b:124141368, chromium:972956, chromium:1006689
TEST=make clean && make runtests
BRANCH=none
Change-Id: Ifbfb21122af0bf85e22a6d3a0d48a1db7f7c25b7
Signed-off-by: Joel Kitching <kitching@google.com>
Cq-Depend: chromium:1819380, chromium:1939168
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/1728298
Tested-by: Joel Kitching <kitching@chromium.org>
Reviewed-by: Andrey Pronin <apronin@chromium.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Commit-Queue: Joel Kitching <kitching@chromium.org>
28 files changed, 832 insertions, 856 deletions
@@ -183,6 +183,11 @@ ifneq (${TPM2_MODE},) CFLAGS += -DTPM2_MODE endif +# Some tests need to be disabled when using mocked_secdata_tpm. +ifneq (${MOCK_TPM},) +CFLAGS += -DMOCK_TPM +endif + # enable all features during local compile (permits testing) ifeq (${FIRMWARE_ARCH},) DIAGNOSTIC_UI := 1 @@ -693,13 +698,16 @@ TEST_NAMES = \ tests/vboot_kernel_tests \ tests/verify_kernel -ifeq (${TPM2_MODE}${MOCK_TPM},) -# TODO(apronin): tests for TPM2 case? +ifeq (${MOCK_TPM},) # secdata_tpm_tests and tlcl_tests only work when MOCK_TPM is disabled TEST_NAMES += \ - tests/secdata_tpm_tests \ + tests/secdata_tpm_tests +ifeq (${TPM2_MODE},) +# TODO(apronin): tests for TPM2 case? +TEST_NAMES += \ tests/tlcl_tests endif +endif TEST_FUTIL_NAMES = \ tests/futility/binary_editor \ @@ -1259,12 +1267,14 @@ runtestscripts: test_setup genfuzztestcases .PHONY: runmisctests runmisctests: test_setup -ifeq (${TPM2_MODE}${MOCK_TPM},) -# TODO(apronin): tests for TPM2 case? +ifeq (${MOCK_TPM},) # secdata_tpm_tests and tlcl_tests only work when MOCK_TPM is disabled ${RUNTEST} ${BUILD_RUN}/tests/secdata_tpm_tests +ifeq (${TPM2_MODE},) +# TODO(apronin): tests for TPM2 case? ${RUNTEST} ${BUILD_RUN}/tests/tlcl_tests endif +endif ${RUNTEST} ${BUILD_RUN}/tests/utility_string_tests ${RUNTEST} ${BUILD_RUN}/tests/vboot_api_devmode_tests ${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel2_tests diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c index 92e930a8..86438b44 100644 --- a/firmware/2lib/2misc.c +++ b/firmware/2lib/2misc.c @@ -369,3 +369,18 @@ vb2_error_t vb2_select_fw_slot(struct vb2_context *ctx) return VB2_SUCCESS; } + +vb2_error_t vb2_enable_developer_mode(struct vb2_context *ctx) +{ + uint32_t flags; + + VB2_DEBUG("Enabling developer mode...\n"); + + flags = vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS); + flags |= VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE; + vb2_secdata_firmware_set(ctx, VB2_SECDATA_FIRMWARE_FLAGS, flags); + + VB2_DEBUG("Mode change will take effect on next reboot\n"); + + return VB2_SUCCESS; +} diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h index 50ebc1bc..03df7e25 100644 --- a/firmware/2lib/include/2api.h +++ b/firmware/2lib/include/2api.h @@ -930,4 +930,19 @@ vb2_error_t vb2ex_auxfw_finalize(struct vb2_context *ctx); */ void vb2ex_abort(void); +/** + * Commit any pending data to disk. + * + * Commit nvdata and secdata spaces if modified. Normally this should be + * performed after vboot has completed executing and control has been passed + * back to the caller. However, in certain kernel verification cases (e.g. + * right before attempting to boot an OS; from a UI screen which requires + * user-initiated shutdown; just prior to triggering battery cut-off), the + * caller may not get a chance to commit this data. + * + * @param ctx Vboot context + * @returns VB2_SUCCESS, or non-zero error code. + */ +vb2_error_t vb2ex_commit_data(struct vb2_context *ctx); + #endif /* VBOOT_REFERENCE_2API_H_ */ diff --git a/firmware/2lib/include/2misc.h b/firmware/2lib/include/2misc.h index d9be9730..ac8311f2 100644 --- a/firmware/2lib/include/2misc.h +++ b/firmware/2lib/include/2misc.h @@ -163,4 +163,18 @@ vb2_error_t vb2_load_kernel_keyblock(struct vb2_context *ctx); */ vb2_error_t vb2_load_kernel_preamble(struct vb2_context *ctx); +/** + * Utility function to enable developer mode. + * + * Enables the developer flag in vb2_context firmware secdata. Note that + * modified secdata must be saved for change to apply on reboot. + * + * NOTE: Doesn't update the LAST_BOOT_DEVELOPER secdata flag. That should be + * done on the next boot. + * + * @param ctx Vboot context + * @return VB2_SUCCESS, or error code on error. + */ +vb2_error_t vb2_enable_developer_mode(struct vb2_context *ctx); + #endif /* VBOOT_REFERENCE_2MISC_H_ */ diff --git a/firmware/2lib/include/2recovery_reasons.h b/firmware/2lib/include/2recovery_reasons.h index d943563b..d76b142a 100644 --- a/firmware/2lib/include/2recovery_reasons.h +++ b/firmware/2lib/include/2recovery_reasons.h @@ -231,6 +231,9 @@ enum vb2_nv_recovery { /* Alt FW Failed hash verification */ VB2_RECOVERY_ALTFW_HASH_FAILED = 0x61, + /* FWMP secure data initialization error */ + VB2_RECOVERY_SECDATA_FWMP_INIT = 0x62, + /* Unspecified/unknown error in rewritable firmware */ VB2_RECOVERY_RW_UNSPECIFIED = 0x7f, diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h index e6109485..0ab9e750 100644 --- a/firmware/2lib/include/2return_codes.h +++ b/firmware/2lib/include/2return_codes.h @@ -240,6 +240,27 @@ enum vb2_return_code { /* Bad struct version in vb2_secdata_fwmp_check() */ VB2_ERROR_SECDATA_FWMP_VERSION, + /* Error reading secdata_firmware from storage backend */ + VB2_ERROR_SECDATA_FIRMWARE_READ, + + /* Error writing secdata_firmware to storage backend */ + VB2_ERROR_SECDATA_FIRMWARE_WRITE, + + /* Error locking secdata_firmware in storage backend */ + VB2_ERROR_SECDATA_FIRMWARE_LOCK, + + /* Error reading secdata_kernel from storage backend */ + VB2_ERROR_SECDATA_KERNEL_READ, + + /* Error writing secdata_kernel to storage backend */ + VB2_ERROR_SECDATA_KERNEL_WRITE, + + /* Error locking secdata_kernel in storage backend */ + VB2_ERROR_SECDATA_KERNEL_LOCK, + + /* Error reading secdata_fwmp from storage backend */ + VB2_ERROR_SECDATA_FWMP_READ, + /********************************************************************** * Common code errors */ diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h index 5481c379..455c3dcc 100644 --- a/firmware/include/vboot_api.h +++ b/firmware/include/vboot_api.h @@ -231,21 +231,6 @@ vb2_error_t VbExTpmGetRandom(uint8_t *buf, uint32_t length); #endif /* CHROMEOS_ENVIRONMENT */ /*****************************************************************************/ -/* Non-volatile storage */ - -#define VBNV_BLOCK_SIZE 16 /* Size of NV storage block in bytes */ - -/** - * Read the VBNV_BLOCK_SIZE-byte non-volatile storage into buf. - */ -vb2_error_t VbExNvStorageRead(uint8_t *buf); - -/** - * Write the VBNV_BLOCK_SIZE-byte non-volatile storage from buf. - */ -vb2_error_t VbExNvStorageWrite(const uint8_t *buf); - -/*****************************************************************************/ /* Disk access (previously in boot_device.h) */ /* Flags for VbDisk APIs */ diff --git a/firmware/include/vboot_test.h b/firmware/include/vboot_test.h index bdd1f378..a6ed8c09 100644 --- a/firmware/include/vboot_test.h +++ b/firmware/include/vboot_test.h @@ -26,10 +26,14 @@ vb2_error_t vb2_check_padding(const uint8_t *sig, /**************************************************************************** * vboot_api_kernel.c */ -struct RollbackSpaceFwmp; -struct RollbackSpaceFwmp *VbApiKernelGetFwmp(void); - struct LoadKernelParams; struct LoadKernelParams *VbApiKernelGetParams(void); +/**************************************************************************** + * secdata_tpm.c */ + +extern int secdata_kernel_locked; +uint32_t tlcl_clear_and_reenable(void); +uint32_t tlcl_safe_write(uint32_t index, const void *data, uint32_t length); + #endif /* VBOOT_REFERENCE_TEST_API_H_ */ diff --git a/firmware/lib/include/load_kernel_fw.h b/firmware/lib/include/load_kernel_fw.h index b2841e17..9e4db8e6 100644 --- a/firmware/lib/include/load_kernel_fw.h +++ b/firmware/lib/include/load_kernel_fw.h @@ -19,8 +19,6 @@ struct vb2_context; /* GPT is external */ #define BOOT_FLAG_EXTERNAL_GPT (0x04ULL) -struct RollbackSpaceFwmp; - typedef struct LoadKernelParams { /* Inputs to LoadKernel() */ /* Disk handle for current device */ @@ -37,8 +35,6 @@ typedef struct LoadKernelParams { uint64_t kernel_buffer_size; /* Boot flags */ uint64_t boot_flags; - /* Firmware management parameters; may be NULL if not present. */ - const struct RollbackSpaceFwmp *fwmp; /* * Outputs from LoadKernel(); valid only if LoadKernel() returns diff --git a/firmware/lib/include/secdata_tpm.h b/firmware/lib/include/secdata_tpm.h index 6e31e71c..3cf1ae75 100644 --- a/firmware/lib/include/secdata_tpm.h +++ b/firmware/lib/include/secdata_tpm.h @@ -9,165 +9,25 @@ #ifndef VBOOT_REFERENCE_SECDATA_TPM_H_ #define VBOOT_REFERENCE_SECDATA_TPM_H_ -#include "2return_codes.h" -#include "2sysincludes.h" -#include "tss_constants.h" +#include "2api.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 +#define FIRMWARE_NV_INDEX 0x1007 +#define KERNEL_NV_INDEX 0x1008 +/* BACKUP_NV_INDEX (size 16) used to live at 0x1009; now deprecated */ +#define FWMP_NV_INDEX 0x100a +#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), -}; +#define OOBE_USB_AUTOCONFIG_KEY_DIGEST_NV_INDEX 0x100c +#define OOBE_USB_AUTOCONFIG_KEY_DIGEST_NV_SIZE VB2_SHA256_DIGEST_SIZE /* 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); +uint32_t secdata_firmware_write(struct vb2_context *ctx); +uint32_t secdata_kernel_read(struct vb2_context *ctx); +uint32_t secdata_kernel_write(struct vb2_context *ctx); +uint32_t secdata_kernel_lock(struct vb2_context *ctx); +uint32_t secdata_fwmp_read(struct vb2_context *ctx); #endif /* VBOOT_REFERENCE_SECDATA_TPM_H_ */ diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h index cf3c4bb3..28c6cc9a 100644 --- a/firmware/lib/include/vboot_kernel.h +++ b/firmware/lib/include/vboot_kernel.h @@ -80,22 +80,32 @@ vb2_error_t VbBootDeveloperMenu(struct vb2_context *ctx); vb2_error_t VbBootRecoveryMenu(struct vb2_context *ctx); /** - * Return the current FWMP flags. Valid only inside VbSelectAndLoadKernel(). + * Reinitialize global state. This should only need to be called by init tests. */ -uint32_t vb2_get_fwmp_flags(void); +void vb2_init_ui(void); /** - * Commit NvStorage. + * Locks secdata_kernel. * - * This may be called by UI functions which need to save settings before they - * sit in an infinite loop waiting for shutdown (this is, by a UI state which - * will never return). + * Should be used right before attempting to leave vboot (by booting + * an OS or chainloading to another firmware). + * + * @param ctx Vboot context + * @returns VB2_SUCCESS, or non-zero error code. */ -void vb2_nv_commit(struct vb2_context *ctx); +vb2_error_t vb2_secdata_kernel_lock(struct vb2_context *ctx); /** - * Reinitialize global state. This should only need to be called by init tests. + * Writes modified secdata spaces and nvdata. + * + * This is a temporary wrapper around vb2ex_commit_data, until secdata-writing + * functions are relocated into depthcharge. + * + * (See chromium:972956, chromium:1006689.) + * + * @param ctx Vboot context + * @returns VB2_SUCCESS, or non-zero error code. */ -void vb2_init_ui(void); +vb2_error_t vb2_commit_data(struct vb2_context *ctx); #endif /* VBOOT_REFERENCE_VBOOT_KERNEL_H_ */ diff --git a/firmware/lib/mocked_secdata_tpm.c b/firmware/lib/mocked_secdata_tpm.c index dc9f16c6..373c4940 100644 --- a/firmware/lib/mocked_secdata_tpm.c +++ b/firmware/lib/mocked_secdata_tpm.c @@ -3,36 +3,42 @@ * found in the LICENSE file. * * Functions for querying, manipulating and locking secure data spaces - * stored in the TPM NVRAM. + * stored in the TPM NVRAM (mock versions). */ +#include "2api.h" +#include "2secdata.h" #include "secdata_tpm.h" #include "tss_constants.h" -#include "utility.h" -vb2_error_t SetVirtualDevMode(int val) +int secdata_kernel_locked = 0; + +uint32_t secdata_firmware_write(struct vb2_context *ctx) { - return VB2_SUCCESS; + ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED; + return TPM_SUCCESS; } -uint32_t RollbackKernelRead(uint32_t *version) +uint32_t secdata_kernel_read(struct vb2_context *ctx) { - *version = 0; + vb2api_secdata_kernel_create(ctx); return TPM_SUCCESS; } -uint32_t RollbackKernelWrite(uint32_t version) +uint32_t secdata_kernel_write(struct vb2_context *ctx) { + ctx->flags &= ~VB2_CONTEXT_SECDATA_KERNEL_CHANGED; return TPM_SUCCESS; } -uint32_t RollbackKernelLock(int recovery_mode) +uint32_t secdata_kernel_lock(struct vb2_context *ctx) { + secdata_kernel_locked = 1; return TPM_SUCCESS; } -uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp) +uint32_t secdata_fwmp_read(struct vb2_context *ctx) { - memset(fwmp, 0, sizeof(*fwmp)); + ctx->flags |= VB2_CONTEXT_NO_SECDATA_FWMP; return TPM_SUCCESS; } diff --git a/firmware/lib/secdata_tpm.c b/firmware/lib/secdata_tpm.c index 6b77ba55..b8f3522c 100644 --- a/firmware/lib/secdata_tpm.c +++ b/firmware/lib/secdata_tpm.c @@ -6,15 +6,12 @@ * stored in the TPM NVRAM. */ +#include "2api.h" #include "2common.h" -#include "2crc8.h" -#include "2nvstorage.h" -#include "2secdata.h" -#include "2sysincludes.h" #include "secdata_tpm.h" #include "tlcl.h" #include "tss_constants.h" -#include "vboot_api.h" +#include "vboot_test.h" #define RETURN_ON_FAILURE(tpm_command) do { \ uint32_t result_; \ @@ -34,9 +31,15 @@ VB2_DEBUG_RAW("\n"); \ } while (0) -uint32_t TPMClearAndReenable(void) +/* Keeps track of whether the kernel space has already been locked or not. */ +int secdata_kernel_locked = 0; + +/** + * Issue a TPM_Clear and reenable/reactivate the TPM. + */ +uint32_t tlcl_clear_and_reenable(void) { - VB2_DEBUG("TPM: clear and re-enable\n"); + VB2_DEBUG("TPM: clear_and_reenable\n"); RETURN_ON_FAILURE(TlclForceClear()); RETURN_ON_FAILURE(TlclSetEnable()); RETURN_ON_FAILURE(TlclSetDeactivated(0)); @@ -44,11 +47,17 @@ uint32_t TPMClearAndReenable(void) return TPM_SUCCESS; } -uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length) +/** + * 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 tlcl_safe_write(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_ON_FAILURE(tlcl_clear_and_reenable()); return TlclWrite(index, data, length); } else { return result; @@ -56,73 +65,30 @@ uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length) } /* 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 %#x\n", r); - return r; +uint32_t secdata_firmware_write(struct vb2_context *ctx) +{ + if (!(ctx->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED)) { + VB2_DEBUG("TPM: secdata_firmware unchanged\n"); + return TPM_SUCCESS; } - 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; + if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { + VB2_DEBUG("Error: secdata_firmware modified " + "in non-recovery mode?\n"); + return TPM_E_AREA_LOCKED; } - 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; - } + PRINT_BYTES("TPM: write secdata_firmware", &ctx->secdata_firmware); + RETURN_ON_FAILURE(tlcl_safe_write(FIRMWARE_NV_INDEX, + ctx->secdata_firmware, + VB2_SECDATA_FIRMWARE_SIZE)); + ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED; 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) +uint32_t secdata_kernel_read(struct vb2_context *ctx) { #ifndef TPM2_MODE /* @@ -135,158 +101,89 @@ uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk) uint32_t perms; RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms)); - - if (perms != TPM_NV_PER_PPWRITE) + if (perms != TPM_NV_PER_PPWRITE) { + VB2_DEBUG("TPM: invalid secdata_kernel permissions: %#x\n", + perms); 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 %#x\n", r); - return r; } - PRINT_BYTES("TPM: read secdata_kernel", rsk); +#endif - if (rsk->struct_version < ROLLBACK_SPACE_FIRMWARE_VERSION) - return TPM_E_STRUCT_VERSION; + RETURN_ON_FAILURE(TlclRead(KERNEL_NV_INDEX, ctx->secdata_kernel, + VB2_SECDATA_KERNEL_SIZE)); - if (rsk->uid != ROLLBACK_SPACE_KERNEL_UID) - return TPM_E_CORRUPTED_STATE; + PRINT_BYTES("TPM: read secdata_kernel", &ctx->secdata_kernel); - if (rsk->crc8 != vb2_crc8(rsk, offsetof(RollbackSpaceKernel, crc8))) { - VB2_DEBUG("TPM: bad secdata_kernel CRC\n"); + if (vb2api_secdata_kernel_check(ctx)) { + VB2_DEBUG("TPM: secdata_kernel invalid (corrupted?)\n"); return TPM_E_CORRUPTED_STATE; } return TPM_SUCCESS; } -uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk) +uint32_t secdata_kernel_write(struct vb2_context *ctx) { - 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; + if (!(ctx->flags & VB2_CONTEXT_SECDATA_KERNEL_CHANGED)) { + VB2_DEBUG("TPM: secdata_kernel unchanged\n"); + return TPM_SUCCESS; } - return TPM_SUCCESS; -} + PRINT_BYTES("TPM: write secdata_kernel", &ctx->secdata_kernel); -uint32_t RollbackKernelRead(uint32_t* version) -{ - RollbackSpaceKernel rsk; - RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); - memcpy(version, &rsk.kernel_versions, sizeof(*version)); - VB2_DEBUG("TPM: RollbackKernelRead %#x\n", (int)*version); - return TPM_SUCCESS; -} + RETURN_ON_FAILURE(tlcl_safe_write(KERNEL_NV_INDEX, ctx->secdata_kernel, + VB2_SECDATA_KERNEL_SIZE)); -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 %#x --> %#x\n", - (int)old_version, (int)version); - memcpy(&rsk.kernel_versions, &version, sizeof(version)); - return WriteSpaceKernel(&rsk); + ctx->flags &= ~VB2_CONTEXT_SECDATA_KERNEL_CHANGED; + return TPM_SUCCESS; } -uint32_t RollbackKernelLock(int recovery_mode) +uint32_t secdata_kernel_lock(struct vb2_context *ctx) { - static int kernel_locked = 0; - uint32_t r; - - if (recovery_mode || kernel_locked) + /* Skip if already locked */ + if (secdata_kernel_locked) { + VB2_DEBUG("TPM: secdata_kernel already locked; skipping\n"); return TPM_SUCCESS; + } - r = TlclLockPhysicalPresence(); - if (TPM_SUCCESS == r) - kernel_locked = 1; + RETURN_ON_FAILURE(TlclLockPhysicalPresence()); - VB2_DEBUG("TPM: lock secdata_kernel returned %#x\n", r); - return r; + VB2_DEBUG("TPM: secdata_kernel locked\n"); + secdata_kernel_locked = 1; + return TPM_SUCCESS; } -uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp) +uint32_t secdata_fwmp_read(struct vb2_context *ctx) { - 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; + vb2_error_t rv; + uint8_t size = VB2_SECDATA_FWMP_MIN_SIZE; 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)); + r = TlclRead(FWMP_NV_INDEX, ctx->secdata_fwmp, size); if (TPM_E_BADINDEX == r) { - /* Missing space is not an error; use defaults */ - VB2_DEBUG("TPM: no FWMP space\n"); + /* Missing space is not an error; tell vboot */ + VB2_DEBUG("TPM: no secdata_fwmp space\n"); + ctx->flags |= VB2_CONTEXT_NO_SECDATA_FWMP; return TPM_SUCCESS; } else if (TPM_SUCCESS != r) { - VB2_DEBUG("TPM: read FWMP returned %#x\n", r); + VB2_DEBUG("TPM: read secdata_fwmp returned %#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: %#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 %#x\n", r); - return r; - } - } + /* Re-read more data if necessary */ + rv = vb2api_secdata_fwmp_check(ctx, &size); + if (rv == VB2_SUCCESS) + return VB2_SUCCESS; - /* 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; - } + if (rv == VB2_ERROR_SECDATA_FWMP_INCOMPLETE) { + RETURN_ON_FAILURE(TlclRead(FWMP_NV_INDEX, ctx->secdata_fwmp, + size)); - /* 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; + /* Check one more time */ + if (vb2api_secdata_fwmp_check(ctx, &size) == VB2_SUCCESS) + return VB2_SUCCESS; } - /* - * 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; + VB2_DEBUG("TPM: secdata_fwmp invalid (corrupted?)\n"); + return TPM_E_CORRUPTED_STATE; } diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index 5408c5a3..308a3275 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -22,36 +22,20 @@ #include "vboot_test.h" /* Global variables */ -static struct RollbackSpaceFwmp fwmp; static LoadKernelParams lkp; #ifdef CHROMEOS_ENVIRONMENT -/* Global variable accessors for unit tests */ - -struct RollbackSpaceFwmp *VbApiKernelGetFwmp(void) -{ - return &fwmp; -} - +/* Global variable accessor for unit tests */ struct LoadKernelParams *VbApiKernelGetParams(void) { return &lkp; } - #endif -void vb2_nv_commit(struct vb2_context *ctx) -{ - /* Exit if nothing has changed */ - if (!(ctx->flags & VB2_CONTEXT_NVDATA_CHANGED)) - return; - - ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED; - VbExNvStorageWrite(ctx->nvdata); -} - static vb2_error_t handle_battery_cutoff(struct vb2_context *ctx) { + vb2_error_t rv; + /* * Check if we need to cut-off battery. This should be done after EC * FW and Aux FW are updated, and before the kernel is started. This @@ -61,8 +45,12 @@ static vb2_error_t handle_battery_cutoff(struct vb2_context *ctx) if (vb2_nv_get(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST)) { VB2_DEBUG("Request to cut-off battery\n"); vb2_nv_set(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST, 0); + /* May lose power immediately, so commit our update now. */ - vb2_nv_commit(ctx); + rv = vb2_commit_data(ctx); + if (rv) + return rv; + vb2ex_ec_battery_cutoff(); return VBERROR_SHUTDOWN_REQUESTED; } @@ -70,11 +58,6 @@ static vb2_error_t handle_battery_cutoff(struct vb2_context *ctx) return VB2_SUCCESS; } -uint32_t vb2_get_fwmp_flags(void) -{ - return fwmp.flags; -} - vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t get_info_flags) { vb2_error_t rv = VBERROR_NO_DISK_FOUND; @@ -82,7 +65,6 @@ vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t get_info_flags) uint32_t disk_count = 0; uint32_t i; - lkp.fwmp = &fwmp; lkp.disk_handle = NULL; /* Find disks */ @@ -234,13 +216,8 @@ vb2_error_t VbBootNormal(struct vb2_context *ctx) } if (shared->kernel_version_tpm > shared->kernel_version_tpm_start) { - uint32_t tpm_rv = - RollbackKernelWrite(shared->kernel_version_tpm); - if (tpm_rv) { - VB2_DEBUG("Error writing kernel versions to TPM.\n"); - vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_W_ERROR, tpm_rv); - return VBERROR_TPM_WRITE_KERNEL; - } + vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS, + shared->kernel_version_tpm); } return rv; @@ -251,6 +228,7 @@ static vb2_error_t vb2_kernel_setup(struct vb2_context *ctx, VbSelectAndLoadKernelParams *kparams) { uint32_t tpm_rv; + vb2_error_t rv; /* Translate vboot1 flags back to vboot2 */ if (shared->recovery_reason) @@ -274,11 +252,9 @@ static vb2_error_t vb2_kernel_setup(struct vb2_context *ctx, if (shared->flags & VBSD_NVDATA_V2) ctx->flags |= VB2_CONTEXT_NVDATA_V2; - VbExNvStorageRead(ctx->nvdata); vb2_nv_init(ctx); struct vb2_shared_data *sd = vb2_get_sd(ctx); - struct vb2_gbb_header *gbb = vb2_get_gbb(ctx); sd->recovery_reason = shared->recovery_reason; /* @@ -312,41 +288,53 @@ static vb2_error_t vb2_kernel_setup(struct vb2_context *ctx, kparams->flags = 0; memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid)); - /* Read kernel version from the TPM. Ignore errors in recovery mode. */ - tpm_rv = RollbackKernelRead(&shared->kernel_version_tpm); - if (tpm_rv) { - VB2_DEBUG("Unable to get kernel versions from TPM\n"); - if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { - vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_R_ERROR, tpm_rv); - return VBERROR_TPM_READ_KERNEL; - } + /* + * Read secdata_kernel and secdata_fwmp spaces. No need to read + * secdata_firmware, since it was already read during firmware + * verification. Ignore errors in recovery mode. + */ + tpm_rv = secdata_kernel_read(ctx); + if (tpm_rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { + VB2_DEBUG("TPM: read secdata_kernel returned %#x\n", tpm_rv); + vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_R_ERROR, tpm_rv); + return VB2_ERROR_SECDATA_KERNEL_READ; } - - shared->kernel_version_tpm_start = shared->kernel_version_tpm; - - /* Read FWMP. Ignore errors in recovery mode. */ - if (gbb->flags & VB2_GBB_FLAG_DISABLE_FWMP) { - memset(&fwmp, 0, sizeof(fwmp)); - return VB2_SUCCESS; + tpm_rv = secdata_fwmp_read(ctx); + if (tpm_rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { + VB2_DEBUG("TPM: read secdata_fwmp returned %#x\n", tpm_rv); + vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_R_ERROR, tpm_rv); + return VB2_ERROR_SECDATA_FWMP_READ; } - tpm_rv = RollbackFwmpRead(&fwmp); - if (tpm_rv) { - VB2_DEBUG("Unable to get FWMP from TPM\n"); - if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { - vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_R_ERROR, tpm_rv); - return VBERROR_TPM_READ_FWMP; - } + /* + * Init secdata_kernel and secdata_fwmp spaces. No need to init + * secdata_firmware, since it was already read during firmware + * verification. Ignore errors in recovery mode. + */ + rv = vb2_secdata_kernel_init(ctx); + if (rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { + VB2_DEBUG("TPM: init secdata_kernel returned %#x\n", rv); + vb2api_fail(ctx, VB2_RECOVERY_SECDATA_KERNEL_INIT, rv); + return rv; } + rv = vb2_secdata_fwmp_init(ctx); + if (rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { + VB2_DEBUG("TPM: init secdata_fwmp returned %#x\n", rv); + vb2api_fail(ctx, VB2_RECOVERY_SECDATA_FWMP_INIT, rv); + return rv; + } + + /* Read kernel version from the TPM. */ + shared->kernel_version_tpm = + vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS); + shared->kernel_version_tpm_start = shared->kernel_version_tpm; return VB2_SUCCESS; } -static vb2_error_t vb2_kernel_phase4(struct vb2_context *ctx, - VbSelectAndLoadKernelParams *kparams) +static void vb2_kernel_fill_kparams(struct vb2_context *ctx, + VbSelectAndLoadKernelParams *kparams) { - struct vb2_shared_data *sd = vb2_get_sd(ctx); - /* Save disk parameters */ kparams->disk_handle = lkp.disk_handle; kparams->partition_number = lkp.partition_number; @@ -357,30 +345,89 @@ static vb2_error_t vb2_kernel_phase4(struct vb2_context *ctx, kparams->kernel_buffer_size = lkp.kernel_buffer_size; memcpy(kparams->partition_guid, lkp.partition_guid, sizeof(kparams->partition_guid)); +} - /* Lock the kernel versions if not in recovery mode */ - if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { - uint32_t tpm_rv = RollbackKernelLock(sd->recovery_reason); - if (tpm_rv) { - VB2_DEBUG("Error locking kernel versions.\n"); - vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_L_ERROR, tpm_rv); - return VBERROR_TPM_LOCK_KERNEL; - } +vb2_error_t vb2_secdata_kernel_lock(struct vb2_context *ctx) +{ + uint32_t tpm_rv; + + /* Skip if in recovery mode. */ + if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) + return VB2_SUCCESS; + + tpm_rv = secdata_kernel_lock(ctx); + if (tpm_rv) { + VB2_DEBUG("TPM: lock secdata_kernel returned %#x\n", tpm_rv); + vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_L_ERROR, tpm_rv); + return VB2_ERROR_SECDATA_KERNEL_LOCK; } return VB2_SUCCESS; } -static void vb2_kernel_cleanup(struct vb2_context *ctx) +vb2_error_t vb2_commit_data(struct vb2_context *ctx) { - vb2_nv_commit(ctx); + vb2_error_t call_rv; + vb2_error_t rv = VB2_SUCCESS; + uint32_t tpm_rv; + + /* Write secdata spaces. vboot never writes back to secdata_fwmp. */ + tpm_rv = secdata_firmware_write(ctx); + if (tpm_rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { + VB2_DEBUG("TPM: write secdata_firmware returned %#x\n", tpm_rv); + vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_W_ERROR, tpm_rv); + rv = VB2_ERROR_SECDATA_FIRMWARE_WRITE; + } + + tpm_rv = secdata_kernel_write(ctx); + if (tpm_rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { + VB2_DEBUG("TPM: write secdata_kernel returned %#x\n", tpm_rv); + vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_W_ERROR, tpm_rv); + if (rv == VB2_SUCCESS) + rv = VB2_ERROR_SECDATA_KERNEL_WRITE; + } + + /* Always try to write nvdata, since it may have been changed by + setting a recovery reason above. */ + + /* TODO(chromium:972956, chromium:1006689): Currently only commits + nvdata, but should eventually also commit secdata. */ + call_rv = vb2ex_commit_data(ctx); + switch (call_rv) { + case VB2_ERROR_NV_WRITE: + /* Don't bother with vb2api_fail since we can't write + nvdata anyways. */ + if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) { + VB2_DEBUG("write nvdata failed\n"); + if (rv == VB2_SUCCESS) + rv = call_rv; + } else { + /* Impossible to enter recovery mode */ + VB2_DIE("write nvdata failed\n"); + } + break; + + case VB2_SUCCESS: + break; + + default: + VB2_DEBUG("unknown commit error: %#x\n", call_rv); + if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE) && + rv == VB2_SUCCESS) + rv = call_rv; + break; + } + + return rv; } vb2_error_t VbSelectAndLoadKernel(struct vb2_context *ctx, VbSharedDataHeader *shared, VbSelectAndLoadKernelParams *kparams) { - vb2_error_t rv = vb2_kernel_setup(ctx, shared, kparams); + vb2_error_t rv, call_rv; + + rv = vb2_kernel_setup(ctx, shared, kparams); if (rv) goto VbSelectAndLoadKernel_exit; @@ -441,10 +488,18 @@ vb2_error_t VbSelectAndLoadKernel(struct vb2_context *ctx, VbSelectAndLoadKernel_exit: - if (VB2_SUCCESS == rv) - rv = vb2_kernel_phase4(ctx, kparams); + if (rv == VB2_SUCCESS) + vb2_kernel_fill_kparams(ctx, kparams); + + /* Commit data, but retain any previous errors */ + call_rv = vb2_commit_data(ctx); + if (rv == VB2_SUCCESS) + rv = call_rv; - vb2_kernel_cleanup(ctx); + /* Lock secdata_kernel, but retain any previous errors */ + call_rv = vb2_secdata_kernel_lock(ctx); + if (rv == VB2_SUCCESS) + rv = call_rv; /* Pass through return value from boot path */ VB2_DEBUG("Returning %#x\n", rv); diff --git a/firmware/lib/vboot_display.c b/firmware/lib/vboot_display.c index d3daf658..0c62a86d 100644 --- a/firmware/lib/vboot_display.c +++ b/firmware/lib/vboot_display.c @@ -383,11 +383,11 @@ vb2_error_t VbCheckDisplayKey(struct vb2_context *ctx, uint32_t key, /* * Non-manual recovery mode is meant to be left via three-finger * salute (into manual recovery mode). Need to commit nvdata - * changes immediately. + * changes immediately. Ignore commit errors in recovery mode. */ if ((ctx->flags & VB2_CONTEXT_RECOVERY_MODE) && !vb2_allow_recovery(ctx)) - vb2_nv_commit(ctx); + vb2_commit_data(ctx); /* Force redraw of current screen */ return VbDisplayScreen(ctx, disp_current_screen, 1, data); diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c index 351044b3..1f1647cc 100644 --- a/firmware/lib/vboot_kernel.c +++ b/firmware/lib/vboot_kernel.c @@ -63,8 +63,8 @@ static int require_official_os(struct vb2_context *ctx, return 1; /* FWMP can require developer mode to use official OS */ - if (params->fwmp && - (params->fwmp->flags & FWMP_DEV_ENABLE_OFFICIAL_ONLY)) + if (vb2_secdata_fwmp_get_flag( + ctx, VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY)) return 1; /* Developer can request official OS via nvstorage */ @@ -210,7 +210,7 @@ static vb2_error_t vb2_verify_kernel_vblock( /* If in developer mode and using key hash, check it */ if ((kBootDev == boot_mode) && - params->fwmp && (params->fwmp->flags & FWMP_DEV_USE_KEY_HASH)) { + vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_USE_KEY_HASH)) { struct vb2_packed_key *key = &keyblock->data_key; uint8_t *buf = ((uint8_t *)key) + key->key_offset; uint32_t buflen = key->key_size; @@ -219,15 +219,22 @@ static vb2_error_t vb2_verify_kernel_vblock( VB2_DEBUG("Checking developer key hash.\n"); vb2_digest_buffer(buf, buflen, VB2_HASH_SHA256, digest, sizeof(digest)); - if (0 != vb2_safe_memcmp(digest, params->fwmp->dev_key_hash, + + uint8_t *fwmp_dev_key_hash = + vb2_secdata_fwmp_get_dev_key_hash(ctx); + if (fwmp_dev_key_hash == NULL) { + VB2_DEBUG("Couldn't retrieve developer key hash.\n"); + return VB2_ERROR_VBLOCK_DEV_KEY_HASH; + } + + if (0 != vb2_safe_memcmp(digest, fwmp_dev_key_hash, VB2_SHA256_DIGEST_SIZE)) { int i; VB2_DEBUG("Wrong developer key hash.\n"); VB2_DEBUG("Want: "); for (i = 0; i < VB2_SHA256_DIGEST_SIZE; i++) - VB2_DEBUG("%02x", - params->fwmp->dev_key_hash[i]); + VB2_DEBUG("%02x", fwmp_dev_key_hash[i]); VB2_DEBUG("\nGot: "); for (i = 0; i < VB2_SHA256_DIGEST_SIZE; i++) VB2_DEBUG("%02x", digest[i]); diff --git a/firmware/lib/vboot_ui.c b/firmware/lib/vboot_ui.c index f7e82a99..306e22da 100644 --- a/firmware/lib/vboot_ui.c +++ b/firmware/lib/vboot_ui.c @@ -477,10 +477,10 @@ static vb2_error_t vb2_diagnostics_ui(struct vb2_context *ctx) /* * The following helps avoid use of the TPM after * it's disabled (e.g., when vb2_run_altfw() calls - * RollbackKernelLock() ). + * secdata_kernel_lock() ). */ - if (RollbackKernelLock(0)) { + if (secdata_kernel_lock(ctx)) { VB2_DEBUG("Failed to lock TPM PP\n"); vb2api_fail(ctx, VB2_RECOVERY_TPM_DISABLE_FAILED, 0); } else if (vb2ex_tpm_set_mode(VB2_TPM_MODE_DISABLED) != @@ -542,12 +542,11 @@ static vb2_error_t vb2_developer_ui(struct vb2_context *ctx) } /* Handle FWMP override */ - uint32_t fwmp_flags = vb2_get_fwmp_flags(); - if (fwmp_flags & FWMP_DEV_ENABLE_USB) + if (vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_ENABLE_USB)) allow_usb = 1; - if (fwmp_flags & FWMP_DEV_ENABLE_LEGACY) + if (vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_ENABLE_LEGACY)) allow_legacy = 1; - if (fwmp_flags & FWMP_DEV_DISABLE_BOOT) { + if (vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_DISABLE_BOOT)) { if (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON) { VB2_DEBUG("FWMP_DEV_DISABLE_BOOT rejected by " "FORCE_DEV_SWITCH_ON\n"); @@ -819,9 +818,9 @@ static vb2_error_t recovery_ui(struct vb2_context *ctx) /* * Non-manual recovery mode is meant to be left via three-finger * salute (into manual recovery mode). Need to commit nvdata - * changes immediately. + * changes immediately. Ignore commit errors in recovery mode. */ - vb2_nv_commit(ctx); + vb2_commit_data(ctx); VbDisplayScreen(ctx, VB_SCREEN_OS_BROKEN, 0, NULL); VB2_DEBUG("VbBootRecovery() waiting for manual recovery\n"); @@ -885,7 +884,7 @@ static vb2_error_t recovery_ui(struct vb2_context *ctx) switch (VbUserConfirms(ctx, vbc_flags)) { case 1: VB2_DEBUG("Enabling dev-mode...\n"); - if (VB2_SUCCESS != SetVirtualDevMode(1)) + if (VB2_SUCCESS != vb2_enable_developer_mode(ctx)) return VBERROR_TPM_SET_BOOT_MODE_STATE; VB2_DEBUG("Reboot so it will take effect\n"); if (VbExGetSwitches diff --git a/firmware/lib/vboot_ui_common.c b/firmware/lib/vboot_ui_common.c index 1e956576..5f51f530 100644 --- a/firmware/lib/vboot_ui_common.c +++ b/firmware/lib/vboot_ui_common.c @@ -43,11 +43,12 @@ void vb2_error_notify(const char *print_msg, void vb2_run_altfw(struct vb2_context *ctx, enum VbAltFwIndex_t altfw_num) { - if (RollbackKernelLock(0)) { + if (secdata_kernel_lock(ctx)) { vb2_error_notify("Error locking kernel versions on legacy " "boot.\n", NULL, VB_BEEP_FAILED); } else { - vb2_nv_commit(ctx); + /* TODO: Figure out what to do on commit error in altfw. */ + vb2_commit_data(ctx); VbExLegacy(altfw_num); /* will not return if found */ vb2_error_notify("Legacy boot failed. Missing BIOS?\n", NULL, VB_BEEP_FAILED); diff --git a/firmware/lib/vboot_ui_menu.c b/firmware/lib/vboot_ui_menu.c index 89ac6323..bc3d882c 100644 --- a/firmware/lib/vboot_ui_menu.c +++ b/firmware/lib/vboot_ui_menu.c @@ -181,7 +181,7 @@ static vb2_error_t boot_usb_action(struct vb2_context *ctx) if (!vb2_nv_get(ctx, VB2_NV_DEV_BOOT_USB) && !(vb2_get_gbb(ctx)->flags & VB2_GBB_FLAG_FORCE_DEV_BOOT_USB) && - !(vb2_get_fwmp_flags() & FWMP_DEV_ENABLE_USB)) { + !vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_ENABLE_USB)) { vb2_flash_screen(ctx); vb2_error_notify("WARNING: Booting from external media " "(USB/SD) has not been enabled. Refer " @@ -313,11 +313,11 @@ static vb2_error_t language_action(struct vb2_context *ctx) /* * Non-manual recovery mode is meant to be left via three-finger * salute (into manual recovery mode). Need to commit nvdata - * changes immediately. + * changes immediately. Ignore commit errors in recovery mode. */ if ((ctx->flags & VB2_CONTEXT_RECOVERY_MODE) && !vb2_allow_recovery(ctx)) - vb2_nv_commit(ctx); + vb2_commit_data(ctx); /* Return to previous menu. */ switch (prev_menu) { @@ -360,7 +360,7 @@ static vb2_error_t to_dev_action(struct vb2_context *ctx) return VBERROR_KEEP_LOOPING; VB2_DEBUG("Enabling dev-mode...\n"); - if (VB2_SUCCESS != SetVirtualDevMode(1)) + if (VB2_SUCCESS != vb2_enable_developer_mode(ctx)) return VBERROR_TPM_SET_BOOT_MODE_STATE; /* This was meant for headless devices, shouldn't really matter here. */ @@ -744,7 +744,7 @@ static vb2_error_t vb2_developer_menu(struct vb2_context *ctx) /* Check if developer mode is disabled by FWMP */ disable_dev_boot = 0; - if (vb2_get_fwmp_flags() & FWMP_DEV_DISABLE_BOOT) { + if (vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_DISABLE_BOOT)) { if (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON) { VB2_DEBUG("FWMP_DEV_DISABLE_BOOT rejected by" "FORCE_DEV_SWITCH_ON\n"); @@ -754,9 +754,10 @@ static vb2_error_t vb2_developer_menu(struct vb2_context *ctx) VB2_DEBUG("dev_disable_boot is set.\n"); } } + altfw_allowed = vb2_nv_get(ctx, VB2_NV_DEV_BOOT_LEGACY) || (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_BOOT_LEGACY) || - (vb2_get_fwmp_flags() & FWMP_DEV_ENABLE_LEGACY); + vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_ENABLE_LEGACY); /* Show appropriate initial menu */ if (disable_dev_boot) @@ -849,7 +850,9 @@ static vb2_error_t broken_ui(struct vb2_context *ctx) */ VB2_DEBUG("saving recovery reason (%#x)\n", vbsd->recovery_reason); vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, vbsd->recovery_reason); - vb2_nv_commit(ctx); + + /* Ignore commit errors in recovery mode. */ + vb2_commit_data(ctx); enter_recovery_base_screen(ctx); diff --git a/firmware/stub/vboot_api_stub_init.c b/firmware/stub/vboot_api_stub_init.c index 7dc4c01c..d533325c 100644 --- a/firmware/stub/vboot_api_stub_init.c +++ b/firmware/stub/vboot_api_stub_init.c @@ -23,12 +23,8 @@ uint64_t VbExGetTimer(void) return (uint64_t)tv.tv_sec * VB_USEC_PER_SEC + (uint64_t)tv.tv_usec; } -vb2_error_t VbExNvStorageRead(uint8_t *buf) -{ - return VB2_SUCCESS; -} - -vb2_error_t VbExNvStorageWrite(const uint8_t *buf) +vb2_error_t vb2ex_commit_data(struct vb2_context *ctx) { + ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED; return VB2_SUCCESS; } diff --git a/tests/secdata_tpm_tests.c b/tests/secdata_tpm_tests.c index dd28e62a..32285ded 100644 --- a/tests/secdata_tpm_tests.c +++ b/tests/secdata_tpm_tests.c @@ -2,24 +2,16 @@ * 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 + * Tests for TPM secure data space functions */ -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "2crc8.h" +#include "2api.h" +#include "2secdata.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"); +#include "tss_constants.h" +#include "vboot_test.h" /* * Buffer to hold accumulated list of calls to mocked Tlcl functions. @@ -45,59 +37,85 @@ static char *mock_cnext = mock_calls; static int mock_count = 0; static int fail_at_count = 0; static uint32_t fail_with_error = TPM_SUCCESS; +static int mock_bad_crc = 0; /* 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 uint8_t mock_rsf[VB2_SECDATA_FIRMWARE_SIZE]; +static uint8_t mock_rsk[VB2_SECDATA_KERNEL_SIZE]; +static uint8_t mock_fwmp[VB2_SECDATA_FWMP_MAX_SIZE]; +static uint32_t mock_fwmp_real_size; 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); -} +static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE] + __attribute__ ((aligned (VB2_WORKBUF_ALIGN))); +static struct vb2_context *ctx; /* Reset the variables for the Tlcl mock functions. */ -static void ResetMocks(int fail_on_call, uint32_t fail_with_err) +static void reset_common_data(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; + mock_bad_crc = 0; 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)); + /* Use value other than 0 for memcmp() checks */ + memset(&mock_rsf, 0xa6, sizeof(mock_rsf)); + memset(&mock_rsk, 0xa7, sizeof(mock_rsk)); + memset(&mock_fwmp, 0xa8, sizeof(mock_fwmp)); - 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_fwmp_real_size = VB2_SECDATA_FWMP_MIN_SIZE; + /* Note: only used when TPM2_MODE is disabled. */ +#ifndef TPM2_MODE mock_permissions = TPM_NV_PER_PPWRITE; +#else + mock_permissions = 0; +#endif + + secdata_kernel_locked = 0; + + TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx), + "vb2api_init failed"); + + ctx->flags |= VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED; + ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED; + ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; +} + +/* Mock functions */ + +vb2_error_t vb2api_secdata_firmware_check(struct vb2_context *c) +{ + if (mock_bad_crc) + return VB2_ERROR_SECDATA_FIRMWARE_CRC; + + return VB2_SUCCESS; +} - 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(); +vb2_error_t vb2api_secdata_kernel_check(struct vb2_context *c) +{ + if (mock_bad_crc) + return VB2_ERROR_SECDATA_FIRMWARE_CRC; + + return VB2_SUCCESS; +} + +vb2_error_t vb2api_secdata_fwmp_check(struct vb2_context *c, uint8_t *size) +{ + if (*size < mock_fwmp_real_size) { + *size = mock_fwmp_real_size; + return VB2_ERROR_SECDATA_FWMP_INCOMPLETE; + } + + if (mock_bad_crc) + return VB2_ERROR_SECDATA_FIRMWARE_CRC; + + return VB2_SUCCESS; } /****************************************************************************/ @@ -212,26 +230,12 @@ uint32_t TlclAssertPhysicalPresence(void) 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"); @@ -244,6 +248,7 @@ uint32_t TlclLockPhysicalPresence(void) return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS; } +#ifndef TPM2_MODE uint32_t TlclGetPermissions(uint32_t index, uint32_t* permissions) { mock_cnext += sprintf(mock_cnext, "TlclGetPermissions(%#x)\n", index); @@ -251,297 +256,332 @@ uint32_t TlclGetPermissions(uint32_t index, uint32_t* permissions) return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS; } -/****************************************************************************/ -/* Tests for CRC errors */ - -static void FirmwareSpaceTest(void) +uint32_t TlclFinalizePhysicalPresence(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"); + mock_cnext += sprintf(mock_cnext, "TlclFinalizePhysicalPresence()\n"); + mock_pflags.physicalPresenceLifetimeLock = 1; + return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS; } -static void KernelSpaceTest(void) +uint32_t TlclSetNvLocked(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"); + mock_cnext += sprintf(mock_cnext, "TlclSetNvLocked()\n"); + mock_pflags.nvLocked = 1; + return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS; } +#endif /****************************************************************************/ /* Tests for misc helper functions */ -static void MiscTest(void) +static void misc_tests(void) { uint8_t buf[8]; - ResetMocks(0, 0); - TEST_EQ(TPMClearAndReenable(), 0, "TPMClearAndReenable()"); + reset_common_data(0, 0); + TEST_EQ(tlcl_clear_and_reenable(), 0, "tlcl_clear_and_enable()"); TEST_STR_EQ(mock_calls, "TlclForceClear()\n" "TlclSetEnable()\n" "TlclSetDeactivated(0)\n", - "tlcl calls"); + " tlcl calls"); - ResetMocks(0, 0); - TEST_EQ(SafeWrite(0x123, buf, 8), 0, "SafeWrite()"); + reset_common_data(0, 0); + TEST_EQ(tlcl_safe_write(0x123, buf, 8), 0, "tlcl_safe_write()"); TEST_STR_EQ(mock_calls, "TlclWrite(0x123, 8)\n", - "tlcl calls"); + " tlcl calls"); - ResetMocks(1, TPM_E_BADINDEX); - TEST_EQ(SafeWrite(0x123, buf, 8), TPM_E_BADINDEX, "SafeWrite() bad"); + reset_common_data(1, TPM_E_BADINDEX); + TEST_EQ(tlcl_safe_write(0x123, buf, 8), TPM_E_BADINDEX, + "tlcl_safe_write() bad"); TEST_STR_EQ(mock_calls, "TlclWrite(0x123, 8)\n", - "tlcl calls"); + " tlcl calls"); - ResetMocks(1, TPM_E_MAXNVWRITES); - TEST_EQ(SafeWrite(0x123, buf, 8), 0, "SafeWrite() retry max writes"); + reset_common_data(1, TPM_E_MAXNVWRITES); + TEST_EQ(tlcl_safe_write(0x123, buf, 8), 0, + "tlcl_safe_write() 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"); + " tlcl calls"); } /****************************************************************************/ -/* Tests for RollbackKernel() calls */ +/* Tests for firmware space functions */ -static void RollbackKernelTest(void) +static void secdata_firmware_tests(void) { - uint32_t version = 0; + /* Write with no new changes */ + reset_common_data(0, 0); + ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED; + TEST_SUCC(secdata_firmware_write(ctx), + "secdata_firmware_write(), no changes, success"); + TEST_STR_EQ(mock_calls, + "", + " tlcl calls"); - /* Normal read */ - ResetMocks(0, 0); - TEST_EQ(RollbackKernelRead(&version), 0, "RollbackKernelRead()"); + /* Write failure */ + reset_common_data(1, TPM_E_IOERROR); + TEST_EQ(secdata_firmware_write(ctx), TPM_E_IOERROR, + "secdata_firmware_write(), failure"); TEST_STR_EQ(mock_calls, - "TlclGetPermissions(0x1008)\n" + "TlclWrite(0x1007, 10)\n", + " tlcl calls"); + TEST_NEQ(ctx->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED, 0, + " should leave SECDATA_FIRMWARE_CHANGED context flag"); + + /* Write in normal mode */ + reset_common_data(0, 0); + ctx->flags &= ~VB2_CONTEXT_RECOVERY_MODE; + TEST_EQ(secdata_firmware_write(ctx), TPM_E_AREA_LOCKED, + "secdata_firmware_write(), normal mode, failure"); + TEST_STR_EQ(mock_calls, + "", + " tlcl calls"); + TEST_NEQ(ctx->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED, 0, + " should leave SECDATA_FIRMWARE_CHANGED context flag"); + + /* Write success and readback */ + reset_common_data(0, 0); + memset(ctx->secdata_firmware, 0xaa, sizeof(ctx->secdata_firmware)); + TEST_SUCC(secdata_firmware_write(ctx), + "secdata_firmware_write(), success"); + TEST_STR_EQ(mock_calls, + "TlclWrite(0x1007, 10)\n", + " tlcl calls"); + memset(ctx->secdata_firmware, 0xaa, sizeof(ctx->secdata_firmware)); + TEST_EQ(memcmp(ctx->secdata_firmware, &mock_rsf, + sizeof(ctx->secdata_firmware)), 0, + " unchanged on readback"); + TEST_EQ(ctx->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED, 0, + " should reset SECDATA_FIRMWARE_CHANGED context flag"); +} + +/****************************************************************************/ +/* Tests for kernel space functions */ + +static void secdata_kernel_tests(void) +{ + /* Not present is an error */ + reset_common_data(1, TPM_E_BADINDEX); + TEST_EQ(secdata_kernel_read(ctx), TPM_E_BADINDEX, + "secdata_kernel_read(), not present"); + TEST_STR_EQ(mock_calls, +#ifndef TPM2_MODE + "TlclGetPermissions(0x1008)\n", +#else "TlclRead(0x1008, 13)\n", - "tlcl calls"); - TEST_EQ(version, 0x87654321, "RollbackKernelRead() version"); +#endif + " tlcl calls"); - /* 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); +#ifndef TPM2_MODE + /* Bad permissions */ + reset_common_data(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_EQ(secdata_kernel_read(ctx), TPM_E_CORRUPTED_STATE, + "secdata_kernel_read(), bad permissions"); + TEST_STR_EQ(mock_calls, + "TlclGetPermissions(0x1008)\n", + " tlcl calls"); +#endif + + /* Good permissions, read failure */ +#ifndef TPM2_MODE + int read_failure_on_call = 2; +#else + int read_failure_on_call = 1; +#endif + reset_common_data(read_failure_on_call, TPM_E_IOERROR); + TEST_EQ(secdata_kernel_read(ctx), TPM_E_IOERROR, + "secdata_kernel_read(), good permissions, failure"); TEST_STR_EQ(mock_calls, +#ifndef TPM2_MODE "TlclGetPermissions(0x1008)\n" - "TlclRead(0x1008, 13)\n" - "TlclWrite(0x1008, 13)\n", - "tlcl calls"); +#endif + "TlclRead(0x1008, 13)\n", + " tlcl calls"); + + /* Good permissions, read success, bad CRC */ + reset_common_data(0, 0); + mock_bad_crc = 1; + TEST_EQ(secdata_kernel_read(ctx), TPM_E_CORRUPTED_STATE, + "secdata_kernel_read(), read success, bad CRC"); + TEST_STR_EQ(mock_calls, +#ifndef TPM2_MODE + "TlclGetPermissions(0x1008)\n" +#endif + "TlclRead(0x1008, 13)\n", + " tlcl calls"); - ResetMocks(1, TPM_E_IOERROR); - TEST_EQ(RollbackKernelWrite(123), TPM_E_IOERROR, - "RollbackKernelWrite() error"); + /* Good permissions, read success */ + reset_common_data(0, 0); + TEST_SUCC(secdata_kernel_read(ctx), + "secdata_kernel_read(), good permissions, success"); + TEST_STR_EQ(mock_calls, +#ifndef TPM2_MODE + "TlclGetPermissions(0x1008)\n" +#endif + "TlclRead(0x1008, 13)\n", + " tlcl calls"); + TEST_EQ(memcmp(ctx->secdata_kernel, &mock_rsk, + sizeof(ctx->secdata_kernel)), 0, " data"); + + /* Write with no new changes */ + reset_common_data(0, 0); + ctx->flags &= ~VB2_CONTEXT_SECDATA_KERNEL_CHANGED; + TEST_SUCC(secdata_kernel_write(ctx), + "secdata_kernel_write(), no changes, success"); + TEST_STR_EQ(mock_calls, + "", + " tlcl calls"); - /* Test lock (recovery off) */ - ResetMocks(1, TPM_E_IOERROR); - TEST_EQ(RollbackKernelLock(0), TPM_E_IOERROR, - "RollbackKernelLock() error"); + /* Write failure */ + reset_common_data(1, TPM_E_IOERROR); + TEST_EQ(secdata_kernel_write(ctx), TPM_E_IOERROR, + "secdata_kernel_write(), failure"); + TEST_STR_EQ(mock_calls, + "TlclWrite(0x1008, 13)\n", + " tlcl calls"); + TEST_NEQ(ctx->flags & VB2_CONTEXT_SECDATA_KERNEL_CHANGED, 0, + " should leave SECDATA_KERNEL_CHANGED context flag"); + + /* Write success and readback */ + reset_common_data(0, 0); + memset(ctx->secdata_kernel, 0xaa, sizeof(ctx->secdata_kernel)); + TEST_SUCC(secdata_kernel_write(ctx), + "secdata_kernel_write(), failure"); + TEST_STR_EQ(mock_calls, + "TlclWrite(0x1008, 13)\n", + " tlcl calls"); + memset(ctx->secdata_kernel, 0xaa, sizeof(ctx->secdata_kernel)); + TEST_EQ(memcmp(ctx->secdata_kernel, &mock_rsk, + sizeof(ctx->secdata_kernel)), 0, + " unchanged on readback"); + TEST_EQ(ctx->flags & VB2_CONTEXT_SECDATA_KERNEL_CHANGED, 0, + " should reset SECDATA_KERNEL_CHANGED context flag"); + + /* Lock in normal mode with failure */ + reset_common_data(1, TPM_E_AREA_LOCKED); + TEST_EQ(secdata_kernel_lock(ctx), TPM_E_AREA_LOCKED, + "secdata_kernel_lock(), lock failure"); + TEST_STR_EQ(mock_calls, + "TlclLockPhysicalPresence()\n", + " tlcl calls"); - /* 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"); + /* Lock in normal mode */ + reset_common_data(0, 0); + TEST_SUCC(secdata_kernel_lock(ctx), + "secdata_kernel_lock(), success (locked)"); + TEST_STR_EQ(mock_calls, + "TlclLockPhysicalPresence()\n", + " tlcl calls"); - ResetMocks(0, 0); - TEST_EQ(RollbackKernelLock(0), 0, "RollbackKernelLock()"); + /* Lock after already locked (only one TlclLockPhysicalPresence). */ + reset_common_data(0, 0); + TEST_SUCC(secdata_kernel_lock(ctx), + "secdata_kernel_lock(), lock first run"); + TEST_SUCC(secdata_kernel_lock(ctx), + "secdata_kernel_lock(), already locked"); TEST_STR_EQ(mock_calls, "TlclLockPhysicalPresence()\n", - "tlcl calls"); + " tlcl calls"); } /****************************************************************************/ -/* Tests for RollbackFwmpRead() calls */ +/* Tests for fwmp space functions */ -static void RollbackFwmpTest(void) +static void secdata_fwmp_tests(void) { - struct RollbackSpaceFwmp fwmp; - struct RollbackSpaceFwmp fwmp_zero = {0}; + /* Read failure */ + reset_common_data(1, TPM_E_IOERROR); + TEST_EQ(secdata_fwmp_read(ctx), TPM_E_IOERROR, + "secdata_fwmp_read(), failure"); + TEST_STR_EQ(mock_calls, + "TlclRead(0x100a, 40)\n", + " tlcl calls"); + TEST_EQ(ctx->flags & VB2_CONTEXT_NO_SECDATA_FWMP, 0, + " should leave NO_SECDATA_FWMP context flag"); + + /* Normal read, bad CRC */ + reset_common_data(0, 0); + mock_bad_crc = 1; + TEST_EQ(secdata_fwmp_read(ctx), TPM_E_CORRUPTED_STATE, + "secdata_fwmp_read(), success, bad CRC"); + TEST_STR_EQ(mock_calls, + "TlclRead(0x100a, 40)\n", + " tlcl calls"); + TEST_EQ(ctx->flags & VB2_CONTEXT_NO_SECDATA_FWMP, 0, + " should leave NO_SECDATA_FWMP context flag"); /* Normal read */ - ResetMocks(0, 0); - TEST_EQ(RollbackFwmpRead(&fwmp), 0, "RollbackFwmpRead()"); + reset_common_data(0, 0); + TEST_SUCC(secdata_fwmp_read(ctx), + "secdata_fwmp_read(), success"); TEST_STR_EQ(mock_calls, "TlclRead(0x100a, 40)\n", " tlcl calls"); - TEST_EQ(0, memcmp(&fwmp, &mock_fwmp, sizeof(fwmp)), " data"); + TEST_EQ(memcmp(ctx->secdata_fwmp, &mock_fwmp, + mock_fwmp_real_size), 0, " data"); + TEST_EQ(ctx->flags & VB2_CONTEXT_NO_SECDATA_FWMP, 0, + " should leave NO_SECDATA_FWMP context flag"); /* Read error */ - ResetMocks(1, TPM_E_IOERROR); - TEST_EQ(RollbackFwmpRead(&fwmp), TPM_E_IOERROR, - "RollbackFwmpRead() error"); + reset_common_data(1, TPM_E_IOERROR); + TEST_EQ(secdata_fwmp_read(ctx), TPM_E_IOERROR, + "secdata_fwmp_read(), error"); TEST_STR_EQ(mock_calls, "TlclRead(0x100a, 40)\n", " tlcl calls"); - TEST_EQ(0, memcmp(&fwmp, &fwmp_zero, sizeof(fwmp)), " data clear"); + TEST_EQ(ctx->flags & VB2_CONTEXT_NO_SECDATA_FWMP, 0, + " should leave NO_SECDATA_FWMP context flag"); - /* Not present isn't an error; just returns empty data */ - ResetMocks(1, TPM_E_BADINDEX); - TEST_EQ(RollbackFwmpRead(&fwmp), 0, "RollbackFwmpRead() not present"); + /* Not present isn't an error; just sets context flag */ + reset_common_data(1, TPM_E_BADINDEX); + TEST_SUCC(secdata_fwmp_read(ctx), "secdata_fwmp_read(), 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_NEQ(ctx->flags & VB2_CONTEXT_NO_SECDATA_FWMP, 0, + " should set NO_SECDATA_FWMP context flag"); + + /* Struct size too large, then bad CRC */ + reset_common_data(0, 0); + mock_fwmp_real_size += 4; + mock_bad_crc = 1; + TEST_EQ(secdata_fwmp_read(ctx), TPM_E_CORRUPTED_STATE, + "secdata_fwmp_read(), bigger, bad CRC"); 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"); + TEST_EQ(ctx->flags & VB2_CONTEXT_NO_SECDATA_FWMP, 0, + " should leave NO_SECDATA_FWMP context flag"); - /* 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"); + /* Struct size too large */ + reset_common_data(0, 0); + mock_fwmp_real_size += 4; + TEST_SUCC(secdata_fwmp_read(ctx), "secdata_fwmp_read(), bigger"); 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"); + TEST_EQ(memcmp(ctx->secdata_fwmp, &mock_fwmp, + mock_fwmp_real_size), 0, " data"); + TEST_EQ(ctx->flags & VB2_CONTEXT_NO_SECDATA_FWMP, 0, + " should leave NO_SECDATA_FWMP context flag"); } int main(int argc, char* argv[]) { - FirmwareSpaceTest(); - KernelSpaceTest(); - MiscTest(); - RollbackKernelTest(); - RollbackFwmpTest(); + misc_tests(); + secdata_firmware_tests(); + secdata_kernel_tests(); + secdata_fwmp_tests(); return gTestSuccess ? 0 : 255; } diff --git a/tests/test_common.h b/tests/test_common.h index 17689b71..e0d8ef3b 100644 --- a/tests/test_common.h +++ b/tests/test_common.h @@ -109,7 +109,7 @@ int test_false(int result, #result " == false", \ comment) -/* Return 1 if result is 0 (VB_ERROR_SUCCESS / VB2_SUCCESS), else return 0. +/* Return 1 if result is 0 (VB2_SUCCESS or other), else return 0. * Also update the global gTestSuccess flag if test fails. */ int test_succ(int result, const char *preamble, const char *desc, const char *comment); diff --git a/tests/vboot_api_devmode_tests.c b/tests/vboot_api_devmode_tests.c index 6cbcedec..36983d1f 100644 --- a/tests/vboot_api_devmode_tests.c +++ b/tests/vboot_api_devmode_tests.c @@ -122,6 +122,9 @@ static void ResetMocks(void) sd = vb2_get_sd(ctx); sd->vbsd = shared; + ctx->flags |= VB2_CONTEXT_NO_SECDATA_FWMP; + sd->status |= VB2_SD_STATUS_SECDATA_FWMP_INIT; + memset(&gbb, 0, sizeof(gbb)); memset(&shared_data, 0, sizeof(shared_data)); @@ -149,12 +152,7 @@ struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c) return &gbb; } -vb2_error_t VbExNvStorageRead(uint8_t* buf) -{ - return VB2_SUCCESS; -} - -vb2_error_t VbExNvStorageWrite(const uint8_t* buf) +vb2_error_t vb2_commit_data(struct vb2_context *c) { return VB2_SUCCESS; } diff --git a/tests/vboot_api_kernel2_tests.c b/tests/vboot_api_kernel2_tests.c index 50ee0752..6d8946ee 100644 --- a/tests/vboot_api_kernel2_tests.c +++ b/tests/vboot_api_kernel2_tests.c @@ -9,6 +9,7 @@ #include "2misc.h" #include "2nvstorage.h" #include "2secdata.h" +#include "2secdata_struct.h" #include "host_common.h" #include "load_kernel_fw.h" #include "secdata_tpm.h" @@ -30,6 +31,7 @@ static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE] static struct vb2_context *ctx; static struct vb2_shared_data *sd; static struct vb2_gbb_header gbb; +static struct vb2_secdata_fwmp *fwmp; static int audio_looping_calls_left; static uint32_t vbtlk_retval; @@ -82,7 +84,6 @@ static void MockGpioAfter(uint32_t ticks, uint32_t gpio_flags) static void ResetMocks(void) { vb2_init_ui(); - memset(VbApiKernelGetFwmp(), 0, sizeof(struct RollbackSpaceFwmp)); memset(&shared_data, 0, sizeof(shared_data)); VbSharedDataInit(shared, sizeof(shared_data)); @@ -97,6 +98,10 @@ static void ResetMocks(void) sd->vbsd = shared; sd->flags |= VB2_SD_FLAG_DISPLAY_AVAILABLE; + /* CRC will be invalid after here, but nobody's checking */ + sd->status |= VB2_SD_STATUS_SECDATA_FWMP_INIT; + fwmp = (struct vb2_secdata_fwmp *)ctx->secdata_fwmp; + memset(&gbb, 0, sizeof(gbb)); audio_looping_calls_left = 30; @@ -125,7 +130,8 @@ static void ResetMocks(void) } /* Mock functions */ -uint32_t RollbackKernelLock(int recovery_mode) + +uint32_t secdata_kernel_lock(struct vb2_context *c) { return TPM_SUCCESS; } @@ -252,9 +258,9 @@ vb2_error_t VbDisplayScreen(struct vb2_context *c, uint32_t screen, int force, return VB2_SUCCESS; } -vb2_error_t SetVirtualDevMode(int val) +vb2_error_t vb2_enable_developer_mode(struct vb2_context *c) { - virtdev_set = val; + virtdev_set = 1; return virtdev_retval; } @@ -718,7 +724,7 @@ static void VbBootDevTest(void) /* Enter altfw menu and select firmware 0 */ ResetMocks(); - VbApiKernelGetFwmp()->flags |= FWMP_DEV_ENABLE_LEGACY; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_LEGACY; mock_keypress[0] = VB_KEY_CTRL('L'); mock_keypress[1] = '0'; TEST_EQ(VbBootDeveloper(ctx), 1002, @@ -750,7 +756,7 @@ static void VbBootDevTest(void) TEST_EQ(altfw_num, key - '0', " check altfw_num"); ResetMocks(); - VbApiKernelGetFwmp()->flags |= FWMP_DEV_ENABLE_LEGACY; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_LEGACY; mock_keypress[0] = key; TEST_EQ(VbBootDeveloper(ctx), 1002, "Ctrl+L fwmp legacy"); @@ -779,7 +785,7 @@ static void VbBootDevTest(void) /* Ctrl+U enabled via FWMP */ ResetMocks(); - VbApiKernelGetFwmp()->flags |= FWMP_DEV_ENABLE_USB; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_USB; mock_keypress[0] = VB_KEY_CTRL('U'); vbtlk_retval = VB2_SUCCESS - VB_DISK_FLAG_REMOVABLE; TEST_EQ(VbBootDeveloper(ctx), 0, "Ctrl+U force USB"); @@ -984,7 +990,7 @@ static void VbBootDevTest(void) /* If dev mode is disabled, goes to TONORM screen repeatedly */ ResetMocks(); - VbApiKernelGetFwmp()->flags |= FWMP_DEV_DISABLE_BOOT; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_DISABLE_BOOT; mock_keypress[0] = VB_KEY_ESC; /* Just causes TONORM again */ mock_keypress[1] = VB_KEY_ENTER; TEST_EQ(VbBootDeveloper(ctx), VBERROR_REBOOT_REQUIRED, @@ -1001,7 +1007,7 @@ static void VbBootDevTest(void) /* Shutdown requested when dev disabled */ ResetMocks(); shared->flags = VBSD_BOOT_DEV_SWITCH_ON; - VbApiKernelGetFwmp()->flags |= FWMP_DEV_DISABLE_BOOT; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_DISABLE_BOOT; MockGpioAfter(1, GPIO_SHUTDOWN); TEST_EQ(VbBootDeveloper(ctx), VBERROR_SHUTDOWN_REQUESTED, @@ -1012,7 +1018,7 @@ static void VbBootDevTest(void) /* Shutdown requested by keyboard when dev disabled */ ResetMocks(); shared->flags = VBSD_BOOT_DEV_SWITCH_ON; - VbApiKernelGetFwmp()->flags |= FWMP_DEV_DISABLE_BOOT; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_DISABLE_BOOT; mock_keypress[0] = VB_BUTTON_POWER_SHORT_PRESS; TEST_EQ(VbBootDeveloper(ctx), VBERROR_SHUTDOWN_REQUESTED, diff --git a/tests/vboot_api_kernel4_tests.c b/tests/vboot_api_kernel4_tests.c index c168f82d..c0a10727 100644 --- a/tests/vboot_api_kernel4_tests.c +++ b/tests/vboot_api_kernel4_tests.c @@ -21,27 +21,31 @@ #include "vboot_common.h" #include "vboot_kernel.h" #include "vboot_struct.h" +#include "vboot_test.h" /* Mock data */ static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE] __attribute__((aligned(VB2_WORKBUF_ALIGN))); static struct vb2_context *ctx; -static struct vb2_context ctx_nvram_backend; static struct vb2_shared_data *sd; static VbSelectAndLoadKernelParams kparams; static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE]; static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data; static struct vb2_gbb_header gbb; -static uint32_t rkr_version; +static uint32_t kernel_version; static uint32_t new_version; -static struct RollbackSpaceFwmp rfr_fwmp; -static int rkr_retval, rkw_retval, rkl_retval, rfr_retval; +static uint8_t fwmp_buf[VB2_SECDATA_FWMP_MIN_SIZE]; +static uint32_t kernel_read_retval; +static uint32_t kernel_write_retval; +static uint32_t kernel_lock_retval; +static uint32_t fwmp_read_retval; static vb2_error_t vbboot_retval; static uint32_t mock_switches[8]; static uint32_t mock_switches_count; static int mock_switches_are_stuck; +static int commit_data_called; /* Reset mock data (for use before each test) */ static void ResetMocks(void) @@ -57,26 +61,22 @@ static void ResetMocks(void) "vb2api_init failed"); sd = vb2_get_sd(ctx); sd->flags |= VB2_SD_FLAG_DISPLAY_AVAILABLE; + ctx->flags |= VB2_CONTEXT_NO_SECDATA_FWMP; - /* - * ctx_nvram_backend is only used as an NVRAM backend (see - * VbExNvStorageRead and VbExNvStorageWrite), and with - * vb2_set_nvdata and nv2_get_nvdata to manually read and tweak - * contents. No other initialization is needed. - */ - memset(&ctx_nvram_backend, 0, sizeof(ctx_nvram_backend)); - vb2_nv_init(&ctx_nvram_backend); - vb2_nv_set(&ctx_nvram_backend, VB2_NV_KERNEL_MAX_ROLLFORWARD, - 0xffffffff); + vb2_nv_init(ctx); + vb2_nv_set(ctx, VB2_NV_KERNEL_MAX_ROLLFORWARD, 0xffffffff); + commit_data_called = 0; memset(&shared_data, 0, sizeof(shared_data)); VbSharedDataInit(shared, sizeof(shared_data)); - memset(&rfr_fwmp, 0, sizeof(rfr_fwmp)); - rfr_retval = TPM_SUCCESS; + memset(&fwmp_buf, 0, sizeof(fwmp_buf)); + fwmp_read_retval = TPM_SUCCESS; - rkr_version = new_version = 0x10002; - rkr_retval = rkw_retval = rkl_retval = VB2_SUCCESS; + kernel_version = new_version = 0x10002; + kernel_read_retval = TPM_SUCCESS; + kernel_write_retval = TPM_SUCCESS; + kernel_lock_retval = TPM_SUCCESS; vbboot_retval = VB2_SUCCESS; memset(mock_switches, 0, sizeof(mock_switches)); @@ -86,41 +86,59 @@ static void ResetMocks(void) /* Mock functions */ -vb2_error_t VbExNvStorageRead(uint8_t *buf) +vb2_error_t vb2ex_commit_data(struct vb2_context *c) { - memcpy(buf, ctx_nvram_backend.nvdata, - vb2_nv_get_size(&ctx_nvram_backend)); + commit_data_called = 1; return VB2_SUCCESS; } -vb2_error_t VbExNvStorageWrite(const uint8_t *buf) +uint32_t secdata_firmware_write(struct vb2_context *c) { - memcpy(ctx_nvram_backend.nvdata, buf, - vb2_nv_get_size(&ctx_nvram_backend)); - return VB2_SUCCESS; + return TPM_SUCCESS; +} + +uint32_t secdata_kernel_read(struct vb2_context *c) +{ + return kernel_read_retval; +} + +uint32_t secdata_kernel_write(struct vb2_context *c) +{ + return kernel_write_retval; } -uint32_t RollbackKernelRead(uint32_t *version) +uint32_t secdata_kernel_lock(struct vb2_context *c) { - *version = rkr_version; - return rkr_retval; + return kernel_lock_retval; } -uint32_t RollbackKernelWrite(uint32_t version) +uint32_t secdata_fwmp_read(struct vb2_context *c) { - rkr_version = version; - return rkw_retval; + memcpy(&c->secdata_fwmp, &fwmp_buf, sizeof(fwmp_buf)); + return fwmp_read_retval; } -uint32_t RollbackKernelLock(int recovery_mode) +vb2_error_t vb2_secdata_firmware_init(struct vb2_context *c) { - return rkl_retval; + return VB2_SUCCESS; +} + +vb2_error_t vb2_secdata_kernel_init(struct vb2_context *c) +{ + return VB2_SUCCESS; } -uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp) +uint32_t vb2_secdata_kernel_get(struct vb2_context *c, + enum vb2_secdata_kernel_param param) { - memcpy(fwmp, &rfr_fwmp, sizeof(*fwmp)); - return rfr_retval; + return kernel_version; +} + +void vb2_secdata_kernel_set(struct vb2_context *c, + enum vb2_secdata_kernel_param param, + uint32_t value) +{ + kernel_version = value; } vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t get_info_flags) @@ -164,8 +182,10 @@ vb2_error_t VbBootDiagnostic(struct vb2_context *c) static void test_slk(vb2_error_t retval, int recovery_reason, const char *desc) { TEST_EQ(VbSelectAndLoadKernel(ctx, shared, &kparams), retval, desc); - TEST_EQ(vb2_nv_get(&ctx_nvram_backend, VB2_NV_RECOVERY_REQUEST), + TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), recovery_reason, " recovery reason"); + if (recovery_reason) + TEST_TRUE(commit_data_called, " didn't commit nvdata"); } uint32_t VbExGetSwitches(uint32_t request_mask) @@ -189,7 +209,7 @@ static void VbSlkTest(void) { ResetMocks(); test_slk(0, 0, "Normal"); - TEST_EQ(rkr_version, 0x10002, " version"); + TEST_EQ(kernel_version, 0x10002, " version"); /* * If shared->flags doesn't ask for software sync, we won't notice @@ -206,42 +226,43 @@ static void VbSlkTest(void) /* Rollback kernel version */ ResetMocks(); - rkr_retval = 123; - test_slk(VBERROR_TPM_READ_KERNEL, + kernel_read_retval = 123; + test_slk(VB2_ERROR_SECDATA_KERNEL_READ, VB2_RECOVERY_RW_TPM_R_ERROR, "Read kernel rollback"); ResetMocks(); new_version = 0x20003; test_slk(0, 0, "Roll forward"); - TEST_EQ(rkr_version, 0x20003, " version"); + TEST_EQ(kernel_version, 0x20003, " version"); ResetMocks(); - vb2_nv_set(&ctx_nvram_backend, VB2_NV_FW_RESULT, VB2_FW_RESULT_TRYING); + vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_TRYING); new_version = 0x20003; test_slk(0, 0, "Don't roll forward kernel when trying new FW"); - TEST_EQ(rkr_version, 0x10002, " version"); + TEST_EQ(kernel_version, 0x10002, " version"); ResetMocks(); - vb2_nv_set(&ctx_nvram_backend, VB2_NV_KERNEL_MAX_ROLLFORWARD, 0x30005); + vb2_nv_set(ctx, VB2_NV_KERNEL_MAX_ROLLFORWARD, 0x30005); new_version = 0x40006; test_slk(0, 0, "Limit max roll forward"); - TEST_EQ(rkr_version, 0x30005, " version"); + TEST_EQ(kernel_version, 0x30005, " version"); ResetMocks(); - vb2_nv_set(&ctx_nvram_backend, VB2_NV_KERNEL_MAX_ROLLFORWARD, 0x10001); + vb2_nv_set(ctx, VB2_NV_KERNEL_MAX_ROLLFORWARD, 0x10001); new_version = 0x40006; test_slk(0, 0, "Max roll forward can't rollback"); - TEST_EQ(rkr_version, 0x10002, " version"); + TEST_EQ(kernel_version, 0x10002, " version"); + ResetMocks(); new_version = 0x20003; - rkw_retval = 123; - test_slk(VBERROR_TPM_WRITE_KERNEL, + kernel_write_retval = 123; + test_slk(VB2_ERROR_SECDATA_KERNEL_WRITE, VB2_RECOVERY_RW_TPM_W_ERROR, "Write kernel rollback"); ResetMocks(); - rkl_retval = 123; - test_slk(VBERROR_TPM_LOCK_KERNEL, + kernel_lock_retval = 123; + test_slk(VB2_ERROR_SECDATA_KERNEL_LOCK, VB2_RECOVERY_RW_TPM_L_ERROR, "Lock kernel rollback"); /* Boot normal */ @@ -253,12 +274,14 @@ static void VbSlkTest(void) if (DIAGNOSTIC_UI) { ResetMocks(); mock_switches[1] = VB_SWITCH_FLAG_PHYS_PRESENCE_PRESSED; - vb2_nv_set(&ctx_nvram_backend, VB2_NV_DIAG_REQUEST, 1); + vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1); vbboot_retval = -4; test_slk(VB2_ERROR_MOCK, 0, "Normal boot with diag"); - TEST_EQ(vb2_nv_get(&ctx_nvram_backend, VB2_NV_DIAG_REQUEST), + TEST_EQ(vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST), 0, " diag not requested"); + TEST_TRUE(commit_data_called, + " didn't commit nvdata"); } /* Boot dev */ @@ -271,7 +294,7 @@ static void VbSlkTest(void) shared->flags |= VBSD_BOOT_DEV_SWITCH_ON; new_version = 0x20003; test_slk(0, 0, "Dev doesn't roll forward"); - TEST_EQ(rkr_version, 0x10002, " version"); + TEST_EQ(kernel_version, 0x10002, " version"); /* Boot recovery */ ResetMocks(); @@ -283,11 +306,13 @@ static void VbSlkTest(void) shared->recovery_reason = 123; new_version = 0x20003; test_slk(0, 0, "Recovery doesn't roll forward"); - TEST_EQ(rkr_version, 0x10002, " version"); + TEST_EQ(kernel_version, 0x10002, " version"); ResetMocks(); shared->recovery_reason = 123; - rkr_retval = rkw_retval = rkl_retval = VB2_ERROR_MOCK; + kernel_read_retval = TPM_E_IOERROR; + kernel_write_retval = TPM_E_IOERROR; + kernel_lock_retval = TPM_E_IOERROR; test_slk(0, 0, "Recovery ignore TPM errors"); ResetMocks(); diff --git a/tests/vboot_detach_menu_tests.c b/tests/vboot_detach_menu_tests.c index f0440cfb..d85acbc6 100644 --- a/tests/vboot_detach_menu_tests.c +++ b/tests/vboot_detach_menu_tests.c @@ -9,6 +9,7 @@ #include "2misc.h" #include "2nvstorage.h" #include "2secdata.h" +#include "2secdata_struct.h" #include "host_common.h" #include "load_kernel_fw.h" #include "secdata_tpm.h" @@ -32,6 +33,7 @@ static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE] static struct vb2_context *ctx; static struct vb2_shared_data *sd; static struct vb2_gbb_header gbb; +static struct vb2_secdata_fwmp *fwmp; static int shutdown_request_calls_left; static int audio_looping_calls_left; @@ -61,8 +63,6 @@ static int vbexaltfwmask_called; /* Reset mock data (for use before each test) */ static void ResetMocks(void) { - memset(VbApiKernelGetFwmp(), 0, sizeof(struct RollbackSpaceFwmp)); - memset(&shared_data, 0, sizeof(shared_data)); VbSharedDataInit(shared, sizeof(shared_data)); shared->flags = VBSD_BOOT_FIRMWARE_VBOOT2; @@ -76,6 +76,10 @@ static void ResetMocks(void) sd = vb2_get_sd(ctx); sd->vbsd = shared; + /* CRC will be invalid after here, but nobody's checking */ + sd->status |= VB2_SD_STATUS_SECDATA_FWMP_INIT; + fwmp = (struct vb2_secdata_fwmp *)ctx->secdata_fwmp; + memset(&gbb, 0, sizeof(gbb)); /* In recovery we have 50 keyscans per disk scan, this must be high. */ @@ -124,7 +128,8 @@ static void ResetMocksForManualRecovery(void) } /* Mock functions */ -uint32_t RollbackKernelLock(int recovery_mode) + +uint32_t secdata_kernel_lock(struct vb2_context *c) { return TPM_SUCCESS; } @@ -252,9 +257,9 @@ vb2_error_t VbExBeep(uint32_t msec, uint32_t frequency) return VB2_SUCCESS; } -vb2_error_t SetVirtualDevMode(int val) +vb2_error_t vb2_enable_developer_mode(struct vb2_context *c) { - virtdev_set = val; + virtdev_set = 1; return virtdev_retval; } @@ -665,7 +670,7 @@ static void VbBootDevTest(void) /* Ctrl+L boots legacy if enabled by FWMP */ ResetMocksForDeveloper(); - VbApiKernelGetFwmp()->flags |= FWMP_DEV_ENABLE_LEGACY; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_LEGACY; mock_keypress[0] = VB_KEY_CTRL('L'); mock_keypress[1] = VB_BUTTON_POWER_SHORT_PRESS; TEST_EQ(VbBootDeveloperMenu(ctx), vbtlk_retval_fixed, @@ -755,7 +760,7 @@ static void VbBootDevTest(void) /* Ctrl+U enabled via FWMP */ ResetMocksForDeveloper(); - VbApiKernelGetFwmp()->flags |= FWMP_DEV_ENABLE_USB; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_USB; mock_keypress[0] = VB_KEY_CTRL('U'); vbtlk_retval[0] = VB2_SUCCESS - VB_DISK_FLAG_REMOVABLE; TEST_EQ(VbBootDeveloperMenu(ctx), VB2_SUCCESS, "Ctrl+U force USB"); @@ -1148,7 +1153,7 @@ static void VbBootDevTest(void) /* If dev mode is disabled, goes to TONORM screen repeatedly */ ResetMocksForDeveloper(); - VbApiKernelGetFwmp()->flags |= FWMP_DEV_DISABLE_BOOT; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_DISABLE_BOOT; audio_looping_calls_left = 1; /* Confirm audio doesn't tick down. */ i = 0; mock_keypress[i++] = VB_KEY_CTRL('D'); /* Just stays on TONORM and flashes */ @@ -1202,7 +1207,7 @@ static void VbBootDevTest(void) /* Shutdown requested when dev disabled */ ResetMocksForDeveloper(); - VbApiKernelGetFwmp()->flags |= FWMP_DEV_DISABLE_BOOT; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_DISABLE_BOOT; shutdown_request_calls_left = 1; TEST_EQ(VbBootDeveloperMenu(ctx), VBERROR_SHUTDOWN_REQUESTED, "Shutdown requested when dev disabled"); @@ -1218,7 +1223,7 @@ static void VbBootDevTest(void) /* Explicit Power Off when dev disabled */ ResetMocksForDeveloper(); - VbApiKernelGetFwmp()->flags |= FWMP_DEV_DISABLE_BOOT; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_DISABLE_BOOT; i = 0; mock_keypress[i++] = VB_BUTTON_VOL_DOWN_SHORT_PRESS; // Power Off mock_keypress[i++] = VB_BUTTON_POWER_SHORT_PRESS; diff --git a/tests/vboot_display_tests.c b/tests/vboot_display_tests.c index 58ccda07..7565a196 100644 --- a/tests/vboot_display_tests.c +++ b/tests/vboot_display_tests.c @@ -16,6 +16,7 @@ #include "2struct.h" #include "2sysincludes.h" #include "host_common.h" +#include "secdata_tpm.h" #include "test_common.h" #include "vboot_common.h" #include "vboot_display.h" @@ -72,6 +73,11 @@ vb2_error_t VbExDisplayDebugInfo(const char *info_str, int full_info) return VB2_SUCCESS; } +vb2_error_t vb2_commit_data(struct vb2_context *c) +{ + return VB2_SUCCESS; +} + /* Test displaying debug info */ static void DebugInfoTest(void) { diff --git a/tests/vboot_kernel_tests.c b/tests/vboot_kernel_tests.c index b43a2acd..86afcb8d 100644 --- a/tests/vboot_kernel_tests.c +++ b/tests/vboot_kernel_tests.c @@ -63,7 +63,7 @@ static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data; static LoadKernelParams lkp; static struct vb2_keyblock kbh; static VbKernelPreambleHeader kph; -static struct RollbackSpaceFwmp fwmp; +static struct vb2_secdata_fwmp *fwmp; static uint8_t mock_disk[MOCK_SECTOR_SIZE * MOCK_SECTOR_COUNT]; static GptHeader *mock_gpt_primary = (GptHeader*)&mock_disk[MOCK_SECTOR_SIZE * 1]; @@ -164,9 +164,6 @@ static void ResetMocks(void) kph.bootloader_address = 0xbeadd008; kph.bootloader_size = 0x1234; - memset(&fwmp, 0, sizeof(fwmp)); - memcpy(fwmp.dev_key_hash, mock_digest, sizeof(fwmp.dev_key_hash)); - memset(mock_parts, 0, sizeof(mock_parts)); mock_parts[0].start = 100; mock_parts[0].size = 150; /* 75 KB */ @@ -181,6 +178,11 @@ static void ResetMocks(void) struct vb2_shared_data *sd = vb2_get_sd(ctx); sd->vbsd = shared; + /* CRC will be invalid after here, but nobody's checking */ + sd->status |= VB2_SD_STATUS_SECDATA_FWMP_INIT; + fwmp = (struct vb2_secdata_fwmp *)ctx->secdata_fwmp; + memcpy(&fwmp->dev_key_hash, mock_digest, sizeof(fwmp->dev_key_hash)); + // TODO: more workbuf fields - flags, secdata_firmware, secdata_kernel } @@ -670,8 +672,7 @@ static void LoadKernelTest(void) ResetMocks(); ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - lkp.fwmp = &fwmp; - fwmp.flags |= FWMP_DEV_ENABLE_OFFICIAL_ONLY; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY; keyblock_verify_fail = 1; TestLoadKernel(VBERROR_INVALID_KERNEL_FOUND, "Fail keyblock dev sig fwmp"); @@ -761,17 +762,15 @@ static void LoadKernelTest(void) /* Check developer key hash - bad */ ResetMocks(); ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - lkp.fwmp = &fwmp; - fwmp.flags |= FWMP_DEV_USE_KEY_HASH; - fwmp.dev_key_hash[0]++; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_USE_KEY_HASH; + fwmp->dev_key_hash[0]++; TestLoadKernel(VBERROR_INVALID_KERNEL_FOUND, "Fail keyblock dev fwmp hash"); /* Check developer key hash - good */ ResetMocks(); ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; - lkp.fwmp = &fwmp; - fwmp.flags |= FWMP_DEV_USE_KEY_HASH; + fwmp->flags |= VB2_SECDATA_FWMP_DEV_USE_KEY_HASH; TestLoadKernel(0, "Good keyblock dev fwmp hash"); ResetMocks(); |