random: group entropy collection functions
commit 92c653cf14400946f376a29b828d6af7e01f38dd upstream. This pulls all of the entropy collection-focused functions into the fourth labeled section. No functional changes. Cc: Theodore Ts'o <tytso@mit.edu> Reviewed-by: Dominik Brodowski <linux@dominikbrodowski.net> Reviewed-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
e9ff357860
commit
f04580811d
@@ -1039,51 +1039,105 @@ static bool drain_entropy(void *buf, size_t nbytes)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fast_pool {
|
|
||||||
union {
|
/**********************************************************************
|
||||||
u32 pool32[4];
|
*
|
||||||
u64 pool64[2];
|
* Entropy collection routines.
|
||||||
};
|
*
|
||||||
unsigned long last;
|
* The following exported functions are used for pushing entropy into
|
||||||
u16 reg_idx;
|
* the above entropy accumulation routines:
|
||||||
u8 count;
|
*
|
||||||
};
|
* void add_device_randomness(const void *buf, size_t size);
|
||||||
|
* void add_input_randomness(unsigned int type, unsigned int code,
|
||||||
|
* unsigned int value);
|
||||||
|
* void add_disk_randomness(struct gendisk *disk);
|
||||||
|
* void add_hwgenerator_randomness(const void *buffer, size_t count,
|
||||||
|
* size_t entropy);
|
||||||
|
* void add_bootloader_randomness(const void *buf, size_t size);
|
||||||
|
* void add_interrupt_randomness(int irq);
|
||||||
|
*
|
||||||
|
* add_device_randomness() adds data to the input pool that
|
||||||
|
* is likely to differ between two devices (or possibly even per boot).
|
||||||
|
* This would be things like MAC addresses or serial numbers, or the
|
||||||
|
* read-out of the RTC. This does *not* credit any actual entropy to
|
||||||
|
* the pool, but it initializes the pool to different values for devices
|
||||||
|
* that might otherwise be identical and have very little entropy
|
||||||
|
* available to them (particularly common in the embedded world).
|
||||||
|
*
|
||||||
|
* add_input_randomness() uses the input layer interrupt timing, as well
|
||||||
|
* as the event type information from the hardware.
|
||||||
|
*
|
||||||
|
* add_disk_randomness() uses what amounts to the seek time of block
|
||||||
|
* layer request events, on a per-disk_devt basis, as input to the
|
||||||
|
* entropy pool. Note that high-speed solid state drives with very low
|
||||||
|
* seek times do not make for good sources of entropy, as their seek
|
||||||
|
* times are usually fairly consistent.
|
||||||
|
*
|
||||||
|
* The above two routines try to estimate how many bits of entropy
|
||||||
|
* to credit. They do this by keeping track of the first and second
|
||||||
|
* order deltas of the event timings.
|
||||||
|
*
|
||||||
|
* add_hwgenerator_randomness() is for true hardware RNGs, and will credit
|
||||||
|
* entropy as specified by the caller. If the entropy pool is full it will
|
||||||
|
* block until more entropy is needed.
|
||||||
|
*
|
||||||
|
* add_bootloader_randomness() is the same as add_hwgenerator_randomness() or
|
||||||
|
* add_device_randomness(), depending on whether or not the configuration
|
||||||
|
* option CONFIG_RANDOM_TRUST_BOOTLOADER is set.
|
||||||
|
*
|
||||||
|
* add_interrupt_randomness() uses the interrupt timing as random
|
||||||
|
* inputs to the entropy pool. Using the cycle counters and the irq source
|
||||||
|
* as inputs, it feeds the input pool roughly once a second or after 64
|
||||||
|
* interrupts, crediting 1 bit of entropy for whichever comes first.
|
||||||
|
*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
static bool trust_cpu __ro_after_init = IS_ENABLED(CONFIG_RANDOM_TRUST_CPU);
|
||||||
|
static int __init parse_trust_cpu(char *arg)
|
||||||
|
{
|
||||||
|
return kstrtobool(arg, &trust_cpu);
|
||||||
|
}
|
||||||
|
early_param("random.trust_cpu", parse_trust_cpu);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a fast mixing routine used by the interrupt randomness
|
* The first collection of entropy occurs at system boot while interrupts
|
||||||
* collector. It's hardcoded for an 128 bit pool and assumes that any
|
* are still turned off. Here we push in RDSEED, a timestamp, and utsname().
|
||||||
* locks that might be needed are taken by the caller.
|
* Depending on the above configuration knob, RDSEED may be considered
|
||||||
|
* sufficient for initialization. Note that much earlier setup may already
|
||||||
|
* have pushed entropy into the input pool by the time we get here.
|
||||||
*/
|
*/
|
||||||
static void fast_mix(u32 pool[4])
|
int __init rand_initialize(void)
|
||||||
{
|
{
|
||||||
u32 a = pool[0], b = pool[1];
|
size_t i;
|
||||||
u32 c = pool[2], d = pool[3];
|
ktime_t now = ktime_get_real();
|
||||||
|
bool arch_init = true;
|
||||||
|
unsigned long rv;
|
||||||
|
|
||||||
a += b; c += d;
|
for (i = 0; i < BLAKE2S_BLOCK_SIZE; i += sizeof(rv)) {
|
||||||
b = rol32(b, 6); d = rol32(d, 27);
|
if (!arch_get_random_seed_long_early(&rv) &&
|
||||||
d ^= a; b ^= c;
|
!arch_get_random_long_early(&rv)) {
|
||||||
|
rv = random_get_entropy();
|
||||||
|
arch_init = false;
|
||||||
|
}
|
||||||
|
mix_pool_bytes(&rv, sizeof(rv));
|
||||||
|
}
|
||||||
|
mix_pool_bytes(&now, sizeof(now));
|
||||||
|
mix_pool_bytes(utsname(), sizeof(*(utsname())));
|
||||||
|
|
||||||
a += b; c += d;
|
extract_entropy(base_crng.key, sizeof(base_crng.key));
|
||||||
b = rol32(b, 16); d = rol32(d, 14);
|
++base_crng.generation;
|
||||||
d ^= a; b ^= c;
|
|
||||||
|
|
||||||
a += b; c += d;
|
if (arch_init && trust_cpu && crng_init < 2) {
|
||||||
b = rol32(b, 6); d = rol32(d, 27);
|
crng_init = 2;
|
||||||
d ^= a; b ^= c;
|
pr_notice("crng init done (trusting CPU's manufacturer)\n");
|
||||||
|
|
||||||
a += b; c += d;
|
|
||||||
b = rol32(b, 16); d = rol32(d, 14);
|
|
||||||
d ^= a; b ^= c;
|
|
||||||
|
|
||||||
pool[0] = a; pool[1] = b;
|
|
||||||
pool[2] = c; pool[3] = d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
if (ratelimit_disable) {
|
||||||
*
|
urandom_warning.interval = 0;
|
||||||
* Entropy input management
|
unseeded_warning.interval = 0;
|
||||||
*
|
}
|
||||||
*********************************************************************/
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* There is one of these per entropy source */
|
/* There is one of these per entropy source */
|
||||||
struct timer_rand_state {
|
struct timer_rand_state {
|
||||||
@@ -1091,8 +1145,6 @@ struct timer_rand_state {
|
|||||||
long last_delta, last_delta2;
|
long last_delta, last_delta2;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define INIT_TIMER_RAND_STATE { INITIAL_JIFFIES, };
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add device- or boot-specific data to the input pool to help
|
* Add device- or boot-specific data to the input pool to help
|
||||||
* initialize it.
|
* initialize it.
|
||||||
@@ -1116,8 +1168,6 @@ void add_device_randomness(const void *buf, size_t size)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(add_device_randomness);
|
EXPORT_SYMBOL(add_device_randomness);
|
||||||
|
|
||||||
static struct timer_rand_state input_timer_state = INIT_TIMER_RAND_STATE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function adds entropy to the entropy "pool" by using timing
|
* This function adds entropy to the entropy "pool" by using timing
|
||||||
* delays. It uses the timer_rand_state structure to make an estimate
|
* delays. It uses the timer_rand_state structure to make an estimate
|
||||||
@@ -1179,8 +1229,9 @@ void add_input_randomness(unsigned int type, unsigned int code,
|
|||||||
unsigned int value)
|
unsigned int value)
|
||||||
{
|
{
|
||||||
static unsigned char last_value;
|
static unsigned char last_value;
|
||||||
|
static struct timer_rand_state input_timer_state = { INITIAL_JIFFIES };
|
||||||
|
|
||||||
/* ignore autorepeat and the like */
|
/* Ignore autorepeat and the like. */
|
||||||
if (value == last_value)
|
if (value == last_value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1190,6 +1241,119 @@ void add_input_randomness(unsigned int type, unsigned int code,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(add_input_randomness);
|
EXPORT_SYMBOL_GPL(add_input_randomness);
|
||||||
|
|
||||||
|
#ifdef CONFIG_BLOCK
|
||||||
|
void add_disk_randomness(struct gendisk *disk)
|
||||||
|
{
|
||||||
|
if (!disk || !disk->random)
|
||||||
|
return;
|
||||||
|
/* First major is 1, so we get >= 0x200 here. */
|
||||||
|
add_timer_randomness(disk->random, 0x100 + disk_devt(disk));
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(add_disk_randomness);
|
||||||
|
|
||||||
|
void rand_initialize_disk(struct gendisk *disk)
|
||||||
|
{
|
||||||
|
struct timer_rand_state *state;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If kzalloc returns null, we just won't use that entropy
|
||||||
|
* source.
|
||||||
|
*/
|
||||||
|
state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL);
|
||||||
|
if (state) {
|
||||||
|
state->last_time = INITIAL_JIFFIES;
|
||||||
|
disk->random = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interface for in-kernel drivers of true hardware RNGs.
|
||||||
|
* Those devices may produce endless random bits and will be throttled
|
||||||
|
* when our pool is full.
|
||||||
|
*/
|
||||||
|
void add_hwgenerator_randomness(const void *buffer, size_t count,
|
||||||
|
size_t entropy)
|
||||||
|
{
|
||||||
|
if (unlikely(crng_init == 0)) {
|
||||||
|
size_t ret = crng_fast_load(buffer, count);
|
||||||
|
mix_pool_bytes(buffer, ret);
|
||||||
|
count -= ret;
|
||||||
|
buffer += ret;
|
||||||
|
if (!count || crng_init == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Throttle writing if we're above the trickle threshold.
|
||||||
|
* We'll be woken up again once below POOL_MIN_BITS, when
|
||||||
|
* the calling thread is about to terminate, or once
|
||||||
|
* CRNG_RESEED_INTERVAL has elapsed.
|
||||||
|
*/
|
||||||
|
wait_event_interruptible_timeout(random_write_wait,
|
||||||
|
!system_wq || kthread_should_stop() ||
|
||||||
|
input_pool.entropy_count < POOL_MIN_BITS,
|
||||||
|
CRNG_RESEED_INTERVAL);
|
||||||
|
mix_pool_bytes(buffer, count);
|
||||||
|
credit_entropy_bits(entropy);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle random seed passed by bootloader.
|
||||||
|
* If the seed is trustworthy, it would be regarded as hardware RNGs. Otherwise
|
||||||
|
* it would be regarded as device data.
|
||||||
|
* The decision is controlled by CONFIG_RANDOM_TRUST_BOOTLOADER.
|
||||||
|
*/
|
||||||
|
void add_bootloader_randomness(const void *buf, size_t size)
|
||||||
|
{
|
||||||
|
if (IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER))
|
||||||
|
add_hwgenerator_randomness(buf, size, size * 8);
|
||||||
|
else
|
||||||
|
add_device_randomness(buf, size);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(add_bootloader_randomness);
|
||||||
|
|
||||||
|
struct fast_pool {
|
||||||
|
union {
|
||||||
|
u32 pool32[4];
|
||||||
|
u64 pool64[2];
|
||||||
|
};
|
||||||
|
unsigned long last;
|
||||||
|
u16 reg_idx;
|
||||||
|
u8 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a fast mixing routine used by the interrupt randomness
|
||||||
|
* collector. It's hardcoded for an 128 bit pool and assumes that any
|
||||||
|
* locks that might be needed are taken by the caller.
|
||||||
|
*/
|
||||||
|
static void fast_mix(u32 pool[4])
|
||||||
|
{
|
||||||
|
u32 a = pool[0], b = pool[1];
|
||||||
|
u32 c = pool[2], d = pool[3];
|
||||||
|
|
||||||
|
a += b; c += d;
|
||||||
|
b = rol32(b, 6); d = rol32(d, 27);
|
||||||
|
d ^= a; b ^= c;
|
||||||
|
|
||||||
|
a += b; c += d;
|
||||||
|
b = rol32(b, 16); d = rol32(d, 14);
|
||||||
|
d ^= a; b ^= c;
|
||||||
|
|
||||||
|
a += b; c += d;
|
||||||
|
b = rol32(b, 6); d = rol32(d, 27);
|
||||||
|
d ^= a; b ^= c;
|
||||||
|
|
||||||
|
a += b; c += d;
|
||||||
|
b = rol32(b, 16); d = rol32(d, 14);
|
||||||
|
d ^= a; b ^= c;
|
||||||
|
|
||||||
|
pool[0] = a; pool[1] = b;
|
||||||
|
pool[2] = c; pool[3] = d;
|
||||||
|
}
|
||||||
|
|
||||||
static DEFINE_PER_CPU(struct fast_pool, irq_randomness);
|
static DEFINE_PER_CPU(struct fast_pool, irq_randomness);
|
||||||
|
|
||||||
static u32 get_reg(struct fast_pool *f, struct pt_regs *regs)
|
static u32 get_reg(struct fast_pool *f, struct pt_regs *regs)
|
||||||
@@ -1259,22 +1423,11 @@ void add_interrupt_randomness(int irq)
|
|||||||
|
|
||||||
fast_pool->count = 0;
|
fast_pool->count = 0;
|
||||||
|
|
||||||
/* award one bit for the contents of the fast pool */
|
/* Award one bit for the contents of the fast pool. */
|
||||||
credit_entropy_bits(1);
|
credit_entropy_bits(1);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(add_interrupt_randomness);
|
EXPORT_SYMBOL_GPL(add_interrupt_randomness);
|
||||||
|
|
||||||
#ifdef CONFIG_BLOCK
|
|
||||||
void add_disk_randomness(struct gendisk *disk)
|
|
||||||
{
|
|
||||||
if (!disk || !disk->random)
|
|
||||||
return;
|
|
||||||
/* first major is 1, so we get >= 0x200 here */
|
|
||||||
add_timer_randomness(disk->random, 0x100 + disk_devt(disk));
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(add_disk_randomness);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Each time the timer fires, we expect that we got an unpredictable
|
* Each time the timer fires, we expect that we got an unpredictable
|
||||||
* jump in the cycle counter. Even if the timer is running on another
|
* jump in the cycle counter. Even if the timer is running on another
|
||||||
@@ -1324,73 +1477,6 @@ static void try_to_generate_entropy(void)
|
|||||||
mix_pool_bytes(&stack.now, sizeof(stack.now));
|
mix_pool_bytes(&stack.now, sizeof(stack.now));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool trust_cpu __ro_after_init = IS_ENABLED(CONFIG_RANDOM_TRUST_CPU);
|
|
||||||
static int __init parse_trust_cpu(char *arg)
|
|
||||||
{
|
|
||||||
return kstrtobool(arg, &trust_cpu);
|
|
||||||
}
|
|
||||||
early_param("random.trust_cpu", parse_trust_cpu);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note that setup_arch() may call add_device_randomness()
|
|
||||||
* long before we get here. This allows seeding of the pools
|
|
||||||
* with some platform dependent data very early in the boot
|
|
||||||
* process. But it limits our options here. We must use
|
|
||||||
* statically allocated structures that already have all
|
|
||||||
* initializations complete at compile time. We should also
|
|
||||||
* take care not to overwrite the precious per platform data
|
|
||||||
* we were given.
|
|
||||||
*/
|
|
||||||
int __init rand_initialize(void)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
ktime_t now = ktime_get_real();
|
|
||||||
bool arch_init = true;
|
|
||||||
unsigned long rv;
|
|
||||||
|
|
||||||
for (i = 0; i < BLAKE2S_BLOCK_SIZE; i += sizeof(rv)) {
|
|
||||||
if (!arch_get_random_seed_long_early(&rv) &&
|
|
||||||
!arch_get_random_long_early(&rv)) {
|
|
||||||
rv = random_get_entropy();
|
|
||||||
arch_init = false;
|
|
||||||
}
|
|
||||||
mix_pool_bytes(&rv, sizeof(rv));
|
|
||||||
}
|
|
||||||
mix_pool_bytes(&now, sizeof(now));
|
|
||||||
mix_pool_bytes(utsname(), sizeof(*(utsname())));
|
|
||||||
|
|
||||||
extract_entropy(base_crng.key, sizeof(base_crng.key));
|
|
||||||
++base_crng.generation;
|
|
||||||
|
|
||||||
if (arch_init && trust_cpu && crng_init < 2) {
|
|
||||||
crng_init = 2;
|
|
||||||
pr_notice("crng init done (trusting CPU's manufacturer)\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ratelimit_disable) {
|
|
||||||
urandom_warning.interval = 0;
|
|
||||||
unseeded_warning.interval = 0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_BLOCK
|
|
||||||
void rand_initialize_disk(struct gendisk *disk)
|
|
||||||
{
|
|
||||||
struct timer_rand_state *state;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If kzalloc returns null, we just won't use that entropy
|
|
||||||
* source.
|
|
||||||
*/
|
|
||||||
state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL);
|
|
||||||
if (state) {
|
|
||||||
state->last_time = INITIAL_JIFFIES;
|
|
||||||
disk->random = state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static ssize_t urandom_read(struct file *file, char __user *buf, size_t nbytes,
|
static ssize_t urandom_read(struct file *file, char __user *buf, size_t nbytes,
|
||||||
loff_t *ppos)
|
loff_t *ppos)
|
||||||
{
|
{
|
||||||
@@ -1675,47 +1761,3 @@ struct ctl_table random_table[] = {
|
|||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_SYSCTL */
|
#endif /* CONFIG_SYSCTL */
|
||||||
|
|
||||||
/* Interface for in-kernel drivers of true hardware RNGs.
|
|
||||||
* Those devices may produce endless random bits and will be throttled
|
|
||||||
* when our pool is full.
|
|
||||||
*/
|
|
||||||
void add_hwgenerator_randomness(const void *buffer, size_t count,
|
|
||||||
size_t entropy)
|
|
||||||
{
|
|
||||||
if (unlikely(crng_init == 0)) {
|
|
||||||
size_t ret = crng_fast_load(buffer, count);
|
|
||||||
mix_pool_bytes(buffer, ret);
|
|
||||||
count -= ret;
|
|
||||||
buffer += ret;
|
|
||||||
if (!count || crng_init == 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Throttle writing if we're above the trickle threshold.
|
|
||||||
* We'll be woken up again once below POOL_MIN_BITS, when
|
|
||||||
* the calling thread is about to terminate, or once
|
|
||||||
* CRNG_RESEED_INTERVAL has elapsed.
|
|
||||||
*/
|
|
||||||
wait_event_interruptible_timeout(random_write_wait,
|
|
||||||
!system_wq || kthread_should_stop() ||
|
|
||||||
input_pool.entropy_count < POOL_MIN_BITS,
|
|
||||||
CRNG_RESEED_INTERVAL);
|
|
||||||
mix_pool_bytes(buffer, count);
|
|
||||||
credit_entropy_bits(entropy);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);
|
|
||||||
|
|
||||||
/* Handle random seed passed by bootloader.
|
|
||||||
* If the seed is trustworthy, it would be regarded as hardware RNGs. Otherwise
|
|
||||||
* it would be regarded as device data.
|
|
||||||
* The decision is controlled by CONFIG_RANDOM_TRUST_BOOTLOADER.
|
|
||||||
*/
|
|
||||||
void add_bootloader_randomness(const void *buf, size_t size)
|
|
||||||
{
|
|
||||||
if (IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER))
|
|
||||||
add_hwgenerator_randomness(buf, size, size * 8);
|
|
||||||
else
|
|
||||||
add_device_randomness(buf, size);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(add_bootloader_randomness);
|
|
||||||
|
Reference in New Issue
Block a user