diff options
Diffstat (limited to 'include/linux/random.h')
| -rw-r--r-- | include/linux/random.h | 160 |
1 files changed, 113 insertions, 47 deletions
diff --git a/include/linux/random.h b/include/linux/random.h index 3b9377d6b7a5..8a8064dc3970 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -1,76 +1,142 @@ -/* - * include/linux/random.h - * - * Include file for the random number generator. - */ +/* SPDX-License-Identifier: GPL-2.0 */ + #ifndef _LINUX_RANDOM_H #define _LINUX_RANDOM_H -#include <uapi/linux/random.h> +#include <linux/bug.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <uapi/linux/random.h> -extern void add_device_randomness(const void *, unsigned int); -extern void add_input_randomness(unsigned int type, unsigned int code, - unsigned int value); -extern void add_interrupt_randomness(int irq, int irq_flags); +struct notifier_block; -extern void get_random_bytes(void *buf, int nbytes); -extern void get_random_bytes_arch(void *buf, int nbytes); -void generate_random_uuid(unsigned char uuid_out[16]); +void add_device_randomness(const void *buf, size_t len); +void __init add_bootloader_randomness(const void *buf, size_t len); +void add_input_randomness(unsigned int type, unsigned int code, + unsigned int value) __latent_entropy; +void add_interrupt_randomness(int irq) __latent_entropy; +void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy, bool sleep_after); -#ifndef MODULE -extern const struct file_operations random_fops, urandom_fops; +static inline void add_latent_entropy(void) +{ +#if defined(LATENT_ENTROPY_PLUGIN) && !defined(__CHECKER__) + add_device_randomness((const void *)&latent_entropy, sizeof(latent_entropy)); +#else + add_device_randomness(NULL, 0); #endif +} -unsigned int get_random_int(void); -unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len); +#if IS_ENABLED(CONFIG_VMGENID) +void add_vmfork_randomness(const void *unique_vm_id, size_t len); +int register_random_vmfork_notifier(struct notifier_block *nb); +int unregister_random_vmfork_notifier(struct notifier_block *nb); +#else +static inline int register_random_vmfork_notifier(struct notifier_block *nb) { return 0; } +static inline int unregister_random_vmfork_notifier(struct notifier_block *nb) { return 0; } +#endif -u32 prandom_u32(void); -void prandom_bytes(void *buf, int nbytes); -void prandom_seed(u32 seed); +void get_random_bytes(void *buf, size_t len); +u8 get_random_u8(void); +u16 get_random_u16(void); +u32 get_random_u32(void); +u64 get_random_u64(void); +static inline unsigned long get_random_long(void) +{ +#if BITS_PER_LONG == 64 + return get_random_u64(); +#else + return get_random_u32(); +#endif +} -u32 prandom_u32_state(struct rnd_state *); -void prandom_bytes_state(struct rnd_state *state, void *buf, int nbytes); +u32 __get_random_u32_below(u32 ceil); /* - * Handle minimum values for seeds + * Returns a random integer in the interval [0, ceil), with uniform + * distribution, suitable for all uses. Fastest when ceil is a constant, but + * still fast for variable ceil as well. */ -static inline u32 __seed(u32 x, u32 m) +static inline u32 get_random_u32_below(u32 ceil) { - return (x < m) ? x + m : x; + if (!__builtin_constant_p(ceil)) + return __get_random_u32_below(ceil); + + /* + * For the fast path, below, all operations on ceil are precomputed by + * the compiler, so this incurs no overhead for checking pow2, doing + * divisions, or branching based on integer size. The resultant + * algorithm does traditional reciprocal multiplication (typically + * optimized by the compiler into shifts and adds), rejecting samples + * whose lower half would indicate a range indivisible by ceil. + */ + BUILD_BUG_ON_MSG(!ceil, "get_random_u32_below() must take ceil > 0"); + if (ceil <= 1) + return 0; + for (;;) { + if (ceil <= 1U << 8) { + u32 mult = ceil * get_random_u8(); + if (likely(is_power_of_2(ceil) || (u8)mult >= (1U << 8) % ceil)) + return mult >> 8; + } else if (ceil <= 1U << 16) { + u32 mult = ceil * get_random_u16(); + if (likely(is_power_of_2(ceil) || (u16)mult >= (1U << 16) % ceil)) + return mult >> 16; + } else { + u64 mult = (u64)ceil * get_random_u32(); + if (likely(is_power_of_2(ceil) || (u32)mult >= -ceil % ceil)) + return mult >> 32; + } + } } -/** - * prandom_seed_state - set seed for prandom_u32_state(). - * @state: pointer to state structure to receive the seed. - * @seed: arbitrary 64-bit value to use as a seed. +/* + * Returns a random integer in the interval (floor, U32_MAX], with uniform + * distribution, suitable for all uses. Fastest when floor is a constant, but + * still fast for variable floor as well. */ -static inline void prandom_seed_state(struct rnd_state *state, u64 seed) +static inline u32 get_random_u32_above(u32 floor) { - u32 i = (seed >> 32) ^ (seed << 10) ^ seed; - - state->s1 = __seed(i, 1); - state->s2 = __seed(i, 7); - state->s3 = __seed(i, 15); + BUILD_BUG_ON_MSG(__builtin_constant_p(floor) && floor == U32_MAX, + "get_random_u32_above() must take floor < U32_MAX"); + return floor + 1 + get_random_u32_below(U32_MAX - floor); } -#ifdef CONFIG_ARCH_RANDOM -# include <asm/archrandom.h> -#else -static inline int arch_get_random_long(unsigned long *v) +/* + * Returns a random integer in the interval [floor, ceil], with uniform + * distribution, suitable for all uses. Fastest when floor and ceil are + * constant, but still fast for variable floor and ceil as well. + */ +static inline u32 get_random_u32_inclusive(u32 floor, u32 ceil) { - return 0; + BUILD_BUG_ON_MSG(__builtin_constant_p(floor) && __builtin_constant_p(ceil) && + (floor > ceil || ceil - floor == U32_MAX), + "get_random_u32_inclusive() must take floor <= ceil"); + return floor + get_random_u32_below(ceil - floor + 1); } -static inline int arch_get_random_int(unsigned int *v) + +void __init random_init_early(const char *command_line); +void __init random_init(void); +bool rng_is_initialized(void); +int wait_for_random_bytes(void); +int execute_with_initialized_rng(struct notifier_block *nb); + +/* Calls wait_for_random_bytes() and then calls get_random_bytes(buf, nbytes). + * Returns the result of the call to wait_for_random_bytes. */ +static inline int get_random_bytes_wait(void *buf, size_t nbytes) { - return 0; + int ret = wait_for_random_bytes(); + get_random_bytes(buf, nbytes); + return ret; } + +#ifdef CONFIG_SMP +int random_prepare_cpu(unsigned int cpu); +int random_online_cpu(unsigned int cpu); #endif -/* Pseudo random number generator from numerical recipes. */ -static inline u32 next_pseudo_random32(u32 seed) -{ - return seed * 1664525 + 1013904223; -} +#ifndef MODULE +extern const struct file_operations random_fops, urandom_fops; +#endif #endif /* _LINUX_RANDOM_H */ |
