]> git.baikalelectronics.ru Git - kernel.git/commitdiff
x86/rdrand: Remove "nordrand" flag in favor of "random.trust_cpu"
authorJason A. Donenfeld <Jason@zx2c4.com>
Sat, 9 Jul 2022 10:43:06 +0000 (12:43 +0200)
committerJason A. Donenfeld <Jason@zx2c4.com>
Mon, 18 Jul 2022 13:04:04 +0000 (15:04 +0200)
The decision of whether or not to trust RDRAND is controlled by the
"random.trust_cpu" boot time parameter or the CONFIG_RANDOM_TRUST_CPU
compile time default. The "nordrand" flag was added during the early
days of RDRAND, when there were worries that merely using its values
could compromise the RNG. However, these days, RDRAND values are not
used directly but always go through the RNG's hash function, making
"nordrand" no longer useful.

Rather, the correct switch is "random.trust_cpu", which not only handles
the relevant trust issue directly, but also is general to multiple CPU
types, not just x86.

However, x86 RDRAND does have a history of being occasionally
problematic. Prior, when the kernel would notice something strange, it'd
warn in dmesg and suggest enabling "nordrand". We can improve on that by
making the test a little bit better and then taking the step of
automatically disabling RDRAND if we detect it's problematic.

Also disable RDSEED if the RDRAND test fails.

Cc: x86@kernel.org
Cc: Theodore Ts'o <tytso@mit.edu>
Suggested-by: H. Peter Anvin <hpa@zytor.com>
Suggested-by: Borislav Petkov <bp@suse.de>
Acked-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Documentation/admin-guide/kernel-parameters.txt
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/rdrand.c

index f2d26cb7e85391028376424b9daac448df69c015..1e2307f1110502646873ec441d3f74cacc954b17 100644 (file)
        noreplace-smp   [X86-32,SMP] Don't replace SMP instructions
                        with UP alternatives
 
-       nordrand        [X86] Disable kernel use of the RDRAND and
-                       RDSEED instructions even if they are supported
-                       by the processor.  RDRAND and RDSEED are still
-                       available to user space applications.
-
        noresume        [SWSUSP] Disables resume and restores original swap
                        space.
 
index 35d5288394cb82f187b4314e0795f6cef5343dd8..48276c0e479d824bb014f92fbe413086b372c13a 100644 (file)
@@ -808,7 +808,7 @@ static void clear_rdrand_cpuid_bit(struct cpuinfo_x86 *c)
                return;
 
        /*
-        * The nordrand option can clear X86_FEATURE_RDRAND, so check for
+        * 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)
index 8f216669ecb81b179e2c70963818a454852b7f96..26a427fa84eab5f90d12e26ebe2bf0e8f013b735 100644 (file)
 #include <asm/archrandom.h>
 #include <asm/sections.h>
 
-static int __init x86_rdrand_setup(char *s)
-{
-       setup_clear_cpu_cap(X86_FEATURE_RDRAND);
-       setup_clear_cpu_cap(X86_FEATURE_RDSEED);
-       return 1;
-}
-__setup("nordrand", x86_rdrand_setup);
-
 /*
  * RDRAND has Built-In-Self-Test (BIST) that runs on every invocation.
- * Run the instruction a few times as a sanity check.
- * If it fails, it is simple to disable RDRAND here.
+ * Run the instruction a few times as a sanity check. Also make sure
+ * it's not outputting the same value over and over, which has happened
+ * as a result of past CPU bugs.
+ *
+ * If it fails, it is simple to disable RDRAND and RDSEED here.
  */
-#define SANITY_CHECK_LOOPS 8
 
 void x86_init_rdrand(struct cpuinfo_x86 *c)
 {
-       unsigned int changed = 0;
-       unsigned long tmp, prev;
-       int i;
+       enum { SAMPLES = 8, MIN_CHANGE = 5 };
+       unsigned long sample, prev;
+       bool failure = false;
+       size_t i, changed;
 
        if (!cpu_has(c, X86_FEATURE_RDRAND))
                return;
 
-       for (i = 0; i < SANITY_CHECK_LOOPS; i++) {
-               if (!rdrand_long(&tmp)) {
-                       clear_cpu_cap(c, X86_FEATURE_RDRAND);
-                       pr_warn_once("rdrand: disabled\n");
-                       return;
+       for (changed = 0, i = 0; i < SAMPLES; ++i) {
+               if (!rdrand_long(&sample)) {
+                       failure = true;
+                       break;
                }
+               changed += i && sample != prev;
+               prev = sample;
        }
+       if (changed < MIN_CHANGE)
+               failure = true;
 
-       /*
-        * Stupid sanity-check whether RDRAND does *actually* generate
-        * some at least random-looking data.
-        */
-       prev = tmp;
-       for (i = 0; i < SANITY_CHECK_LOOPS; i++) {
-               if (rdrand_long(&tmp)) {
-                       if (prev != tmp)
-                               changed++;
-
-                       prev = tmp;
-               }
+       if (failure) {
+               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");
        }
-
-       if (WARN_ON_ONCE(!changed))
-               pr_emerg(
-"RDRAND gives funky smelling output, might consider not using it by booting with \"nordrand\"");
-
 }