From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f44.google.com (mail-wr1-f44.google.com [209.85.221.44]) by mx.groups.io with SMTP id smtpd.web11.5191.1669154645667191863 for ; Tue, 22 Nov 2022 14:04:06 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20210112 header.b=e36cHNV5; spf=pass (domain: gmail.com, ip: 209.85.221.44, mailfrom: pedro.falcato@gmail.com) Received: by mail-wr1-f44.google.com with SMTP id b12so13078431wrn.2 for ; Tue, 22 Nov 2022 14:04:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=B9p1bhzC68wCWc8az6GzzkM+deqfL2xySGCMulwFkrQ=; b=e36cHNV5p4sWD3qntgc7zg2V796P10I+0MMbmSg9RMCbs9KfW5W84dhctVAq2kukTy gqGagILMjS7xDkmrGSxRmUmxNv9nB3tpV35KdIuRioE+Z8suu7ZyLq4SxhTXCHvA29fA F7D6dcSoVCRcc5U7cFoUBanVneq4MGr0I+KjD4xecQUxMbKKf1Ct/mv9beWYtx+KQG8v I3VL75F6y9CBA5ALXQS6Or1Wfa+sJVUkyLbbr6vSVie65HLUh4ubEy2++NoBZeSJRk3T PjRJM39DrczdRtr/BI/39OQ6om7318vmSteFEVhbsKLq+TVU1S9D240Z/FVxwwFKRcFz +FEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=B9p1bhzC68wCWc8az6GzzkM+deqfL2xySGCMulwFkrQ=; b=lrFRDG+MzWB0Tn811ETKB7pWrsTwEwIm8415ep8EiD6zk8BAI+AcR/vlmbSr2EQNS/ y/hYtYhCt2/4xu3xBVdLn/jmJ/F9e4ROVfnH8UZzK2hSihV301cggG5oCzyEU0kEx5/o J/x9OWC5zrCW2BgINioJQ98ilejvpBg5CV+ylAZNH9ZVbQMqPWuoT7HfrrQczCd5uL9r qhSf914rUbOM/xxnPV1qHyH6XEvPF7ZMei+HlunFP9J+j9wy7BNMT9Wlsckh6/jHxpli PzmgrJ/JIOC5f+peHN1BxrPF8h5xh8u3aUy7n3JauIdcPAilKM/414tj+YVbg6ZPgn1d EOGw== X-Gm-Message-State: ANoB5pmktTmhT7+8EmR2W/ZZrI47EmHP23pHUbW8lJ0rsa6bYPTGQl8m Rebe8iiZc8X/F7bPgetBDUxKsGJCGWHUtMBY X-Google-Smtp-Source: AA0mqf4rP9ZtegtTH3fc+MoK1hp9fQ/yQLzuYx7NxNGK6VPf2X6Dw+hyD32guVh+23cC5EdDPjETCw== X-Received: by 2002:a05:6000:1cc:b0:241:a59b:ed46 with SMTP id t12-20020a05600001cc00b00241a59bed46mr3906369wrx.77.1669154643686; Tue, 22 Nov 2022 14:04:03 -0800 (PST) Return-Path: Received: from PC-PEDRO-ARCH.lan ([2001:8a0:7280:5801:9441:3dce:686c:bfc7]) by smtp.gmail.com with ESMTPSA id v18-20020a5d6112000000b00236e834f050sm14743952wrt.35.2022.11.22.14.04.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Nov 2022 14:04:03 -0800 (PST) From: "Pedro Falcato" To: devel@edk2.groups.io Cc: Pedro Falcato , Michael D Kinney , Liming Gao , Zhiguang Liu , "Jason A . Donenfeld" Subject: [PATCH v3 1/1] MdePkg/BaseRngLib: Add a smoketest for RDRAND and check CPUID Date: Tue, 22 Nov 2022 22:03:56 +0000 Message-Id: <20221122220356.595358-1-pedro.falcato@gmail.com> X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 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 Cc: Michael D Kinney Cc: Liming Gao Cc: Zhiguang Liu Cc: Jason A. Donenfeld --- MdePkg/Library/BaseRngLib/Rand/RdRand.c | 92 ++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 8 deletions(-) diff --git a/MdePkg/Library/BaseRngLib/Rand/RdRand.c b/MdePkg/Library/BaseRngLib/Rand/RdRand.c index 070d41e2555f..b5acd7da89a8 100644 --- a/MdePkg/Library/BaseRngLib/Rand/RdRand.c +++ b/MdePkg/Library/BaseRngLib/Rand/RdRand.c @@ -2,6 +2,7 @@ Random number generator services that uses RdRand instruction access to provide high-quality random numbers. +Copyright (c) 2022, Pedro Falcato. All rights reserved.
Copyright (c) 2021, NUVIA Inc. All rights reserved.
Copyright (c) 2015, Intel Corporation. All rights reserved.
@@ -22,6 +23,81 @@ 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 AsmRdRand AsmRdRand64 +#else +#define AsmRdRand AsmRdRand32 +#endif + +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 (AsmRdRand (&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 AsmRdRand + /** The constructor function checks whether or not RDRAND instruction is supported by the host hardware. @@ -46,10 +122,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; } @@ -68,6 +147,7 @@ ArchGetRandomNumber16 ( OUT UINT16 *Rand ) { + ASSERT (mRdRandSupported); return AsmRdRand16 (Rand); } @@ -86,6 +166,7 @@ ArchGetRandomNumber32 ( OUT UINT32 *Rand ) { + ASSERT (mRdRandSupported); return AsmRdRand32 (Rand); } @@ -104,6 +185,7 @@ ArchGetRandomNumber64 ( OUT UINT64 *Rand ) { + ASSERT (mRdRandSupported); return AsmRdRand64 (Rand); } @@ -120,11 +202,5 @@ ArchIsRngSupported ( VOID ) { - /* - Existing software depends on this always returning TRUE, so for - now hard-code it. - - return mRdRandSupported; - */ - return TRUE; + return mRdRandSupported; } -- 2.38.1