diff --git a/board/cr50/board.h b/board/cr50/board.h index 70e7a6f7ba..53411170de 100644 --- a/board/cr50/board.h +++ b/board/cr50/board.h @@ -41,6 +41,8 @@ #define CONFIG_WP_ALWAYS #define CONFIG_CMD_FLASH +#define CONFIG_CRC8 + /* We're using TOP_A for partition 0, TOP_B for partition 1 */ #define CONFIG_FLASH_NVMEM /* Offset to start of NvMem area from base of flash */ diff --git a/board/cr50/build.mk b/board/cr50/build.mk index 688f36882f..ef2299dccd 100644 --- a/board/cr50/build.mk +++ b/board/cr50/build.mk @@ -49,6 +49,7 @@ board-y += tpm2/stubs.o board-y += tpm2/tpm_state.o board-y += tpm2/trng.o board-y += tpm2/upgrade.o +board-y += tpm_nvmem_read.o board-y += wp.o # Build and link with an external library diff --git a/board/cr50/wp.c b/board/cr50/wp.c index 84ca26d1a0..b3c6007bf8 100644 --- a/board/cr50/wp.c +++ b/board/cr50/wp.c @@ -5,6 +5,7 @@ #include "common.h" #include "console.h" +#include "crc8.h" #include "extension.h" #include "gpio.h" #include "hooks.h" @@ -16,6 +17,7 @@ #include "system_chip.h" #include "task.h" #include "timer.h" +#include "tpm_nvmem_read.h" #include "tpm_registers.h" #include "util.h" @@ -252,9 +254,84 @@ static void init_console_lock_and_wp(void) /* This must run after initializing the NVMem partitions. */ DECLARE_HOOK(HOOK_INIT, init_console_lock_and_wp, HOOK_PRIO_DEFAULT+1); +/* + * These definitions and the structure layout were manually copied from + * src/platform/vboot_reference/firmware/lib/include/rollback_index.h. at + * git sha c7282f6. + */ +#define FWMP_NV_INDEX 0x100a +#define FWMP_HASH_SIZE 32 +#define FWMP_DEV_DISABLE_CCD_UNLOCK (1 << 6) + +/* 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]; +} __packed; + +static int lock_enforced(const struct RollbackSpaceFwmp *fwmp) +{ + uint8_t crc; + + /* Let's verify that the FWMP structure makes sense. */ + if (fwmp->struct_size != sizeof(*fwmp)) { + CPRINTS("%s: fwmp size mismatch (%d)\n", __func__, + fwmp->struct_size); + return 1; + } + + crc = crc8(&fwmp->struct_version, sizeof(struct RollbackSpaceFwmp) - + offsetof(struct RollbackSpaceFwmp, struct_version)); + if (fwmp->crc != crc) { + CPRINTS("%s: fwmp crc mismatch\n", __func__); + return 1; + } + + return !!(fwmp->flags & FWMP_DEV_DISABLE_CCD_UNLOCK); +} + +static int fwmp_allows_unlock; +void read_fwmp(void) +{ + /* Let's see if FWMP disables console activation. */ + struct RollbackSpaceFwmp fwmp; + + switch (read_tpm_nvmem(FWMP_NV_INDEX, + sizeof(struct RollbackSpaceFwmp), &fwmp)) { + default: + /* Something is messed up, let's not allow console unlock. */ + fwmp_allows_unlock = 0; + break; + + case tpm_read_not_found: + fwmp_allows_unlock = 1; + break; + + case tpm_read_success: + fwmp_allows_unlock = !lock_enforced(&fwmp); + break; + } + + CPRINTS("Console unlock %sallowed", fwmp_allows_unlock ? "" : "not "); +} + int console_is_restricted(void) { +#ifndef CR50_DEV + return fwmp_allows_unlock ? console_restricted_state : 1; +#else return console_restricted_state; +#endif } /****************************************************************************/ @@ -410,32 +487,32 @@ static const char warning[] = "\n\t!!! WARNING !!!\n\n" static int command_lock(int argc, char **argv) { - int enabled; + int enable; int i; -#ifndef CR50_DEV - /* Don't allow the console to be unlocked at all for prod images. */ - ASSERT(console_is_restricted() == 1); - if (argc > 1) - return EC_ERROR_ACCESS_DENIED; - - goto out; -#endif /* !defined(CR50_DEV) */ - if (argc > 1) { - if (!parse_bool(argv[1], &enabled)) + if (!parse_bool(argv[1], &enable)) return EC_ERROR_PARAM1; /* Changing nothing does nothing */ - if (enabled == console_is_restricted()) + if (enable == console_is_restricted()) goto out; /* Locking the console is always allowed */ - if (enabled) { + if (enable) { lock_the_console(); goto out; } + if (!fwmp_allows_unlock) { +#ifdef CR50_DEV + ccprintf("Ignoring FWMP unlock setting\n"); +#else + ccprintf("Managed device console can't be unlocked\n"); + goto out; +#endif + } + /* Don't count down if we know it's likely to fail */ if (unlock_in_progress) { ccprintf("An unlock process is already in progress\n"); diff --git a/board/cr50/wp.h b/board/cr50/wp.h index e2ae172df8..10169b793a 100644 --- a/board/cr50/wp.h +++ b/board/cr50/wp.h @@ -3,6 +3,9 @@ * found in the LICENSE file. */ +#ifndef __EC_BOARD_CR50_WP_H +#define __EC_BOARD_CR50_WP_H + #include "common.h" /** @@ -11,3 +14,11 @@ * @param asserted: 0 to disable write protect, otherwise enable write protect. */ void set_wp_state(int asserted); + +/** + * Read the FWMP value from TPM NVMEM and set the console restriction + * appropriately. + */ +void read_fwmp(void); + +#endif /* ! __EC_BOARD_CR50_WP_H */ diff --git a/common/tpm_registers.c b/common/tpm_registers.c index 6a914aabb0..c4353dd566 100644 --- a/common/tpm_registers.c +++ b/common/tpm_registers.c @@ -24,6 +24,7 @@ #include "tpm_registers.h" #include "util.h" #include "watchdog.h" +#include "wp.h" /* TPM2 library includes. */ #include "ExecCommand_fp.h" @@ -864,6 +865,10 @@ void tpm_task(void) */ if (command_code == TPM2_PCR_Read) system_process_retry_counter(); + + else if (command_code == TPM2_Startup) + read_fwmp(); + #ifdef CONFIG_EXTENSION_COMMAND if (!IS_CUSTOM_CODE(command_code)) #endif diff --git a/include/tpm_registers.h b/include/tpm_registers.h index 9812c7c131..ed26591791 100644 --- a/include/tpm_registers.h +++ b/include/tpm_registers.h @@ -69,5 +69,6 @@ struct tpm_cmd_header { * crosbug.com/p/55667 for detals. */ #define TPM2_PCR_Read 0x0000017e +#define TPM2_Startup 0x00000144 #endif /* __CROS_EC_TPM_REGISTERS_H */