summaryrefslogtreecommitdiff
path: root/src/security/vboot
diff options
context:
space:
mode:
Diffstat (limited to 'src/security/vboot')
-rw-r--r--src/security/vboot/Kconfig17
-rw-r--r--src/security/vboot/Makefile.inc7
-rw-r--r--src/security/vboot/vboot_crtm.c144
-rw-r--r--src/security/vboot/vboot_crtm.h62
-rw-r--r--src/security/vboot/vboot_logic.c35
5 files changed, 249 insertions, 16 deletions
diff --git a/src/security/vboot/Kconfig b/src/security/vboot/Kconfig
index a3e9b863cf..a382e670c4 100644
--- a/src/security/vboot/Kconfig
+++ b/src/security/vboot/Kconfig
@@ -26,6 +26,22 @@ config VBOOT
if VBOOT
+config VBOOT_MEASURED_BOOT
+ bool "Enable Measured Boot"
+ default n
+ depends on !VBOOT_MOCK_SECDATA
+ depends on !VBOOT_RETURN_FROM_VERSTAGE
+ help
+ Enables measured boot mode in vboot (experimental)
+
+config VBOOT_MEASURED_BOOT_RUNTIME_DATA
+ string "Runtime data whitelist"
+ default ""
+ depends on VBOOT_MEASURED_BOOT
+ help
+ Runtime data whitelist of cbfs filenames. Needs to be a comma separated
+ list
+
config VBOOT_SLOTS_RW_A
bool "Firmware RO + RW_A"
help
@@ -37,7 +53,6 @@ config VBOOT_SLOTS_RW_AB
help
Have two update partitions beside the RO partition.
-
config VBOOT_VBNV_CMOS
bool
default n
diff --git a/src/security/vboot/Makefile.inc b/src/security/vboot/Makefile.inc
index 0c32d94fab..6d2096ddb0 100644
--- a/src/security/vboot/Makefile.inc
+++ b/src/security/vboot/Makefile.inc
@@ -69,6 +69,13 @@ romstage-y += vboot_common.c
ramstage-y += vboot_common.c
postcar-y += vboot_common.c
+ifeq ($(CONFIG_VBOOT_MEASURED_BOOT),y)
+verstage-y += vboot_crtm.c
+romstage-y += vboot_crtm.c
+ramstage-y += vboot_crtm.c
+postcar-y += vboot_crtm.c
+endif
+
bootblock-y += common.c
verstage-y += vboot_logic.c
verstage-y += common.c
diff --git a/src/security/vboot/vboot_crtm.c b/src/security/vboot/vboot_crtm.c
new file mode 100644
index 0000000000..768986f5cc
--- /dev/null
+++ b/src/security/vboot/vboot_crtm.c
@@ -0,0 +1,144 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2018 Facebook Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <console/console.h>
+#include <fmap.h>
+#include <security/vboot/vboot_crtm.h>
+#include <security/vboot/misc.h>
+
+uint32_t vboot_init_crtm(void)
+{
+ struct prog bootblock = PROG_INIT(PROG_BOOTBLOCK, "bootblock");
+ struct prog verstage =
+ PROG_INIT(PROG_VERSTAGE, CONFIG_CBFS_PREFIX "/verstage");
+ struct prog romstage =
+ PROG_INIT(PROG_ROMSTAGE, CONFIG_CBFS_PREFIX "/romstage");
+
+ /* measure bootblock from RO */
+ struct cbfsf bootblock_data;
+ struct region_device bootblock_fmap;
+ if (fmap_locate_area_as_rdev("BOOTBLOCK", &bootblock_fmap) == 0) {
+ if (tpm_measure_region(&bootblock_fmap,
+ TPM_CRTM_PCR,
+ prog_name(&bootblock)))
+ return VB2_ERROR_UNKNOWN;
+ } else {
+ if (cbfs_boot_locate(&bootblock_data,
+ prog_name(&bootblock), NULL) == 0) {
+ cbfs_file_data(prog_rdev(&bootblock), &bootblock_data);
+
+ if (tpm_measure_region(prog_rdev(&bootblock),
+ TPM_CRTM_PCR,
+ prog_name(&bootblock)))
+ return VB2_ERROR_UNKNOWN;
+ } else {
+ printk(BIOS_INFO,
+ "VBOOT: Couldn't measure bootblock into CRTM!\n");
+ return VB2_ERROR_UNKNOWN;
+ }
+ }
+
+ if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE)) {
+ struct cbfsf romstage_data;
+ /* measure romstage from RO */
+ if (cbfs_boot_locate(&romstage_data,
+ prog_name(&romstage), NULL) == 0) {
+ cbfs_file_data(prog_rdev(&romstage), &romstage_data);
+
+ if (tpm_measure_region(prog_rdev(&romstage),
+ TPM_CRTM_PCR,
+ CONFIG_CBFS_PREFIX "/romstage"))
+ return VB2_ERROR_UNKNOWN;
+ } else {
+ printk(BIOS_INFO,
+ "VBOOT: Couldn't measure %s into CRTM!\n",
+ CONFIG_CBFS_PREFIX "/romstage");
+ return VB2_ERROR_UNKNOWN;
+ }
+ }
+
+ if (IS_ENABLED(CONFIG_VBOOT_SEPARATE_VERSTAGE)) {
+ struct cbfsf verstage_data;
+ /* measure verstage from RO */
+ if (cbfs_boot_locate(&verstage_data,
+ prog_name(&verstage), NULL) == 0) {
+ cbfs_file_data(prog_rdev(&verstage), &verstage_data);
+
+ if (tpm_measure_region(prog_rdev(&verstage),
+ TPM_CRTM_PCR,
+ CONFIG_CBFS_PREFIX "/verstage"))
+ return VB2_ERROR_UNKNOWN;
+ } else {
+ printk(BIOS_INFO,
+ "VBOOT: Couldn't measure %s into CRTM!\n",
+ CONFIG_CBFS_PREFIX "/verstage");
+ return VB2_ERROR_UNKNOWN;
+ }
+ }
+
+ return VB2_SUCCESS;
+}
+
+static bool is_runtime_data(const char *name)
+{
+ const char *whitelist = CONFIG_VBOOT_MEASURED_BOOT_RUNTIME_DATA;
+ size_t whitelist_len = sizeof(CONFIG_VBOOT_MEASURED_BOOT_RUNTIME_DATA) - 1;
+ size_t name_len = strlen(name);
+ int i;
+
+ if (!whitelist_len || !name_len)
+ return false;
+
+ for (i = 0; (i + name_len) <= whitelist_len; i++) {
+ if (!strcmp(whitelist + i, name))
+ return true;
+ }
+
+ return false;
+}
+
+uint32_t vboot_measure_cbfs_hook(struct cbfsf *fh, const char *name)
+{
+ uint32_t pcr_index;
+ uint32_t cbfs_type;
+ struct region_device rdev;
+
+ if (!vb2_logic_executed())
+ return 0;
+
+ cbfsf_file_type(fh, &cbfs_type);
+ cbfs_file_data(&rdev, fh);
+
+ switch (cbfs_type) {
+ case CBFS_TYPE_MRC:
+ case CBFS_TYPE_MRC_CACHE:
+ pcr_index = TPM_RUNTIME_DATA_PCR;
+ break;
+ case CBFS_TYPE_STAGE:
+ case CBFS_TYPE_SELF:
+ case CBFS_TYPE_FIT:
+ pcr_index = TPM_CRTM_PCR;
+ break;
+ default:
+ if (is_runtime_data(name))
+ pcr_index = TPM_RUNTIME_DATA_PCR;
+ else
+ pcr_index = TPM_CRTM_PCR;
+ break;
+ }
+
+ return tpm_measure_region(&rdev, pcr_index,
+ name);
+}
diff --git a/src/security/vboot/vboot_crtm.h b/src/security/vboot/vboot_crtm.h
new file mode 100644
index 0000000000..84ee9e63b5
--- /dev/null
+++ b/src/security/vboot/vboot_crtm.h
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2018 Facebook Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SECURITY_VBOOT_CRTM_H__
+#define __SECURITY_VBOOT_CRTM_H__
+
+#include <program_loading.h>
+#include <security/tpm/tspi.h>
+#include <types.h>
+#include <cbfs.h>
+
+/* CRTM */
+#define TPM_CRTM_PCR 2
+
+/* PCR for measuring data which changes during runtime
+ * e.g. CMOS, NVRAM...
+ */
+#define TPM_RUNTIME_DATA_PCR 3
+
+/*
+ * Initializes the Core Root of Trust for Measurements
+ * in coreboot. The initial code in a chain of trust must measure
+ * itself.
+ *
+ * Summary:
+ * + Measures bootblock in CBFS or BOOTBLOCK FMAP partition.
+ * + If vboot starts in romstage, it measures the romstage
+ * in CBFS.
+ * + Measure the verstage if it is compiled as separate
+ * stage.
+ *
+ * Takes the current vboot context as parameter for s3 checks.
+ * returns on success VB2_SUCCESS, else a vboot error.
+ */
+uint32_t vboot_init_crtm(void);
+
+#if (IS_ENABLED(CONFIG_VBOOT_MEASURED_BOOT) && \
+!ENV_BOOTBLOCK && !ENV_DECOMPRESSOR && !ENV_SMM)
+/*
+ * Measures cbfs data via hook (cbfs)
+ * fh is the cbfs file handle to measure
+ * return 0 if successful, else an error
+ */
+uint32_t vboot_measure_cbfs_hook(struct cbfsf *fh, const char *name);
+
+#else
+#define vboot_measure_cbfs_hook(fh, name) 0
+#endif
+
+#endif /* __VBOOT_VBOOT_CRTM_H__ */
diff --git a/src/security/vboot/vboot_logic.c b/src/security/vboot/vboot_logic.c
index 1b241600d4..00bbae6204 100644
--- a/src/security/vboot/vboot_logic.c
+++ b/src/security/vboot/vboot_logic.c
@@ -24,6 +24,7 @@
#include <vb2_api.h>
#include <security/vboot/misc.h>
#include <security/vboot/vbnv.h>
+#include <security/vboot/vboot_crtm.h>
#include "antirollback.h"
@@ -86,24 +87,21 @@ int vb2ex_read_resource(struct vb2_context *ctx,
}
/* No-op stubs that can be overridden by SoCs with hardware crypto support. */
-__weak
-int vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg,
- uint32_t data_size)
+__weak int vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg,
+ uint32_t data_size)
{
return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
}
-__weak
-int vb2ex_hwcrypto_digest_extend(const uint8_t *buf, uint32_t size)
+__weak int vb2ex_hwcrypto_digest_extend(const uint8_t *buf, uint32_t size)
{
- BUG(); /* Should never get called if init() returned an error. */
+ BUG(); /* Should never get called if init() returned an error. */
return VB2_ERROR_UNKNOWN;
}
-__weak
-int vb2ex_hwcrypto_digest_finalize(uint8_t *digest, uint32_t digest_size)
+__weak int vb2ex_hwcrypto_digest_finalize(uint8_t *digest, uint32_t digest_size)
{
- BUG(); /* Should never get called if init() returned an error. */
+ BUG(); /* Should never get called if init() returned an error. */
return VB2_ERROR_UNKNOWN;
}
@@ -249,7 +247,7 @@ static int hash_body(struct vb2_context *ctx, struct region_device *fw_main)
}
static int locate_firmware(struct vb2_context *ctx,
- struct region_device *fw_main)
+ struct region_device *fw_main)
{
const char *name;
@@ -281,7 +279,7 @@ static void save_if_needed(struct vb2_context *ctx)
static uint32_t extend_pcrs(struct vb2_context *ctx)
{
return vboot_extend_pcr(ctx, 0, BOOT_MODE_PCR) ||
- vboot_extend_pcr(ctx, 1, HWID_DIGEST_PCR);
+ vboot_extend_pcr(ctx, 1, HWID_DIGEST_PCR);
}
/**
@@ -309,7 +307,7 @@ void verstage_main(void)
* does verification of memory init and thus must ensure it resumes with
* the same slot that it booted from. */
if (IS_ENABLED(CONFIG_RESUME_PATH_SAME_AS_BOOT) &&
- vboot_platform_is_resuming())
+ vboot_platform_is_resuming())
ctx.flags |= VB2_CONTEXT_S3_RESUME;
/* Read secdata from TPM. Initialize TPM if secdata not found. We don't
@@ -319,8 +317,15 @@ void verstage_main(void)
antirollback_read_space_firmware(&ctx);
timestamp_add_now(TS_END_TPMINIT);
+ /* Enable measured boot mode */
+ if (IS_ENABLED(CONFIG_VBOOT_MEASURED_BOOT) &&
+ !(ctx.flags & VB2_CONTEXT_S3_RESUME)) {
+ if (vboot_init_crtm() != VB2_SUCCESS)
+ die("Initializing measured boot mode failed!");
+ }
+
if (IS_ENABLED(CONFIG_VBOOT_PHYSICAL_DEV_SWITCH) &&
- get_developer_mode_switch())
+ get_developer_mode_switch())
ctx.flags |= VB2_CONTEXT_FORCE_DEVELOPER_MODE;
if (get_recovery_mode_switch()) {
@@ -330,7 +335,7 @@ void verstage_main(void)
}
if (IS_ENABLED(CONFIG_VBOOT_WIPEOUT_SUPPORTED) &&
- get_wipeout_mode_switch())
+ get_wipeout_mode_switch())
ctx.flags |= VB2_CONTEXT_FORCE_WIPEOUT_MODE;
if (IS_ENABLED(CONFIG_VBOOT_LID_SWITCH) && !get_lid_switch())
@@ -350,7 +355,7 @@ void verstage_main(void)
if (rv == VB2_ERROR_API_PHASE1_RECOVERY) {
printk(BIOS_INFO, "Recovery requested (%x)\n", rv);
save_if_needed(&ctx);
- extend_pcrs(&ctx); /* ignore failures */
+ extend_pcrs(&ctx); /* ignore failures */
timestamp_add_now(TS_END_VBOOT);
return;
}