Skip to content

Commit f1324bb

Browse files
superm1jarkkojs
authored andcommitted
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 b006c43 ("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: b006c43 ("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>
1 parent 80a6c21 commit f1324bb

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed

drivers/char/tpm/tpm-chip.c

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,63 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip)
511511
return 0;
512512
}
513513

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+
514571
static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
515572
{
516573
struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng);
@@ -520,7 +577,8 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
520577

521578
static int tpm_add_hwrng(struct tpm_chip *chip)
522579
{
523-
if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM) || tpm_is_firmware_upgrade(chip))
580+
if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM) || tpm_is_firmware_upgrade(chip) ||
581+
tpm_amd_is_rng_defective(chip))
524582
return 0;
525583

526584
snprintf(chip->hwrng_name, sizeof(chip->hwrng_name),

drivers/char/tpm/tpm.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,79 @@ enum tpm_sub_capabilities {
150150
TPM_CAP_PROP_TIS_DURATION = 0x120,
151151
};
152152

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+
};
153226

154227
/* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18
155228
* bytes, but 128 is still a relatively large number of random bytes and

0 commit comments

Comments
 (0)