From: Mark Wooding Date: Wed, 30 Oct 2019 00:45:11 +0000 (+0000) Subject: base/dispatch.c, etc.: Check that `rdrand' works. X-Git-Tag: 2.4.5~22 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/catacomb/commitdiff_plain/35b1eba81a20fa0b93db161001ad8a46cd0cdc7b base/dispatch.c, etc.: Check that `rdrand' works. When probing for `rdrand', check to make sure that it doesn't just return the same thing every time, and that it can reasonably well make progress. We check that up to five 32-bit samples are not all the same, which will mistakenly mark a working CPU as defective with probability 2^-128. It seems that some processors will return a constant value from `rdrand' but set the carry flag to indicate that it's properly random anyway. See https://arstechnica.com/gadgets/2019/10/how-a-months-old-amd-microcode-bug-destroyed-my-weekend/ as an example. --- diff --git a/base/dispatch.c b/base/dispatch.c index b281ec3d..42c64ee5 100644 --- a/base/dispatch.c +++ b/base/dispatch.c @@ -198,6 +198,59 @@ static int xmm_registers_available_p(void) #endif } +/* --- @rdrand_works_p@ --- * + * + * + * Arguments: --- + * + * Returns: Nonzero if the `rdrand' instruction actually works. Assumes + * that it's already been verified to be safe to issue. + */ + +#ifdef __GNUC__ +static int rdrand(unsigned *x) +{ + int i, rc; + unsigned _t; + + i = 16; + __asm__ ("" : "=g" (_t)); + __asm__ ("0: rdrand %2; jc 1f; decl %1; jnz 0b\n" + "mov $-1, %0; jmp 9f\n" + "1: movl %2, (%3); xorl %0, %0\n" + "9:" + : "=r" (rc), "+r" (i), "+r" (_t) + : "r" (x) + : "cc"); + return (rc); +} +#endif + +static int rdrand_works_p(void) +{ + unsigned ref, x, i; + + /* Check that it doesn't always give the same answer. Try four times: this + * will fail with probability %$2^{-128}$% with a truly random generator, + * which seems fair enough. + */ + if (rdrand(&ref)) goto fail; + for (i = 0; i < 4; i++) { + if (rdrand(&x)) goto fail; + if (x != ref) goto not_stuck; + } + dispatch_debug("RDRAND always returns 0x%08x!", ref); + return (0); + +not_stuck: + dispatch_debug("RDRAND instruction looks plausible"); + return (1); + +fail: + dispatch_debug("RDRAND instruction fails too often"); + return (0); +} + #endif /*----- General feature probing using auxiliary vectors -------------------*/ @@ -544,7 +597,7 @@ int cpu_feature_p(int feat) cpuid_features_p(CPUID1D_SSE2, CPUID1C_AESNI) && xmm_registers_available_p()); CASE_CPUFEAT(X86_RDRAND, "x86:rdrand", - cpuid_features_p(0, CPUID1C_RDRAND)); + cpuid_features_p(0, CPUID1C_RDRAND) && rdrand_works_p()); #endif #ifdef CAPMAP # define FEATP__CASE(feat, tok) \