1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-21 11:13:30 +00:00

random: x86 driver: Prefer RDSEED over RDRAND when available

Per
https://software.intel.com/en-us/blogs/2012/11/17/the-difference-between-rdrand-and-rdseed
, RDRAND is a PRNG seeded from the same source as RDSEED.  The source is
more suitable as PRNG seed material, so prefer it when the RDSEED intrinsic
is available (indicated in CPU feature bits).

Reviewed by:	delphij, jhb, imp (earlier version)
Approved by:	secteam(delphij)
Security:	yes
Sponsored by:	Dell EMC Isilon
Differential Revision:	https://reviews.freebsd.org/D20192
This commit is contained in:
Conrad Meyer 2019-05-08 00:45:16 +00:00
parent fce2d624ea
commit 2cb54a800c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=347239

View File

@ -44,11 +44,13 @@ __FBSDID("$FreeBSD$");
#include <machine/md_var.h>
#include <machine/specialreg.h>
#include <x86/ifunc.h>
#include <dev/random/randomdev.h>
#define RETRY_COUNT 10
static bool has_rdrand, has_rdseed;
static u_int random_ivy_read(void *, u_int);
static struct random_source random_ivy = {
@ -57,10 +59,9 @@ static struct random_source random_ivy = {
.rs_read = random_ivy_read
};
static inline int
ivy_rng_store(u_long *buf)
static int
x86_rdrand_store(u_long *buf)
{
#ifdef __GNUCLIKE_ASM
u_long rndval;
int retry;
@ -75,9 +76,38 @@ ivy_rng_store(u_long *buf)
: "+r" (retry), "=r" (rndval) : : "cc");
*buf = rndval;
return (retry);
#else /* __GNUCLIKE_ASM */
return (0);
#endif
}
static int
x86_rdseed_store(u_long *buf)
{
u_long rndval;
int retry;
retry = RETRY_COUNT;
__asm __volatile(
"1:\n\t"
"rdseed %1\n\t" /* read randomness into rndval */
"jc 2f\n\t" /* CF is set on success, exit retry loop */
"dec %0\n\t" /* otherwise, retry-- */
"jne 1b\n\t" /* and loop if retries are not exhausted */
"2:"
: "+r" (retry), "=r" (rndval) : : "cc");
*buf = rndval;
return (retry);
}
DEFINE_IFUNC(static, int, x86_rng_store, (u_long *buf), static)
{
has_rdrand = (cpu_feature2 & CPUID2_RDRAND);
has_rdseed = (cpu_stdext_feature & CPUID_STDEXT_RDSEED);
if (has_rdseed)
return (x86_rdseed_store);
else if (has_rdrand)
return (x86_rdrand_store);
else
return (NULL);
}
/* It is required that buf length is a multiple of sizeof(u_long). */
@ -90,7 +120,7 @@ random_ivy_read(void *buf, u_int c)
KASSERT(c % sizeof(*b) == 0, ("partial read %d", c));
b = buf;
for (count = c; count > 0; count -= sizeof(*b)) {
if (ivy_rng_store(&rndval) == 0)
if (x86_rng_store(&rndval) == 0)
break;
*b++ = rndval;
}
@ -104,14 +134,14 @@ rdrand_modevent(module_t mod, int type, void *unused)
switch (type) {
case MOD_LOAD:
if (cpu_feature2 & CPUID2_RDRAND) {
if (has_rdrand || has_rdseed) {
random_source_register(&random_ivy);
printf("random: fast provider: \"%s\"\n", random_ivy.rs_ident);
}
break;
case MOD_UNLOAD:
if (cpu_feature2 & CPUID2_RDRAND)
if (has_rdrand || has_rdseed)
random_source_deregister(&random_ivy);
break;