From 66f9a09916368bfab09da42ef0beed84a4bb7206 Mon Sep 17 00:00:00 2001 From: Philipp Deppenwiese Date: Thu, 8 Nov 2018 10:59:40 +0100 Subject: security/vboot: Add measured boot mode * Introduce a measured boot mode into vboot. * Add hook for stage measurements in prog_loader and cbfs. * Implement and hook-up CRTM in vboot and check for suspend. Change-Id: I339a2f1051e44f36aba9f99828f130592a09355e Signed-off-by: Philipp Deppenwiese Signed-off-by: Werner Zeh Reviewed-on: https://review.coreboot.org/c/29547 Tested-by: build bot (Jenkins) --- src/security/vboot/Kconfig | 17 ++++- src/security/vboot/Makefile.inc | 7 ++ src/security/vboot/vboot_crtm.c | 144 +++++++++++++++++++++++++++++++++++++++ src/security/vboot/vboot_crtm.h | 62 +++++++++++++++++ src/security/vboot/vboot_logic.c | 35 ++++++---- 5 files changed, 249 insertions(+), 16 deletions(-) create mode 100644 src/security/vboot/vboot_crtm.c create mode 100644 src/security/vboot/vboot_crtm.h (limited to 'src/security/vboot') 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 +#include +#include +#include + +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 +#include +#include +#include + +/* 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 #include #include +#include #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; } -- cgit v1.2.3