This function gets random data from the best available source The current code has a sequence in several places that calls one or more of arch_get_random_long() or related functions, checks the return value(s) and on failure falls back to random_get_entropy(). get_source long() is intended to replace all such sequences. This is better in several ways. In the fallback case it gives much more random output than random_get_entropy(). It never wastes effort by calling arch_get_random_long() et al. when the relevant config variables are not set. When it does use arch_get_random_long(), it does not deliver raw output from that function but masks it by mixing with stored random data. Signed-off-by: Sandy Harris <sandyinchina@xxxxxxxxx> --- drivers/char/random.c | 74 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/drivers/char/random.c b/drivers/char/random.c index 9edf65ad4259..6c77fd056f66 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1031,6 +1031,80 @@ static void xtea_rekey(void) xtea_iterations = 0 ; } +/************************************************************************** + * Load a 64-bit word with data from whatever source we have + * + * arch_get_random_long() + * hardware RNG + * emulated HWRNG in a VM + * + * When there are two sources, alternate. + * If you have no better source, or if one fails, + * fall back to get_xtea_long() + * + * This function always succeeds, which allows some + * simplifications elsewhere in the code. + * + * This is intended only for use inside the kernel. + * Any data sent to user space should come from the + * chacha-based crng construction. + ***************************************************************************/ + +static int load_count = 0; +#define COUNT_RESTART 128 + +/* + * Add a mask variable so we can avoid using data + * from any source directly as output. + */ +static unsigned long source_mask ; + +/* + * Use xtea sometimes even if we have a good source + * Avoids trusting the source completely + */ +#define MIX_MASK 15 + +static void get_source_long(unsigned long *x) +{ + int a, b ; + int ret = 0 ; + + if (load_count >= COUNT_RESTART) + load_count = 0 ; + if (load_count == 0) + get_xtea_long(&source_mask) ; + + a = IS_ENABLED(CONFIG_ARCH_RANDOM) ; + b = IS_ENABLED(CONFIG_HW_RANDOM) ; + + if (a && b) { + if (load_count & 1) + ret = arch_get_random_long(x) ; + else ret = get_hw_long(x) ; + } + if (a && !b) { + if (load_count&MIX_MASK) + ret = arch_get_random_long(x) ; + } + if (!a && b) { + if (load_count&MIX_MASK) + ret = get_hw_long(x) ; + } + /* + * no source configured + * or configured one failed + * + * or it is just time for tea, + * (load_count&MIX_MASK) == 0 + */ + if (!ret) + get_xtea_long(x) ; + + *x += source_mask ; + load_count++ ; +} + /********************************************************************* * * CRNG using CHACHA20 -- 2.25.1