From nobody Wed Jun 17 01:42:10 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7EBA044D022 for ; Tue, 28 Apr 2026 17:36:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777397761; cv=none; b=rgx779StEwrFB/LER4UmxDt5nm77GX7jBVB/QinxUdI02v25jwRyY4zYCghpk0P1kpggpdyPi7bfi9BTf45Jwnk1uYCdgJXUZ3vGzuxBg6ACHsaQv4Y0Cfy2C3sm30ek0cQUh7DRd89lM8m9D4ggTXKJRoY7LPhtZqBZ1/3hBZ0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777397761; c=relaxed/simple; bh=Vk+FEIjsiUI12yJdxZupYsxsTHu9VbvXnHuZTVjph0o=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=tYH3KTpef6qiagezLP+VzEfVzV+BjwnH+ERQEW1yMHxcQgV83/Teb0rhR/01+3mbhavKl2w2h01Ewvv/6bX4505c8TOCnYE3QRDozIEgavrLK3rRwYGEsLYKi1AGSBf9OdfzF00Wr7NdNA7WZhzC0VSFLwDkzhW0QHAM73kOh9M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AgaPQJdM; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="AgaPQJdM" Received: by smtp.kernel.org (Postfix) with ESMTPS id 0884DC2BCAF; Tue, 28 Apr 2026 17:36:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777397761; bh=Vk+FEIjsiUI12yJdxZupYsxsTHu9VbvXnHuZTVjph0o=; h=From:Date:Subject:To:Cc:Reply-To:From; b=AgaPQJdMcHDz3NGdTAaCb+Js2s5IEXWIw9AEH8YDB+GZjH7d2BOqX11jH0cvQZCPX 61K/nVU6qtsK/h9PpvMPIMN63z0zCClbAbQSZqco0boAExSS55NcatlAgxC+IkCPAR cwr5rLf459nG0W8Vle3CKIkMMKVUnAShxLczjwA4B5yzbI47Y3ElTsCmysqWYsWND5 ZdcsB9iuLOE74WZ7wKxxAhrMkhsCUMsSYDiZeFKjQS7zXDAJMoyyoOPn6huomfpZdV j0qlZnlBWBjlDBCNBIyLQLUMySZLxecVSC8TireIG3E2TuPlxSd6npv19aei64nxmK /UHutauqufUHQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id EA725FF885A; Tue, 28 Apr 2026 17:36:00 +0000 (UTC) From: Dmitry Safonov via B4 Relay Date: Tue, 28 Apr 2026 18:35:31 +0100 Subject: [PATCH] x86/CPU/AMD: Clear RDRAND CPUID if Built-In-Self-Test failed on boot Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260428-rdrand-cpubug-v1-1-ac8384c841f3@arista.com> X-B4-Tracking: v=1; b=H4sIAOLv8GkC/x3MQQrDIBBA0auEWXdoFLHQq5QuRp0kA60NYwxCy N1ru3yL/w8orMIF7sMByrsU+eQOcxkgLpRnRkndYEfrR2dvqEkpJ4xrDXVGb5g8Td44F6E3q/I k7f97PLsDFcbQi7j8Li/JtWHmtl3fVDZWOM8vixJMzoMAAAA= X-Change-ID: 20260427-rdrand-cpubug-61ea6af6144c To: Borislav Petkov , Dave Hansen , "H. Peter Anvin" , Ingo Molnar , Thomas Gleixner Cc: Dmitry Safonov <0x7f454c46@gmail.com>, Tom Lendacky , Peter Edwards , linux-kernel@vger.kernel.org, x86@kernel.org, Dmitry Safonov X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1777397760; l=6222; i=dima@arista.com; s=20250521; h=from:subject:message-id; bh=zY+/MadCaKRzhuk03rxiuRI9MDX1T0Cjb1oF6jSoXlk=; b=1/59vjE9pz0UUKGsNFUNAMOyCKCamwtkhrtxCFdV32i7bNx1DB0Q3xtl7v1/ivXGFKcJBNqGS B5dSF1AZJl8CA55gUAc+B5Znz9ro/1Tj7Dhz5TLOWdUOdVwrDLEbkrA X-Developer-Key: i=dima@arista.com; a=ed25519; pk=/z94x2T59rICwjRqYvDsBe0MkpbkkdYrSW2J1G2gIcU= X-Endpoint-Received: by B4 Relay for dima@arista.com/20250521 with auth_id=405 X-Original-From: Dmitry Safonov Reply-To: dima@arista.com From: Dmitry Safonov On AMD Embedded R-Series RX-421ND (family: 0x15, model: 0x60, stepping: 0x1) with microcode revision 0x0600611a RDRAND is constantly giving zeros: : #include : #include : #define _rdrand(x) ({ unsigned char err; asm volatile("rdrand %0; setc %1= ":"=3Dr"(*x), "=3Dqm"(err)); err; }) : : int main(int argc, char *argv[]) : { : uint64_t x; : int i; : : for (i =3D 0; i < 20; i++) { : _rdrand(&x); : printf("%llx ", x); : } : putchar('\n'); : return 0; : } Prints: : # /tmp/check : 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 BIST correctly detects a broken implementation on boot: [..] RDRAND is not reliable on this platform; disabling. ... [..] smpboot: x86: Booting SMP configuration: [..] .... node #0, CPUs: #1 #2 #3 [..] RDRAND is not reliable on this platform; disabling. [..] RDRAND is not reliable on this platform; disabling. [..] RDRAND is not reliable on this platform; disabling. [..] smp: Brought up 1 node, 4 CPUs Yet, CPUID gets cleared only for previously known broken implementations, see i.e., commit c49a0a80137c ("x86/CPU/AMD: Clear RDRAND CPUID bit on AMD family 15h/16h"), that disabled RDRAND on the same CPU family, where it was broken only after suspend-resume. As RDRAND is not masked in CPUID, some userspace may attempt using it, for example, libstdc++ with the following reproducer (thanks to Peter): : #include : #include : int main() { : std::random_device rd; : std::uniform_int_distribution dist(0, 9); : for (int i =3D 0; i < 10; ++i) : std::cout << dist(rd) << " "; : std::cout << "\n"; : } crashes when RDRAND is unmasked: : # /tmp/rdrand : terminate called after throwing an instance of 'std::runtime_error' : what(): random_device: rdrand failed : Aborted (core dumped) Some userspace already migrated to vgetrandom() instead of raw RDRAND, i.e. systemd [1] and glibc [2], yet unfortunately, some hasn't. Let Built-In-Self-Test mask CPUID on AMD with MSR register when it detects that implementation is not functioning. [1]: https://github.com/systemd/systemd/commit/ffa047a03e4c5f6bd3af73b7eecb= 99cd230fe204 [2]: https://sourceware.org/git/?p=3Dglibc.git;a=3Dcommit;h=3D461cab1de747f= 3842f27a5d24977d78d561d45f9 Signed-off-by: Dmitry Safonov --- arch/x86/include/asm/processor.h | 5 +++++ arch/x86/kernel/cpu/amd.c | 28 +++++++++++++++------------- arch/x86/kernel/cpu/rdrand.c | 1 + 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/proces= sor.h index 10b5355b323e..23c980697cc5 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -716,9 +716,14 @@ static __always_inline void amd_clear_divider(void) } =20 extern void amd_check_microcode(void); +extern int amd_try_clear_rdrand_cpuid(struct cpuinfo_x86 *c); #else static inline void amd_clear_divider(void) { } static inline void amd_check_microcode(void) { } +static inline int amd_try_clear_rdrand_cpuid(struct cpuinfo_x86 *c) +{ + return 0; +} #endif =20 extern unsigned long arch_align_stack(unsigned long sp); diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 2d9ae6ab1701..37a2ce19845a 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -808,22 +808,16 @@ static int __init rdrand_cmdline(char *str) } early_param("rdrand", rdrand_cmdline); =20 -static void clear_rdrand_cpuid_bit(struct cpuinfo_x86 *c) +int amd_try_clear_rdrand_cpuid(struct cpuinfo_x86 *c) { /* * Saving of the MSR used to hide the RDRAND support during - * suspend/resume is done by arch/x86/power/cpu.c, which is - * dependent on CONFIG_PM_SLEEP. - */ - if (!IS_ENABLED(CONFIG_PM_SLEEP)) - return; - - /* + * suspend/resume is done by arch/x86/power/cpu.c * The self-test can clear X86_FEATURE_RDRAND, so check for * RDRAND support using the CPUID function directly. */ if (!(cpuid_ecx(1) & BIT(30)) || rdrand_force) - return; + return -1; =20 msr_clear_bit(MSR_AMD64_CPUID_FN_1, 62); =20 @@ -833,11 +827,17 @@ static void clear_rdrand_cpuid_bit(struct cpuinfo_x86= *c) */ if (cpuid_ecx(1) & BIT(30)) { pr_info_once("BIOS may not properly restore RDRAND after suspend, but hy= pervisor does not support hiding RDRAND via CPUID.\n"); - return; + return -1; } =20 - clear_cpu_cap(c, X86_FEATURE_RDRAND); pr_info_once("BIOS may not properly restore RDRAND after suspend, hiding = RDRAND via CPUID. Use rdrand=3Dforce to reenable.\n"); + return 0; +} + +static void clear_rdrand_cpuid(struct cpuinfo_x86 *c) +{ + if (!amd_try_clear_rdrand_cpuid(c)) + clear_cpu_cap(c, X86_FEATURE_RDRAND); } =20 static void init_amd_jg(struct cpuinfo_x86 *c) @@ -847,7 +847,8 @@ static void init_amd_jg(struct cpuinfo_x86 *c) * across suspend and resume. Check on whether to hide the RDRAND * instruction support via CPUID. */ - clear_rdrand_cpuid_bit(c); + if (IS_ENABLED(CONFIG_PM_SLEEP)) + clear_rdrand_cpuid(c); } =20 static void init_amd_bd(struct cpuinfo_x86 *c) @@ -870,7 +871,8 @@ static void init_amd_bd(struct cpuinfo_x86 *c) * across suspend and resume. Check on whether to hide the RDRAND * instruction support via CPUID. */ - clear_rdrand_cpuid_bit(c); + if (IS_ENABLED(CONFIG_PM_SLEEP)) + clear_rdrand_cpuid(c); } =20 static const struct x86_cpu_id erratum_1386_microcode[] =3D { diff --git a/arch/x86/kernel/cpu/rdrand.c b/arch/x86/kernel/cpu/rdrand.c index eeac00d20926..1075e18a75f6 100644 --- a/arch/x86/kernel/cpu/rdrand.c +++ b/arch/x86/kernel/cpu/rdrand.c @@ -43,6 +43,7 @@ void x86_init_rdrand(struct cpuinfo_x86 *c) failure =3D true; =20 if (failure) { + amd_try_clear_rdrand_cpuid(c); clear_cpu_cap(c, X86_FEATURE_RDRAND); clear_cpu_cap(c, X86_FEATURE_RDSEED); pr_emerg("RDRAND is not reliable on this platform; disabling.\n"); --- base-commit: 9974969c14031a097d6b45bcb7a06bb4aa525c40 change-id: 20260427-rdrand-cpubug-61ea6af6144c Best regards, --=20 Dmitry Safonov