You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
6.0 KiB
214 lines
6.0 KiB
5 months ago
|
From 1d4b6d489cb919faa3ad67a3ae53fe26c4cd0a75 Mon Sep 17 00:00:00 2001
|
||
|
From: Jon Maloy <jmaloy@redhat.com>
|
||
|
Date: Thu, 20 Jun 2024 10:32:29 -0400
|
||
|
Subject: [PATCH 25/31] MdePkg/BaseRngLib: Add a smoketest for RDRAND and check
|
||
|
CPUID
|
||
|
|
||
|
RH-Author: Jon Maloy <jmaloy@redhat.com>
|
||
|
RH-MergeRequest: 77: UINT32 overflow in S3 ResumeCount and Pixiefail fixes
|
||
|
RH-Jira: RHEL-21854 RHEL-21856 RHEL-40099
|
||
|
RH-Acked-by: Gerd Hoffmann <None>
|
||
|
RH-Commit: [25/31] 11804d6f86a644ae2c3dcad89c633ad63b794d3f
|
||
|
|
||
|
JIRA: https://issues.redhat.com/browse/RHEL-21856
|
||
|
Upstream: Merged
|
||
|
CVE: CVE-2023-45237
|
||
|
|
||
|
commit c3a8ca7b54a9fd17acdf16c6282a92cc989fa92a
|
||
|
Author: Pedro Falcato <pedro.falcato@gmail.com>
|
||
|
Date: Tue Nov 22 22:31:03 2022 +0000
|
||
|
|
||
|
MdePkg/BaseRngLib: Add a smoketest for RDRAND and check CPUID
|
||
|
|
||
|
RDRAND has notoriously been broken many times over its lifespan.
|
||
|
Add a smoketest to RDRAND, in order to better sniff out potential
|
||
|
security concerns.
|
||
|
|
||
|
Also add a proper CPUID test in order to support older CPUs which may
|
||
|
not have it; it was previously being tested but then promptly ignored.
|
||
|
|
||
|
Testing algorithm inspired by linux's arch/x86/kernel/cpu/rdrand.c
|
||
|
:x86_init_rdrand() per commit 049f9ae9..
|
||
|
|
||
|
Many thanks to Jason Donenfeld for relicensing his linux RDRAND detection
|
||
|
code to MIT and the public domain.
|
||
|
|
||
|
>On Tue, Nov 22, 2022 at 2:21 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
|
||
|
<..>
|
||
|
> I (re)wrote that function in Linux. I hereby relicense it as MIT, and
|
||
|
> also place it into public domain. Do with it what you will now.
|
||
|
>
|
||
|
> Jason
|
||
|
|
||
|
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4163
|
||
|
|
||
|
Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
|
||
|
Cc: Michael D Kinney <michael.d.kinney@intel.com>
|
||
|
Cc: Liming Gao <gaoliming@byosoft.com.cn>
|
||
|
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
|
||
|
Cc: Jason A. Donenfeld <Jason@zx2c4.com>
|
||
|
|
||
|
Signed-off-by: Jon Maloy <jmaloy@gmail.com>
|
||
|
---
|
||
|
MdePkg/Library/BaseRngLib/Rand/RdRand.c | 99 +++++++++++++++++++++++--
|
||
|
1 file changed, 91 insertions(+), 8 deletions(-)
|
||
|
|
||
|
diff --git a/MdePkg/Library/BaseRngLib/Rand/RdRand.c b/MdePkg/Library/BaseRngLib/Rand/RdRand.c
|
||
|
index aee8ea04e8..7132ab0efd 100644
|
||
|
--- a/MdePkg/Library/BaseRngLib/Rand/RdRand.c
|
||
|
+++ b/MdePkg/Library/BaseRngLib/Rand/RdRand.c
|
||
|
@@ -3,6 +3,7 @@
|
||
|
to provide high-quality random numbers.
|
||
|
|
||
|
Copyright (c) 2023, Arm Limited. All rights reserved.<BR>
|
||
|
+Copyright (c) 2022, Pedro Falcato. All rights reserved.<BR>
|
||
|
Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
|
||
|
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
|
||
|
|
||
|
@@ -25,6 +26,88 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
|
||
|
STATIC BOOLEAN mRdRandSupported;
|
||
|
|
||
|
+//
|
||
|
+// Intel SDM says 10 tries is good enough for reliable RDRAND usage.
|
||
|
+//
|
||
|
+#define RDRAND_RETRIES 10
|
||
|
+
|
||
|
+#define RDRAND_TEST_SAMPLES 8
|
||
|
+
|
||
|
+#define RDRAND_MIN_CHANGE 5
|
||
|
+
|
||
|
+//
|
||
|
+// Add a define for native-word RDRAND, just for the test.
|
||
|
+//
|
||
|
+#ifdef MDE_CPU_X64
|
||
|
+#define ASM_RDRAND AsmRdRand64
|
||
|
+#else
|
||
|
+#define ASM_RDRAND AsmRdRand32
|
||
|
+#endif
|
||
|
+
|
||
|
+/**
|
||
|
+ Tests RDRAND for broken implementations.
|
||
|
+
|
||
|
+ @retval TRUE RDRAND is reliable (and hopefully safe).
|
||
|
+ @retval FALSE RDRAND is unreliable and should be disabled, despite CPUID.
|
||
|
+
|
||
|
+**/
|
||
|
+STATIC
|
||
|
+BOOLEAN
|
||
|
+TestRdRand (
|
||
|
+ VOID
|
||
|
+ )
|
||
|
+{
|
||
|
+ //
|
||
|
+ // Test for notoriously broken rdrand implementations that always return the same
|
||
|
+ // value, like the Zen 3 uarch (all-1s) or other several AMD families on suspend/resume (also all-1s).
|
||
|
+ // Note that this should be expanded to extensively test for other sorts of possible errata.
|
||
|
+ //
|
||
|
+
|
||
|
+ //
|
||
|
+ // Our algorithm samples rdrand $RDRAND_TEST_SAMPLES times and expects
|
||
|
+ // a different result $RDRAND_MIN_CHANGE times for reliable RDRAND usage.
|
||
|
+ //
|
||
|
+ UINTN Prev;
|
||
|
+ UINT8 Idx;
|
||
|
+ UINT8 TestIteration;
|
||
|
+ UINT32 Changed;
|
||
|
+
|
||
|
+ Changed = 0;
|
||
|
+
|
||
|
+ for (TestIteration = 0; TestIteration < RDRAND_TEST_SAMPLES; TestIteration++) {
|
||
|
+ UINTN Sample;
|
||
|
+ //
|
||
|
+ // Note: We use a retry loop for rdrand. Normal users get this in BaseRng.c
|
||
|
+ // Any failure to get a random number will assume RDRAND does not work.
|
||
|
+ //
|
||
|
+ for (Idx = 0; Idx < RDRAND_RETRIES; Idx++) {
|
||
|
+ if (ASM_RDRAND (&Sample)) {
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (Idx == RDRAND_RETRIES) {
|
||
|
+ DEBUG ((DEBUG_ERROR, "BaseRngLib/x86: CPU BUG: Failed to get an RDRAND random number - disabling\n"));
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (TestIteration != 0) {
|
||
|
+ Changed += Sample != Prev;
|
||
|
+ }
|
||
|
+
|
||
|
+ Prev = Sample;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (Changed < RDRAND_MIN_CHANGE) {
|
||
|
+ DEBUG ((DEBUG_ERROR, "BaseRngLib/x86: CPU BUG: RDRAND not reliable - disabling\n"));
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+#undef ASM_RDRAND
|
||
|
+
|
||
|
/**
|
||
|
The constructor function checks whether or not RDRAND instruction is supported
|
||
|
by the host hardware.
|
||
|
@@ -49,10 +132,13 @@ BaseRngLibConstructor (
|
||
|
// CPUID. A value of 1 indicates that processor support RDRAND instruction.
|
||
|
//
|
||
|
AsmCpuid (1, 0, 0, &RegEcx, 0);
|
||
|
- ASSERT ((RegEcx & RDRAND_MASK) == RDRAND_MASK);
|
||
|
|
||
|
mRdRandSupported = ((RegEcx & RDRAND_MASK) == RDRAND_MASK);
|
||
|
|
||
|
+ if (mRdRandSupported) {
|
||
|
+ mRdRandSupported = TestRdRand ();
|
||
|
+ }
|
||
|
+
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
@@ -71,6 +157,7 @@ ArchGetRandomNumber16 (
|
||
|
OUT UINT16 *Rand
|
||
|
)
|
||
|
{
|
||
|
+ ASSERT (mRdRandSupported);
|
||
|
return AsmRdRand16 (Rand);
|
||
|
}
|
||
|
|
||
|
@@ -89,6 +176,7 @@ ArchGetRandomNumber32 (
|
||
|
OUT UINT32 *Rand
|
||
|
)
|
||
|
{
|
||
|
+ ASSERT (mRdRandSupported);
|
||
|
return AsmRdRand32 (Rand);
|
||
|
}
|
||
|
|
||
|
@@ -107,6 +195,7 @@ ArchGetRandomNumber64 (
|
||
|
OUT UINT64 *Rand
|
||
|
)
|
||
|
{
|
||
|
+ ASSERT (mRdRandSupported);
|
||
|
return AsmRdRand64 (Rand);
|
||
|
}
|
||
|
|
||
|
@@ -123,13 +212,7 @@ ArchIsRngSupported (
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
- /*
|
||
|
- Existing software depends on this always returning TRUE, so for
|
||
|
- now hard-code it.
|
||
|
-
|
||
|
- return mRdRandSupported;
|
||
|
- */
|
||
|
- return TRUE;
|
||
|
+ return mRdRandSupported;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
--
|
||
|
2.39.3
|
||
|
|