summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2017-02-21 18:41:42 -0800
committerchrome-bot <chrome-bot@chromium.org>2017-05-31 00:24:01 -0700
commitfb5a05ab223b56b22a3e0978333586ec13604374 (patch)
treea8c04844e8051a08ffc55f851cd19ba77f21848f
parentbff0a8093402790f3f58af80eb09509c27cafdaf (diff)
downloadchrome-ec-fb5a05ab223b56b22a3e0978333586ec13604374.tar.gz
cr50: read fwmp and act on it when controlling console restrictions
It needs to be possible to prevent unlocking of CCD on enterprise enrolled devices, in particular to prevent users from moving into dev mode. A bit in the FWMP structure flags field was allocated for the purposes of preventing console unlock in those cases. This patch adds code to read the FWMP structure from the TPM NVMEM, verify it and determine if it should be possible to unlock the console. The restriction is not honored by Cr50 DBG images. The FWMP value is read only once per TPM reset, this means each time the admin console changes the relevant flag bit, the Chrome OS device has to be rebooted to pick up the new flag value. BRANCH=cr50 BUG=b:35587387,b:35587053 TEST=verified that FWMP is properly read and acted upon. Change-Id: I17e15ea2b2293a0c096858fba3ccc389452caede Reviewed-on: https://chromium-review.googlesource.com/457824 Commit-Ready: Vadim Bendebury <vbendeb@chromium.org> Tested-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-by: Mary Ruthven <mruthven@chromium.org>
-rw-r--r--board/cr50/board.h2
-rw-r--r--board/cr50/build.mk1
-rw-r--r--board/cr50/wp.c103
-rw-r--r--board/cr50/wp.h11
-rw-r--r--common/tpm_registers.c5
-rw-r--r--include/tpm_registers.h1
6 files changed, 110 insertions, 13 deletions
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 */