From 47e9e8cde1810ee9f249027b14ee9f82a7a52d84 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Wed, 2 Nov 2022 00:50:03 +0200 Subject: security/tpm: replace CONFIG(TPMx) checks with runtime check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prepares the code for enabling both CONFIG_TPM1 and CONFIG_TPM2 during compilation, in which case actual TPM family in use can be determined at runtime. In some places both compile-time and runtime checks are necessary. Yet in places like probe functions runtime state checks don't make sense as runtime state is defined by results of probing. Change-Id: Id9cc25aad8d1d7bfad12b7a92059b1b3641bbfa9 Ticket: https://ticket.coreboot.org/issues/433 Signed-off-by: Sergii Dmytruk Reviewed-on: https://review.coreboot.org/c/coreboot/+/69161 Reviewed-by: Jérémy Compostella Reviewed-by: Julius Werner Tested-by: build bot (Jenkins) --- src/acpi/acpi.c | 8 ++- src/drivers/crb/tis.c | 3 + src/drivers/crb/tpm.c | 26 +++++++++ src/drivers/crb/tpm.h | 1 + src/drivers/pc80/tpm/tis.c | 2 +- src/drivers/tpm/ppi.c | 34 ++++++++--- src/security/tpm/tspi/crtm.h | 6 +- src/security/tpm/tspi/tspi.c | 25 ++++---- src/security/tpm/tss.h | 31 +++++++--- src/security/vboot/secdata_tpm.c | 74 +++++++++++++----------- src/security/vboot/tpm_common.c | 4 +- src/vendorcode/google/chromeos/cse_board_reset.c | 5 ++ src/vendorcode/google/chromeos/tpm2.c | 4 ++ 13 files changed, 153 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c index 98c8ecdc13..30a07bfda0 100644 --- a/src/acpi/acpi.c +++ b/src/acpi/acpi.c @@ -25,7 +25,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -205,7 +207,7 @@ static void *get_tcpa_log(u32 *size) static void acpi_create_tcpa(acpi_header_t *header, void *unused) { - if (!CONFIG(TPM1)) + if (tlcl_get_family() != TPM_1) return; acpi_tcpa_t *tcpa = (acpi_tcpa_t *)header; @@ -251,7 +253,7 @@ static void *get_tpm2_log(u32 *size) static void acpi_create_tpm2(acpi_header_t *header, void *unused) { - if (!CONFIG(TPM2)) + if (tlcl_get_family() != TPM_2) return; acpi_tpm2_t *tpm2 = (acpi_tpm2_t *)header; @@ -271,7 +273,7 @@ static void acpi_create_tpm2(acpi_header_t *header, void *unused) /* Hard to detect for coreboot. Just set it to 0 */ tpm2->platform_class = 0; - if (CONFIG(CRB_TPM)) { + if (CONFIG(CRB_TPM) && tpm2_has_crb_active()) { /* Must be set to 7 for CRB Support */ tpm2->control_area = CONFIG_CRB_TPM_BASE_ADDRESS + 0x40; tpm2->start_method = 7; diff --git a/src/drivers/crb/tis.c b/src/drivers/crb/tis.c index 21a7647108..04e255aa7f 100644 --- a/src/drivers/crb/tis.c +++ b/src/drivers/crb/tis.c @@ -142,6 +142,9 @@ static int smbios_write_type43_tpm(struct device *dev, int *handle, unsigned lon uint32_t fw_ver1, fw_ver2; uint8_t major_spec_ver, minor_spec_ver; + if (tlcl_get_family() == TPM_1) + return 0; + tpm2_get_info(&info); /* If any of these have invalid values, assume TPM not present or disabled */ diff --git a/src/drivers/crb/tpm.c b/src/drivers/crb/tpm.c index 4e9f6f2d2b..b568dcc7f4 100644 --- a/src/drivers/crb/tpm.c +++ b/src/drivers/crb/tpm.c @@ -320,3 +320,29 @@ void tpm2_get_info(struct tpm2_info *tpm2_info) tpm2_info->device_id = (interfaceReg >> 32) & 0xFFFF; tpm2_info->revision = (interfaceReg >> 24) & 0xFF; } + +/* + * tpm2_has_crb_active + * + * Checks that CRB interface is available and active. + * + * The body was derived from crb_probe() which unlike this function can also + * write to registers. + */ +bool tpm2_has_crb_active(void) +{ + uint64_t tpmStatus = read64(CRB_REG(0, CRB_REG_INTF_ID)); + printk(BIOS_SPEW, "Interface ID Reg. %llx\n", tpmStatus); + + if ((tpmStatus & CRB_INTF_REG_CAP_CRB) == 0) { + printk(BIOS_DEBUG, "TPM: CRB Interface is not supported.\n"); + return false; + } + + if ((tpmStatus & (0xf)) != 1) { + printk(BIOS_DEBUG, "TPM: CRB Interface is not active.\n"); + return false; + } + + return true; +} diff --git a/src/drivers/crb/tpm.h b/src/drivers/crb/tpm.h index 7b25e78b3b..60020c3ff9 100644 --- a/src/drivers/crb/tpm.h +++ b/src/drivers/crb/tpm.h @@ -64,3 +64,4 @@ tpm_result_t tpm2_init(void); void tpm2_get_info(struct tpm2_info *tpm2_info); size_t tpm2_process_command(const void *tpm2_command, size_t command_size, void *tpm2_response, size_t max_response); +bool tpm2_has_crb_active(void); diff --git a/src/drivers/pc80/tpm/tis.c b/src/drivers/pc80/tpm/tis.c index da443d3a09..568065c654 100644 --- a/src/drivers/pc80/tpm/tis.c +++ b/src/drivers/pc80/tpm/tis.c @@ -809,7 +809,7 @@ static void lpc_tpm_fill_ssdt(const struct device *dev) acpigen_write_scope(path); acpigen_write_device(acpi_device_name(dev)); - if (CONFIG(TPM2)) { + if (tlcl_get_family() == TPM_2) { acpigen_write_name_string("_HID", "MSFT0101"); acpigen_write_name_string("_CID", "MSFT0101"); } else { diff --git a/src/drivers/tpm/ppi.c b/src/drivers/tpm/ppi.c index 6f12b411ba..d63b8f811b 100644 --- a/src/drivers/tpm/ppi.c +++ b/src/drivers/tpm/ppi.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "tpm_ppi.h" @@ -35,6 +36,8 @@ static void set_package_element_name(const char *package_name, unsigned int elem /* PPI function is passed in src_op. Converted to Local2. Clobbers Local1 and Local2 */ static void verify_supported_ppi(uint8_t src_op) { + enum tpm_family family = tlcl_get_family(); + /* * Old OSes incorrectly pass a Buffer instead of a Package. * See TCG Physical Presence Interface Specification Chapter 8.1.2 for details. @@ -62,7 +65,7 @@ static void verify_supported_ppi(uint8_t src_op) acpigen_write_store(); acpigen_emit_namestring("^FSUP"); acpigen_emit_byte(LOCAL2_OP); - acpigen_emit_byte(CONFIG(TPM1) ? ONE_OP : ZERO_OP); + acpigen_emit_byte(family == TPM_1 ? ONE_OP : ZERO_OP); acpigen_emit_byte(LOCAL1_OP); acpigen_write_if_lequal_op_int(LOCAL1_OP, 0); @@ -84,7 +87,7 @@ static void verify_supported_ppi(uint8_t src_op) acpigen_write_store(); acpigen_emit_namestring("^FSUP"); acpigen_emit_byte(LOCAL2_OP); - acpigen_emit_byte(CONFIG(TPM1) ? ZERO_OP : ONE_OP); + acpigen_emit_byte(family == TPM_1 ? ZERO_OP : ONE_OP); acpigen_emit_byte(LOCAL1_OP); acpigen_write_if_lequal_op_int(LOCAL1_OP, 1); @@ -114,7 +117,7 @@ static void tpm_ppi_func0_cb(void *arg) */ static void tpm_ppi_func1_cb(void *arg) { - if (CONFIG(TPM2)) + if (tlcl_get_family() == TPM_2) /* Interface version: 1.3 */ acpigen_write_return_string("1.3"); else @@ -400,6 +403,8 @@ static void tpm_ppi_func7_cb(void *arg) */ static void tpm_ppi_func8_cb(void *arg) { + enum tpm_family family = tlcl_get_family(); + acpigen_write_to_integer(ARG1_OP, LOCAL0_OP); /* Revision 1 */ @@ -410,7 +415,7 @@ static void tpm_ppi_func8_cb(void *arg) acpigen_write_store(); acpigen_emit_namestring("^FSUP"); acpigen_emit_byte(LOCAL2_OP); - acpigen_emit_byte(CONFIG(TPM1) ? ONE_OP : ZERO_OP); + acpigen_emit_byte(family == TPM_1 ? ONE_OP : ZERO_OP); acpigen_emit_byte(LOCAL1_OP); acpigen_write_if_lequal_op_int(LOCAL1_OP, 0); acpigen_write_return_byte(0); /* Not implemented */ @@ -418,7 +423,7 @@ static void tpm_ppi_func8_cb(void *arg) // FIXME: Only advertise supported functions - if (CONFIG(TPM1)) { + if (family == TPM_1) { /* * Some functions do not require PP depending on configuration. * Those aren't listed here, so the 'required PP' is always set for those. @@ -434,7 +439,7 @@ static void tpm_ppi_func8_cb(void *arg) acpigen_write_return_integer(PPI8_RET_ALLOWED); acpigen_pop_len(); /* Pop : If */ } - } else if (CONFIG(TPM2)) { + } else if (family == TPM_2) { /* * Some functions do not require PP depending on configuration. * Those aren't listed here, so the 'required PP' is always set for those. @@ -564,6 +569,12 @@ void tpm_ppi_acpi_fill_ssdt(const struct device *dev) printk(BIOS_DEBUG, "PPI: Pending OS request: 0x%x (0x%x)\n", ppib->pprq, ppib->pprm); printk(BIOS_DEBUG, "PPI: OS response: CMD 0x%x = 0x%x\n", ppib->lppr, ppib->pprp); + enum tpm_family family = tlcl_get_family(); + if (family == TPM_UNKNOWN) { + printk(BIOS_WARN, "PPI: %s: aborting, because no TPM detected\n", __func__); + return; + } + /* Clear unsupported fields */ ppib->next_step = 0; ppib->ppin = 1; // Not used by ACPI. Read by EDK-2, must be 1. @@ -574,7 +585,7 @@ void tpm_ppi_acpi_fill_ssdt(const struct device *dev) bool found = false; /* Fill in defaults, the TPM command executor may overwrite this list */ memset(ppib->func, 0, sizeof(ppib->func)); - if (CONFIG(TPM1)) { + if (family == TPM_1) { for (size_t i = 0; i < ARRAY_SIZE(tpm1_funcs); i++) { ppib->func[tpm1_funcs[i]] = 1; if (ppib->pprq == tpm1_funcs[i]) @@ -706,17 +717,24 @@ void tpm_ppi_acpi_fill_ssdt(const struct device *dev) void lb_tpm_ppi(struct lb_header *header) { struct lb_tpm_physical_presence *tpm_ppi; + enum tpm_family family; void *ppib; ppib = cbmem_find(CBMEM_ID_TPM_PPI); if (!ppib) return; + family = tlcl_get_family(); + if (family == TPM_UNKNOWN) { + printk(BIOS_WARN, "PPI: %s: aborting, because no TPM detected\n", __func__); + return; + } + tpm_ppi = (struct lb_tpm_physical_presence *)lb_new_record(header); tpm_ppi->tag = LB_TAG_TPM_PPI_HANDOFF; tpm_ppi->size = sizeof(*tpm_ppi); tpm_ppi->ppi_address = (uintptr_t)ppib; - tpm_ppi->tpm_version = CONFIG(TPM1) ? LB_TPM_VERSION_TPM_VERSION_1_2 : + tpm_ppi->tpm_version = family == TPM_1 ? LB_TPM_VERSION_TPM_VERSION_1_2 : LB_TPM_VERSION_TPM_VERSION_2; tpm_ppi->ppi_version = BCD(1, 3); diff --git a/src/security/tpm/tspi/crtm.h b/src/security/tpm/tspi/crtm.h index 6f5eb2e716..69043e233a 100644 --- a/src/security/tpm/tspi/crtm.h +++ b/src/security/tpm/tspi/crtm.h @@ -9,10 +9,8 @@ #include #include -#if CONFIG(TPM_LOG_CB) && CONFIG(TPM1) -# define TPM_MEASURE_ALGO VB2_HASH_SHA1 -#elif CONFIG(TPM_LOG_CB) && CONFIG(TPM2) -# define TPM_MEASURE_ALGO VB2_HASH_SHA256 +#if CONFIG(TPM_LOG_CB) +# define TPM_MEASURE_ALGO (tlcl_get_family() == TPM_1 ? VB2_HASH_SHA1 : VB2_HASH_SHA256) #elif CONFIG(TPM_LOG_TPM1) # define TPM_MEASURE_ALGO VB2_HASH_SHA1 #elif CONFIG(TPM_LOG_TPM2) diff --git a/src/security/tpm/tspi/tspi.c b/src/security/tpm/tspi/tspi.c index 1a0f1d5c88..56b8fa8ede 100644 --- a/src/security/tpm/tspi/tspi.c +++ b/src/security/tpm/tspi/tspi.c @@ -17,6 +17,9 @@ static tpm_result_t tpm1_invoke_state_machine(void) uint8_t deactivated; tpm_result_t rc = TPM_SUCCESS; + if (tlcl_get_family() != TPM_1) + return rc; + /* Check that the TPM is enabled and activated. */ rc = tlcl1_get_flags(&disabled, &deactivated, NULL); if (rc != TPM_SUCCESS) { @@ -199,19 +202,19 @@ tpm_result_t tpm_clear_and_reenable(void) return rc; } -#if CONFIG(TPM1) - rc = tlcl1_set_enable(); - if (rc != TPM_SUCCESS) { - printk(BIOS_ERR, "TPM Error (%#x): Can't set enabled state.\n", rc); - return rc; - } + if (tlcl_get_family() == TPM_1) { + rc = tlcl1_set_enable(); + if (rc != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM Error (%#x): Can't set enabled state.\n", rc); + return rc; + } - rc = tlcl1_set_deactivated(0); - if (rc != TPM_SUCCESS) { - printk(BIOS_ERR, "TPM Error (%#x): Can't set deactivated state.\n", rc); - return rc; + rc = tlcl1_set_deactivated(0); + if (rc != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM Error (%#x): Can't set deactivated state.\n", rc); + return rc; + } } -#endif return TPM_SUCCESS; } diff --git a/src/security/tpm/tss.h b/src/security/tpm/tss.h index 3a019ead32..c9aec08262 100644 --- a/src/security/tpm/tss.h +++ b/src/security/tpm/tss.h @@ -33,16 +33,31 @@ */ tpm_result_t tlcl_lib_init(void); -/* Commands */ +/** + * Query active TPM family. Returns TPM_UNKNOWN if uninitialized and TPM_1 or TPM_2 otherwise. + */ +static inline enum tpm_family tlcl_get_family(void) +{ + /* Defined in tss/tss.c */ + extern enum tpm_family tlcl_tpm_family; + + if (CONFIG(TPM1) && CONFIG(TPM2)) + return tlcl_tpm_family; + if (CONFIG(TPM1)) + return TPM_1; + if (CONFIG(TPM2)) + return TPM_2; + return TPM_UNKNOWN; +} -extern enum tpm_family tlcl_tpm_family; +/* Commands */ -#define TLCL_CALL(name, ...) do { \ - if (CONFIG(TPM1) && (!CONFIG(TPM2) || tlcl_tpm_family == TPM_1)) \ - return tlcl1_##name(__VA_ARGS__); \ - if (CONFIG(TPM2) && (!CONFIG(TPM1) || tlcl_tpm_family == TPM_2)) \ - return tlcl2_##name(__VA_ARGS__); \ - return TPM_CB_INTERNAL_INCONSISTENCY; \ +#define TLCL_CALL(name, ...) do { \ + if (tlcl_get_family() == TPM_1) \ + return tlcl1_##name(__VA_ARGS__); \ + if (tlcl_get_family() == TPM_2) \ + return tlcl2_##name(__VA_ARGS__); \ + return TPM_CB_INTERNAL_INCONSISTENCY; \ } while (0) /** diff --git a/src/security/vboot/secdata_tpm.c b/src/security/vboot/secdata_tpm.c index 21901bb310..f60a5e2ee0 100644 --- a/src/security/vboot/secdata_tpm.c +++ b/src/security/vboot/secdata_tpm.c @@ -30,7 +30,7 @@ static tpm_result_t safe_write(uint32_t index, const void *data, uint32_t length tpm_result_t antirollback_read_space_kernel(struct vb2_context *ctx) { - if (!CONFIG(TPM2)) { + if (tlcl_get_family() == TPM_1) { /* * Before reading the kernel space, verify its permissions. If * the kernel space has the wrong permission, we give up. This @@ -224,12 +224,6 @@ static uint32_t define_space(const char *name, uint32_t index, uint32_t length, return rc; } -/* Nothing special in the TPM2 path yet. */ -static tpm_result_t safe_write(uint32_t index, const void *data, uint32_t length) -{ - return tlcl_write(index, data, length); -} - static tpm_result_t setup_space(const char *name, uint32_t index, const void *data, uint32_t length, const TPMA_NV nv_attributes, const uint8_t *nv_policy, size_t nv_policy_size) @@ -376,7 +370,7 @@ static tpm_result_t setup_widevine_counter_spaces(void) return rc; } -static tpm_result_t _factory_initialize_tpm(struct vb2_context *ctx) +static tpm_result_t _factory_initialize_tpm2(struct vb2_context *ctx) { RETURN_ON_FAILURE(tlcl_force_clear()); @@ -426,11 +420,6 @@ static tpm_result_t _factory_initialize_tpm(struct vb2_context *ctx) return TPM_SUCCESS; } -tpm_result_t antirollback_lock_space_firmware(void) -{ - return tlcl2_lock_nv_write(FIRMWARE_NV_INDEX); -} - tpm_result_t antirollback_read_space_mrc_hash(uint32_t index, uint8_t *data, uint32_t size) { if (size != HASH_NV_SIZE) { @@ -521,25 +510,9 @@ tpm_result_t antirollback_write_space_vbios_hash(const uint8_t *data, uint32_t s return safe_write(VBIOS_CACHE_NV_INDEX, data, size); } -#else +#endif /* CONFIG(TPM2) */ -/** - * Like tlcl_write(), 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. - */ - -static tpm_result_t safe_write(uint32_t index, const void *data, uint32_t length) -{ - tpm_result_t rc = tlcl_write(index, data, length); - if (rc == TPM_MAXNVWRITES) { - RETURN_ON_FAILURE(tpm_clear_and_reenable()); - return tlcl_write(index, data, length); - } else { - return rc; - } -} +#if CONFIG(TPM1) /** * Similarly to safe_write(), this ensures we don't fail a DefineSpace because @@ -558,7 +531,7 @@ static tpm_result_t safe_define_space(uint32_t index, uint32_t perm, uint32_t si } } -static tpm_result_t _factory_initialize_tpm(struct vb2_context *ctx) +static tpm_result_t _factory_initialize_tpm1(struct vb2_context *ctx) { TPM_PERMANENT_FLAGS pflags; tpm_result_t rc; @@ -616,12 +589,45 @@ static tpm_result_t _factory_initialize_tpm(struct vb2_context *ctx) return TPM_SUCCESS; } -tpm_result_t antirollback_lock_space_firmware(void) +#endif /* CONFIG(TPM1) */ + +static tpm_result_t safe_write(uint32_t index, const void *data, uint32_t length) { - return tlcl1_set_global_lock(); + tpm_result_t rc = tlcl_write(index, data, length); + if (tlcl_get_family() == TPM_1 && rc == TPM_MAXNVWRITES) { + /** + * Clear the TPM on write error due to hitting the 64-write + * limit. 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. + */ + RETURN_ON_FAILURE(tpm_clear_and_reenable()); + rc = tlcl_write(index, data, length); + } + return rc; } +static uint32_t _factory_initialize_tpm(struct vb2_context *ctx) +{ +#if CONFIG(TPM1) + if (tlcl_get_family() == TPM_1) + return _factory_initialize_tpm1(ctx); +#endif +#if CONFIG(TPM2) + if (tlcl_get_family() == TPM_2) + return _factory_initialize_tpm2(ctx); #endif + return TPM_CB_CORRUPTED_STATE; +} + +uint32_t antirollback_lock_space_firmware(void) +{ + if (tlcl_get_family() == TPM_1) + return tlcl1_set_global_lock(); + if (tlcl_get_family() == TPM_2) + return tlcl2_lock_nv_write(FIRMWARE_NV_INDEX); + return TPM_CB_CORRUPTED_STATE; +} /** * Perform one-time initializations. diff --git a/src/security/vboot/tpm_common.c b/src/security/vboot/tpm_common.c index 997c4e9cd9..dedf8dfebc 100644 --- a/src/security/vboot/tpm_common.c +++ b/src/security/vboot/tpm_common.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include +#include #include #include #include @@ -43,7 +44,8 @@ tpm_result_t vboot_extend_pcr(struct vb2_context *ctx, int pcr, */ _Static_assert(sizeof(buffer) >= VB2_SHA256_DIGEST_SIZE, "Buffer needs to be able to fit at least a SHA256"); - enum vb2_hash_algorithm algo = CONFIG(TPM1) ? VB2_HASH_SHA1 : VB2_HASH_SHA256; + enum vb2_hash_algorithm algo = tlcl_get_family() == TPM_1 ? + VB2_HASH_SHA1 : VB2_HASH_SHA256; switch (which_digest) { /* SHA1 of (devmode|recmode|keyblock) bits */ diff --git a/src/vendorcode/google/chromeos/cse_board_reset.c b/src/vendorcode/google/chromeos/cse_board_reset.c index e7cb878b68..f3369483e3 100644 --- a/src/vendorcode/google/chromeos/cse_board_reset.c +++ b/src/vendorcode/google/chromeos/cse_board_reset.c @@ -19,6 +19,11 @@ void cse_board_reset(void) if (CONFIG(CSE_RESET_CLEAR_EC_AP_IDLE_FLAG)) google_chromeec_clear_ec_ap_idle(); + /* + * Assuming that if particular TPM implementation is enabled at compile + * time, it's the one being used. This isn't generic code, so can + * probably get away with it. + */ if (CONFIG(TPM2) && CONFIG(TPM_GOOGLE_CR50)) { /* Initialize TPM and get the cr50 firmware version. */ rc = tlcl_lib_init(); diff --git a/src/vendorcode/google/chromeos/tpm2.c b/src/vendorcode/google/chromeos/tpm2.c index 31c28c9d2a..8823978de4 100644 --- a/src/vendorcode/google/chromeos/tpm2.c +++ b/src/vendorcode/google/chromeos/tpm2.c @@ -22,6 +22,10 @@ static void disable_platform_hierarchy(void *unused) return; } + /* In case both families are enabled, but TPM1 is in use. */ + if (tlcl_get_family() != TPM_2) + return; + rc = tlcl2_disable_platform_hierarchy(); if (rc != TPM_SUCCESS) printk(BIOS_ERR, "Platform hierarchy disablement failed: %#x\n", -- cgit v1.2.3