Skip to content

Commit 69efea7

Browse files
zx2c4tytso
authored andcommitted
random: always use batched entropy for get_random_u{32,64}
It turns out that RDRAND is pretty slow. Comparing these two constructions: for (i = 0; i < CHACHA_BLOCK_SIZE; i += sizeof(ret)) arch_get_random_long(&ret); and long buf[CHACHA_BLOCK_SIZE / sizeof(long)]; extract_crng((u8 *)buf); it amortizes out to 352 cycles per long for the top one and 107 cycles per long for the bottom one, on Coffee Lake Refresh, Intel Core i9-9880H. And importantly, the top one has the drawback of not benefiting from the real rng, whereas the bottom one has all the nice benefits of using our own chacha rng. As get_random_u{32,64} gets used in more places (perhaps beyond what it was originally intended for when it was introduced as get_random_{int,long} back in the md5 monstrosity era), it seems like it might be a good thing to strengthen its posture a tiny bit. Doing this should only be stronger and not any weaker because that pool is already initialized with a bunch of rdrand data (when available). This way, we get the benefits of the hardware rng as well as our own rng. Another benefit of this is that we no longer hit pitfalls of the recent stream of AMD bugs in RDRAND. One often used code pattern for various things is: do { val = get_random_u32(); } while (hash_table_contains_key(val)); That recent AMD bug rendered that pattern useless, whereas we're really very certain that chacha20 output will give pretty distributed numbers, no matter what. So, this simplification seems better both from a security perspective and from a performance perspective. Signed-off-by: Jason A. Donenfeld <[email protected]> Reviewed-by: Greg Kroah-Hartman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 23ae0c1 commit 69efea7

File tree

1 file changed

+4
-16
lines changed

1 file changed

+4
-16
lines changed

drivers/char/random.c

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2177,11 +2177,11 @@ struct batched_entropy {
21772177

21782178
/*
21792179
* Get a random word for internal kernel use only. The quality of the random
2180-
* number is either as good as RDRAND or as good as /dev/urandom, with the
2181-
* goal of being quite fast and not depleting entropy. In order to ensure
2180+
* number is good as /dev/urandom, but there is no backtrack protection, with
2181+
* the goal of being quite fast and not depleting entropy. In order to ensure
21822182
* that the randomness provided by this function is okay, the function
2183-
* wait_for_random_bytes() should be called and return 0 at least once
2184-
* at any point prior.
2183+
* wait_for_random_bytes() should be called and return 0 at least once at any
2184+
* point prior.
21852185
*/
21862186
static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64) = {
21872187
.batch_lock = __SPIN_LOCK_UNLOCKED(batched_entropy_u64.lock),
@@ -2194,15 +2194,6 @@ u64 get_random_u64(void)
21942194
struct batched_entropy *batch;
21952195
static void *previous;
21962196

2197-
#if BITS_PER_LONG == 64
2198-
if (arch_get_random_long((unsigned long *)&ret))
2199-
return ret;
2200-
#else
2201-
if (arch_get_random_long((unsigned long *)&ret) &&
2202-
arch_get_random_long((unsigned long *)&ret + 1))
2203-
return ret;
2204-
#endif
2205-
22062197
warn_unseeded_randomness(&previous);
22072198

22082199
batch = raw_cpu_ptr(&batched_entropy_u64);
@@ -2227,9 +2218,6 @@ u32 get_random_u32(void)
22272218
struct batched_entropy *batch;
22282219
static void *previous;
22292220

2230-
if (arch_get_random_int(&ret))
2231-
return ret;
2232-
22332221
warn_unseeded_randomness(&previous);
22342222

22352223
batch = raw_cpu_ptr(&batched_entropy_u32);

0 commit comments

Comments
 (0)