From cfb1839187d6abdb1e89b50f1970e5829bd3c10a Mon Sep 17 00:00:00 2001 From: Hannes Mehnert Date: Wed, 26 Feb 2020 14:12:08 +0100 Subject: [PATCH] check rdrand and rdseed return values (CR=1), as recommended by Intel https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide detect and disable bad rdrand on AMD ryzen 3000, which returns all-ones https://arstechnica.com/gadgets/2019/10/how-a-months-old-amd-microcode-bug-destroyed-my-weekend/ --- src/native/entropy_cpu_stubs.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/native/entropy_cpu_stubs.c b/src/native/entropy_cpu_stubs.c index 360efe6b..4b5d1425 100644 --- a/src/native/entropy_cpu_stubs.c +++ b/src/native/entropy_cpu_stubs.c @@ -59,17 +59,27 @@ enum cpu_rng_t { static enum cpu_rng_t __cpu_rng = RNG_NONE; +#define RETRIES 10 + static void detect () { #if defined (__x86__) unsigned int sig, eax, ebx, ecx, edx; int max = __get_cpuid_max (0, &sig); + random_t r = 0; if (max < 1) return; if (sig == signature_INTEL_ebx || sig == signature_AMD_ebx) { __cpuid (1, eax, ebx, ecx, edx); - if (ecx & bit_RDRND) __cpu_rng = RNG_RDRAND; + if (ecx & bit_RDRND) { + /* AMD Ryzen 3000 bug where RDRAND always returns 0xFFFFFFFF */ + for (int i = 0; i < RETRIES; i++) + if (_rdrand_step(&r) == 1 && r != (random_t) (-1)) { + __cpu_rng = RNG_RDRAND; + break; + } + } if (max > 7) { __cpuid_count (7, 0, eax, ebx, ecx, edx); if (ebx & bit_RDSEED) __cpu_rng = RNG_RDSEED; @@ -91,12 +101,14 @@ CAMLprim value caml_cycle_counter (value __unused(unit)) { CAMLprim value caml_cpu_random (value __unused(unit)) { #if defined (__x86__) random_t r = 0; - if (__cpu_rng == RNG_RDSEED) { - _rdseed_step (&r); - } else if (__cpu_rng == RNG_RDRAND) { - _rdrand_step (&r); + for (int i = 0; i < RETRIES; i++) { + if (__cpu_rng == RNG_RDSEED) { + if (_rdseed_step (&r) == 1) return Val_long (r); + } else if (__cpu_rng == RNG_RDRAND) { + if (_rdrand_step (&r) == 1) return Val_long (r); + } } - return Val_long (r); /* Zeroed-out if carry == 0. */ + return Val_long (0); #else /* ARM: CPU-assisted randomness here. */ return Val_long (0);