Re: [PATCH] tpm: Disable RNG for all AMD fTPMs

From: Jarkko Sakkinen
Date: Wed Aug 02 2023 - 00:12:51 EST


On Wed Aug 2, 2023 at 12:18 AM EEST, Mario Limonciello wrote:
> The TPM RNG functionality is not necessary for entropy when the CPU
> already supports the RDRAND instruction. The TPM RNG functionality
> was previously disabled on a subset of AMD fTPM series, but reports
> continue to show problems on some systems causing stutter root caused
> to TPM RNG functionality.
>
> Expand disabling TPM RNG use for all AMD fTPMs whether they have versions
> that claim to have fixed or not. To accomplish this, move the detection
> into part of the TPM CRB registration and add a flag indicating that
> the TPM should opt-out of registration to hwrng.
>
> Cc: stable@xxxxxxxxxxxxxxx # 6.1.y+
> Fixes: b006c439d58d ("hwrng: core - start hwrng kthread also for untrusted sources")
> Fixes: f1324bbc4011 ("tpm: disable hwrng for fTPM on some AMD designs")
> Reported-by: daniil.stas@xxxxxxxxxx
> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217719
> Reported-by: bitlord0xff@xxxxxxxxx
> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217212
> Signed-off-by: Mario Limonciello <mario.limonciello@xxxxxxx>
> ---
> drivers/char/tpm/tpm-chip.c | 80 +++++++------------------------------
> drivers/char/tpm/tpm_crb.c | 23 +++++++++++
> include/linux/tpm.h | 7 ++++
> 3 files changed, 44 insertions(+), 66 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index cf5499e51999b..3154a5ef2611f 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -89,6 +89,14 @@ static void tpm_clk_disable(struct tpm_chip *chip)
> chip->ops->clk_enable(chip, false);
> }
>
> +static int tpm_check_flags(struct tpm_chip *chip)
> +{
> + if (!chip->ops->check_flags)
> + return 0;
> +
> + return chip->ops->check_flags(chip);
> +}

Instead of adding a new callback, you should probably do the following
in crb_acpi_add(), and get a much less complicated fix:

1. Call tpm_chip_bootstrap() (see tpm_tis_core_init()).
2. Set TPM_CHIP_FLAG_HWRNG_DISABLED if the conditions have been met.
3. Call tpm_chip_register().

> +
> /**
> * tpm_chip_start() - power on the TPM
> * @chip: a TPM chip to use
> @@ -510,70 +518,6 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip)
> return 0;
> }
>
> -/*
> - * Some AMD fTPM versions may cause stutter
> - * https://www.amd.com/en/support/kb/faq/pa-410
> - *
> - * Fixes are available in two series of fTPM firmware:
> - * 6.x.y.z series: 6.0.18.6 +
> - * 3.x.y.z series: 3.57.y.5 +
> - */
> -#ifdef CONFIG_X86
> -static bool tpm_amd_is_rng_defective(struct tpm_chip *chip)
> -{
> - u32 val1, val2;
> - u64 version;
> - int ret;
> -
> - if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
> - return false;
> -
> - ret = tpm_request_locality(chip);
> - if (ret)
> - return false;
> -
> - ret = tpm2_get_tpm_pt(chip, TPM2_PT_MANUFACTURER, &val1, NULL);
> - if (ret)
> - goto release;
> - if (val1 != 0x414D4400U /* AMD */) {
> - ret = -ENODEV;
> - goto release;
> - }
> - ret = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_1, &val1, NULL);
> - if (ret)
> - goto release;
> - ret = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_2, &val2, NULL);
> -
> -release:
> - tpm_relinquish_locality(chip);
> -
> - if (ret)
> - return false;
> -
> - version = ((u64)val1 << 32) | val2;
> - if ((version >> 48) == 6) {
> - if (version >= 0x0006000000180006ULL)
> - return false;
> - } else if ((version >> 48) == 3) {
> - if (version >= 0x0003005700000005ULL)
> - return false;
> - } else {
> - return false;
> - }
> -
> - dev_warn(&chip->dev,
> - "AMD fTPM version 0x%llx causes system stutter; hwrng disabled\n",
> - version);
> -
> - return true;
> -}
> -#else
> -static inline bool tpm_amd_is_rng_defective(struct tpm_chip *chip)
> -{
> - return false;
> -}
> -#endif /* CONFIG_X86 */
> -
> static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
> {
> struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng);
> @@ -588,7 +532,7 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
> static int tpm_add_hwrng(struct tpm_chip *chip)
> {
> if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM) || tpm_is_firmware_upgrade(chip) ||
> - tpm_amd_is_rng_defective(chip))
> + tpm_is_rng_disabled(chip))
> return 0;
>
> snprintf(chip->hwrng_name, sizeof(chip->hwrng_name),
> @@ -670,6 +614,10 @@ int tpm_chip_register(struct tpm_chip *chip)
> if (rc)
> return rc;
>
> + rc = tpm_check_flags(chip);
> + if (rc)
> + return rc;
> +
> tpm_sysfs_add_device(chip);
>
> tpm_bios_log_setup(chip);
> @@ -719,7 +667,7 @@ void tpm_chip_unregister(struct tpm_chip *chip)
> {
> tpm_del_legacy_sysfs(chip);
> if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip) &&
> - !tpm_amd_is_rng_defective(chip))
> + !tpm_is_rng_disabled(chip))
> hwrng_unregister(&chip->hwrng);
> tpm_bios_log_teardown(chip);
> if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip))
> diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
> index 1a5d09b185134..5614b68ef1905 100644
> --- a/drivers/char/tpm/tpm_crb.c
> +++ b/drivers/char/tpm/tpm_crb.c
> @@ -463,6 +463,28 @@ static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
> return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE;
> }
>
> +static int crb_check_flags(struct tpm_chip *chip)
> +{
> + u32 val;
> + int ret;
> +
> + ret = crb_request_locality(chip, 0);
> + if (ret)
> + return ret;
> +
> + ret = tpm2_get_tpm_pt(chip, TPM2_PT_MANUFACTURER, &val, NULL);
> + if (ret)
> + goto release;
> +
> + if (val == 0x414D4400U /* AMD */)
> + chip->flags |= TPM_CHIP_FLAG_HWRNG_DISABLED;
> +
> +release:
> + crb_relinquish_locality(chip, 0);
> +
> + return ret;
> +}
> +
> static const struct tpm_class_ops tpm_crb = {
> .flags = TPM_OPS_AUTO_STARTUP,
> .status = crb_status,
> @@ -476,6 +498,7 @@ static const struct tpm_class_ops tpm_crb = {
> .relinquish_locality = crb_relinquish_locality,
> .req_complete_mask = CRB_DRV_STS_COMPLETE,
> .req_complete_val = CRB_DRV_STS_COMPLETE,
> + .check_flags = crb_check_flags,
> };
>
> static int crb_check_resource(struct acpi_resource *ares, void *data)
> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> index 6a1e8f1572551..aeb84944b0ca4 100644
> --- a/include/linux/tpm.h
> +++ b/include/linux/tpm.h
> @@ -82,6 +82,7 @@ struct tpm_class_ops {
> int (*request_locality)(struct tpm_chip *chip, int loc);
> int (*relinquish_locality)(struct tpm_chip *chip, int loc);
> void (*clk_enable)(struct tpm_chip *chip, bool value);
> + int (*check_flags)(struct tpm_chip *chip);
> };
>
> #define TPM_NUM_EVENT_LOG_FILES 3
> @@ -283,6 +284,7 @@ enum tpm_chip_flags {
> TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED = BIT(6),
> TPM_CHIP_FLAG_FIRMWARE_UPGRADE = BIT(7),
> TPM_CHIP_FLAG_SUSPENDED = BIT(8),
> + TPM_CHIP_FLAG_HWRNG_DISABLED = BIT(9),
> };
>
> #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
> @@ -417,6 +419,11 @@ static inline u32 tpm2_rc_value(u32 rc)
> return (rc & BIT(7)) ? rc & 0xff : rc;
> }
>
> +static inline bool tpm_is_rng_disabled(struct tpm_chip *chip)
> +{
> + return chip->flags & TPM_CHIP_FLAG_HWRNG_DISABLED;
> +}

Please open code to the call sites.

Wrapping a flag check is not very useful and makes the bug fix
only more complex.

> +
> #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
>
> extern int tpm_is_tpm2(struct tpm_chip *chip);
> --
> 2.34.1

BR, Jarkko