From: "Jason A. Donenfeld" <Jason@xxxxxxxxx> commit c440408cf6901eeb2c09563397e24a9097907078 upstream. Many times, when a user wants a random number, he wants a random number of a guaranteed size. So, thinking of get_random_int and get_random_long in terms of get_random_u32 and get_random_u64 makes it much easier to achieve this. It also makes the code simpler. On 32-bit platforms, get_random_int and get_random_long are both aliased to get_random_u32. On 64-bit platforms, int->u32 and long->u64. Signed-off-by: Jason A. Donenfeld <Jason@xxxxxxxxx> Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> Cc: Theodore Ts'o <tytso@xxxxxxx> Signed-off-by: Theodore Ts'o <tytso@xxxxxxx> Signed-off-by: Jason A. Donenfeld <Jason@xxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/char/random.c | 63 ++++++++++++++++++++++++++----------------------- include/linux/random.h | 17 +++++++++++-- 2 files changed, 49 insertions(+), 31 deletions(-) --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -2089,57 +2089,62 @@ struct ctl_table random_table[] = { struct batched_entropy { union { - unsigned long entropy_long[CHACHA20_BLOCK_SIZE / sizeof(unsigned long)]; - unsigned int entropy_int[CHACHA20_BLOCK_SIZE / sizeof(unsigned int)]; + u64 entropy_u64[CHACHA20_BLOCK_SIZE / sizeof(u64)]; + u32 entropy_u32[CHACHA20_BLOCK_SIZE / sizeof(u32)]; }; unsigned int position; }; /* * Get a random word for internal kernel use only. The quality of the random - * number is good as /dev/urandom, but there is no backtrack protection, with - * the goal of being quite fast and not depleting entropy. + * number is either as good as RDRAND or as good as /dev/urandom, with the + * goal of being quite fast and not depleting entropy. */ -static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_long); -unsigned long get_random_long(void) +static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64); +u64 get_random_u64(void) { - unsigned long ret; + u64 ret; struct batched_entropy *batch; - batch = &get_cpu_var(batched_entropy_long); - if (batch->position % ARRAY_SIZE(batch->entropy_long) == 0) { - extract_crng((u8 *)batch->entropy_long); +#if BITS_PER_LONG == 64 + if (arch_get_random_long((unsigned long *)&ret)) + return ret; +#else + if (arch_get_random_long((unsigned long *)&ret) && + arch_get_random_long((unsigned long *)&ret + 1)) + return ret; +#endif + + batch = &get_cpu_var(batched_entropy_u64); + if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) { + extract_crng((u8 *)batch->entropy_u64); batch->position = 0; } - ret = batch->entropy_long[batch->position++]; - put_cpu_var(batched_entropy_long); + ret = batch->entropy_u64[batch->position++]; + put_cpu_var(batched_entropy_u64); return ret; } -EXPORT_SYMBOL(get_random_long); +EXPORT_SYMBOL(get_random_u64); -#if BITS_PER_LONG == 32 -unsigned int get_random_int(void) -{ - return get_random_long(); -} -#else -static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_int); -unsigned int get_random_int(void) +static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32); +u32 get_random_u32(void) { - unsigned int ret; + u32 ret; struct batched_entropy *batch; - batch = &get_cpu_var(batched_entropy_int); - if (batch->position % ARRAY_SIZE(batch->entropy_int) == 0) { - extract_crng((u8 *)batch->entropy_int); + if (arch_get_random_int(&ret)) + return ret; + + batch = &get_cpu_var(batched_entropy_u32); + if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) { + extract_crng((u8 *)batch->entropy_u32); batch->position = 0; } - ret = batch->entropy_int[batch->position++]; - put_cpu_var(batched_entropy_int); + ret = batch->entropy_u32[batch->position++]; + put_cpu_var(batched_entropy_u32); return ret; } -#endif -EXPORT_SYMBOL(get_random_int); +EXPORT_SYMBOL(get_random_u32); /** * randomize_page - Generate a random, page aligned address --- a/include/linux/random.h +++ b/include/linux/random.h @@ -42,8 +42,21 @@ extern void get_random_bytes_arch(void * extern const struct file_operations random_fops, urandom_fops; #endif -unsigned int get_random_int(void); -unsigned long get_random_long(void); +u32 get_random_u32(void); +u64 get_random_u64(void); +static inline unsigned int get_random_int(void) +{ + return get_random_u32(); +} +static inline unsigned long get_random_long(void) +{ +#if BITS_PER_LONG == 64 + return get_random_u64(); +#else + return get_random_u32(); +#endif +} + unsigned long randomize_page(unsigned long start, unsigned long range); /*