Skip to content

Commit

Permalink
tpm: Disable RNG for all AMD fTPMs
Browse files Browse the repository at this point in the history
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@vger.kernel.org # 6.1.y+
Fixes: b006c43 ("hwrng: core - start hwrng kthread also for untrusted sources")
Fixes: f1324bb ("tpm: disable hwrng for fTPM on some AMD designs")
Reported-by: daniil.stas@posteo.net
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217719
Reported-by: bitlord0xff@gmail.com
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217212
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
  • Loading branch information
superm1 authored and damentz committed Aug 8, 2023
1 parent 6acdaf4 commit 7828676
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 59 deletions.
61 changes: 2 additions & 59 deletions drivers/char/tpm/tpm-chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,63 +510,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 +
*/
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;
}

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);
Expand All @@ -581,7 +524,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))
chip->flags & TPM_CHIP_FLAG_HWRNG_DISABLED)
return 0;

snprintf(chip->hwrng_name, sizeof(chip->hwrng_name),
Expand Down Expand Up @@ -712,7 +655,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))
!(chip->flags & TPM_CHIP_FLAG_HWRNG_DISABLED))
hwrng_unregister(&chip->hwrng);
tpm_bios_log_teardown(chip);
if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip))
Expand Down
30 changes: 30 additions & 0 deletions drivers/char/tpm/tpm_crb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -797,6 +819,14 @@ static int crb_acpi_add(struct acpi_device *device)
chip->acpi_dev_handle = device->handle;
chip->flags = TPM_CHIP_FLAG_TPM2;

rc = tpm_chip_bootstrap(chip);
if (rc)
goto out;

rc = crb_check_flags(chip);
if (rc)
goto out;

rc = tpm_chip_register(chip);

out:
Expand Down
1 change: 1 addition & 0 deletions include/linux/tpm.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,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)
Expand Down

0 comments on commit 7828676

Please sign in to comment.