tpm: disable hwrng for fTPM on some AMD designs

AMD has issued an advisory indicating that having fTPM enabled in
BIOS can cause "stuttering" in the OS. This issue has been fixed
in newer versions of the fTPM firmware, but it's up to system
designers to decide whether to distribute it.

This issue has existed for a while, but is more prevalent starting
with kernel 6.1 because commit b006c439d58db ("hwrng: core - start
hwrng kthread also for untrusted sources") started to use the fTPM
for hwrng by default. However, all uses of /dev/hwrng result in
unacceptable stuttering.

So, simply disable registration of the defective hwrng when detecting
these faulty fTPM versions. As this is caused by faulty firmware, it
is plausible that such a problem could also be reproduced by other TPM
interactions, but this hasn't been shown by any user's testing or reports.

It is hypothesized to be triggered more frequently by the use of the RNG
because userspace software will fetch random numbers regularly.

Intentionally continue to register other TPM functionality so that users
that rely upon PCR measurements or any storage of data will still have
access to it. If it's found later that another TPM functionality is
exacerbating this problem a module parameter it can be turned off entirely
and a module parameter can be introduced to allow users who rely upon
fTPM functionality to turn it on even though this problem is present.

Link: https://www.amd.com/en/support/kb/faq/pa-410
Link: https://bugzilla.kernel.org/show_bug.cgi?id=216989
Link: https://lore.kernel.org/all/20230209153120.261904-1-Jason@zx2c4.com/
Fixes: b006c439d58d ("hwrng: core - start hwrng kthread also for untrusted sources")
Cc: stable@vger.kernel.org
Cc: Jarkko Sakkinen <jarkko@kernel.org>
Cc: Thorsten Leemhuis <regressions@leemhuis.info>
Cc: James Bottomley <James.Bottomley@hansenpartnership.com>
Tested-by: reach622@mailcuk.com
Tested-by: Bell <1138267643@qq.com>
Co-developed-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>

authored by

Mario Limonciello and committed by
Jarkko Sakkinen
f1324bbc 80a6c216

+132 -1
+59 -1
drivers/char/tpm/tpm-chip.c
··· 511 return 0; 512 } 513 514 static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) 515 { 516 struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng); ··· 577 578 static int tpm_add_hwrng(struct tpm_chip *chip) 579 { 580 - if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM) || tpm_is_firmware_upgrade(chip)) 581 return 0; 582 583 snprintf(chip->hwrng_name, sizeof(chip->hwrng_name),
··· 511 return 0; 512 } 513 514 + /* 515 + * Some AMD fTPM versions may cause stutter 516 + * https://www.amd.com/en/support/kb/faq/pa-410 517 + * 518 + * Fixes are available in two series of fTPM firmware: 519 + * 6.x.y.z series: 6.0.18.6 + 520 + * 3.x.y.z series: 3.57.y.5 + 521 + */ 522 + static bool tpm_amd_is_rng_defective(struct tpm_chip *chip) 523 + { 524 + u32 val1, val2; 525 + u64 version; 526 + int ret; 527 + 528 + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) 529 + return false; 530 + 531 + ret = tpm_request_locality(chip); 532 + if (ret) 533 + return false; 534 + 535 + ret = tpm2_get_tpm_pt(chip, TPM2_PT_MANUFACTURER, &val1, NULL); 536 + if (ret) 537 + goto release; 538 + if (val1 != 0x414D4400U /* AMD */) { 539 + ret = -ENODEV; 540 + goto release; 541 + } 542 + ret = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_1, &val1, NULL); 543 + if (ret) 544 + goto release; 545 + ret = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_2, &val2, NULL); 546 + 547 + release: 548 + tpm_relinquish_locality(chip); 549 + 550 + if (ret) 551 + return false; 552 + 553 + version = ((u64)val1 << 32) | val2; 554 + if ((version >> 48) == 6) { 555 + if (version >= 0x0006000000180006ULL) 556 + return false; 557 + } else if ((version >> 48) == 3) { 558 + if (version >= 0x0003005700000005ULL) 559 + return false; 560 + } else { 561 + return false; 562 + } 563 + 564 + dev_warn(&chip->dev, 565 + "AMD fTPM version 0x%llx causes system stutter; hwrng disabled\n", 566 + version); 567 + 568 + return true; 569 + } 570 + 571 static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) 572 { 573 struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng); ··· 520 521 static int tpm_add_hwrng(struct tpm_chip *chip) 522 { 523 + if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM) || tpm_is_firmware_upgrade(chip) || 524 + tpm_amd_is_rng_defective(chip)) 525 return 0; 526 527 snprintf(chip->hwrng_name, sizeof(chip->hwrng_name),
+73
drivers/char/tpm/tpm.h
··· 150 TPM_CAP_PROP_TIS_DURATION = 0x120, 151 }; 152 153 154 /* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18 155 * bytes, but 128 is still a relatively large number of random bytes and
··· 150 TPM_CAP_PROP_TIS_DURATION = 0x120, 151 }; 152 153 + enum tpm2_pt_props { 154 + TPM2_PT_NONE = 0x00000000, 155 + TPM2_PT_GROUP = 0x00000100, 156 + TPM2_PT_FIXED = TPM2_PT_GROUP * 1, 157 + TPM2_PT_FAMILY_INDICATOR = TPM2_PT_FIXED + 0, 158 + TPM2_PT_LEVEL = TPM2_PT_FIXED + 1, 159 + TPM2_PT_REVISION = TPM2_PT_FIXED + 2, 160 + TPM2_PT_DAY_OF_YEAR = TPM2_PT_FIXED + 3, 161 + TPM2_PT_YEAR = TPM2_PT_FIXED + 4, 162 + TPM2_PT_MANUFACTURER = TPM2_PT_FIXED + 5, 163 + TPM2_PT_VENDOR_STRING_1 = TPM2_PT_FIXED + 6, 164 + TPM2_PT_VENDOR_STRING_2 = TPM2_PT_FIXED + 7, 165 + TPM2_PT_VENDOR_STRING_3 = TPM2_PT_FIXED + 8, 166 + TPM2_PT_VENDOR_STRING_4 = TPM2_PT_FIXED + 9, 167 + TPM2_PT_VENDOR_TPM_TYPE = TPM2_PT_FIXED + 10, 168 + TPM2_PT_FIRMWARE_VERSION_1 = TPM2_PT_FIXED + 11, 169 + TPM2_PT_FIRMWARE_VERSION_2 = TPM2_PT_FIXED + 12, 170 + TPM2_PT_INPUT_BUFFER = TPM2_PT_FIXED + 13, 171 + TPM2_PT_HR_TRANSIENT_MIN = TPM2_PT_FIXED + 14, 172 + TPM2_PT_HR_PERSISTENT_MIN = TPM2_PT_FIXED + 15, 173 + TPM2_PT_HR_LOADED_MIN = TPM2_PT_FIXED + 16, 174 + TPM2_PT_ACTIVE_SESSIONS_MAX = TPM2_PT_FIXED + 17, 175 + TPM2_PT_PCR_COUNT = TPM2_PT_FIXED + 18, 176 + TPM2_PT_PCR_SELECT_MIN = TPM2_PT_FIXED + 19, 177 + TPM2_PT_CONTEXT_GAP_MAX = TPM2_PT_FIXED + 20, 178 + TPM2_PT_NV_COUNTERS_MAX = TPM2_PT_FIXED + 22, 179 + TPM2_PT_NV_INDEX_MAX = TPM2_PT_FIXED + 23, 180 + TPM2_PT_MEMORY = TPM2_PT_FIXED + 24, 181 + TPM2_PT_CLOCK_UPDATE = TPM2_PT_FIXED + 25, 182 + TPM2_PT_CONTEXT_HASH = TPM2_PT_FIXED + 26, 183 + TPM2_PT_CONTEXT_SYM = TPM2_PT_FIXED + 27, 184 + TPM2_PT_CONTEXT_SYM_SIZE = TPM2_PT_FIXED + 28, 185 + TPM2_PT_ORDERLY_COUNT = TPM2_PT_FIXED + 29, 186 + TPM2_PT_MAX_COMMAND_SIZE = TPM2_PT_FIXED + 30, 187 + TPM2_PT_MAX_RESPONSE_SIZE = TPM2_PT_FIXED + 31, 188 + TPM2_PT_MAX_DIGEST = TPM2_PT_FIXED + 32, 189 + TPM2_PT_MAX_OBJECT_CONTEXT = TPM2_PT_FIXED + 33, 190 + TPM2_PT_MAX_SESSION_CONTEXT = TPM2_PT_FIXED + 34, 191 + TPM2_PT_PS_FAMILY_INDICATOR = TPM2_PT_FIXED + 35, 192 + TPM2_PT_PS_LEVEL = TPM2_PT_FIXED + 36, 193 + TPM2_PT_PS_REVISION = TPM2_PT_FIXED + 37, 194 + TPM2_PT_PS_DAY_OF_YEAR = TPM2_PT_FIXED + 38, 195 + TPM2_PT_PS_YEAR = TPM2_PT_FIXED + 39, 196 + TPM2_PT_SPLIT_MAX = TPM2_PT_FIXED + 40, 197 + TPM2_PT_TOTAL_COMMANDS = TPM2_PT_FIXED + 41, 198 + TPM2_PT_LIBRARY_COMMANDS = TPM2_PT_FIXED + 42, 199 + TPM2_PT_VENDOR_COMMANDS = TPM2_PT_FIXED + 43, 200 + TPM2_PT_NV_BUFFER_MAX = TPM2_PT_FIXED + 44, 201 + TPM2_PT_MODES = TPM2_PT_FIXED + 45, 202 + TPM2_PT_MAX_CAP_BUFFER = TPM2_PT_FIXED + 46, 203 + TPM2_PT_VAR = TPM2_PT_GROUP * 2, 204 + TPM2_PT_PERMANENT = TPM2_PT_VAR + 0, 205 + TPM2_PT_STARTUP_CLEAR = TPM2_PT_VAR + 1, 206 + TPM2_PT_HR_NV_INDEX = TPM2_PT_VAR + 2, 207 + TPM2_PT_HR_LOADED = TPM2_PT_VAR + 3, 208 + TPM2_PT_HR_LOADED_AVAIL = TPM2_PT_VAR + 4, 209 + TPM2_PT_HR_ACTIVE = TPM2_PT_VAR + 5, 210 + TPM2_PT_HR_ACTIVE_AVAIL = TPM2_PT_VAR + 6, 211 + TPM2_PT_HR_TRANSIENT_AVAIL = TPM2_PT_VAR + 7, 212 + TPM2_PT_HR_PERSISTENT = TPM2_PT_VAR + 8, 213 + TPM2_PT_HR_PERSISTENT_AVAIL = TPM2_PT_VAR + 9, 214 + TPM2_PT_NV_COUNTERS = TPM2_PT_VAR + 10, 215 + TPM2_PT_NV_COUNTERS_AVAIL = TPM2_PT_VAR + 11, 216 + TPM2_PT_ALGORITHM_SET = TPM2_PT_VAR + 12, 217 + TPM2_PT_LOADED_CURVES = TPM2_PT_VAR + 13, 218 + TPM2_PT_LOCKOUT_COUNTER = TPM2_PT_VAR + 14, 219 + TPM2_PT_MAX_AUTH_FAIL = TPM2_PT_VAR + 15, 220 + TPM2_PT_LOCKOUT_INTERVAL = TPM2_PT_VAR + 16, 221 + TPM2_PT_LOCKOUT_RECOVERY = TPM2_PT_VAR + 17, 222 + TPM2_PT_NV_WRITE_RECOVERY = TPM2_PT_VAR + 18, 223 + TPM2_PT_AUDIT_COUNTER_0 = TPM2_PT_VAR + 19, 224 + TPM2_PT_AUDIT_COUNTER_1 = TPM2_PT_VAR + 20, 225 + }; 226 227 /* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18 228 * bytes, but 128 is still a relatively large number of random bytes and