random: use symbolic constants for crng_init states
crng_init represents a state machine, with three states, and various rules for transitions. For the longest time, we've been managing these with "0", "1", and "2", and expecting people to figure it out. To make the code more obvious, replace these with proper enum values representing the transition, and then redocument what each of these states mean. Reviewed-by: Dominik Brodowski <linux@dominikbrodowski.net> Cc: Joe Perches <joe@perches.com> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Родитель
d4150779e6
Коммит
e3d2c5e79a
|
@ -71,16 +71,16 @@
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* crng_init = 0 --> Uninitialized
|
|
||||||
* 1 --> Initialized
|
|
||||||
* 2 --> Initialized from input_pool
|
|
||||||
*
|
|
||||||
* crng_init is protected by base_crng->lock, and only increases
|
* crng_init is protected by base_crng->lock, and only increases
|
||||||
* its value (from 0->1->2).
|
* its value (from empty->early->ready).
|
||||||
*/
|
*/
|
||||||
static int crng_init = 0;
|
static enum {
|
||||||
#define crng_ready() (likely(crng_init > 1))
|
CRNG_EMPTY = 0, /* Little to no entropy collected */
|
||||||
/* Various types of waiters for crng_init->2 transition. */
|
CRNG_EARLY = 1, /* At least POOL_EARLY_BITS collected */
|
||||||
|
CRNG_READY = 2 /* Fully initialized with POOL_READY_BITS collected */
|
||||||
|
} crng_init = CRNG_EMPTY;
|
||||||
|
#define crng_ready() (likely(crng_init >= CRNG_READY))
|
||||||
|
/* Various types of waiters for crng_init->CRNG_READY transition. */
|
||||||
static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
|
static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
|
||||||
static struct fasync_struct *fasync;
|
static struct fasync_struct *fasync;
|
||||||
static DEFINE_SPINLOCK(random_ready_chain_lock);
|
static DEFINE_SPINLOCK(random_ready_chain_lock);
|
||||||
|
@ -283,7 +283,7 @@ static void crng_reseed(void)
|
||||||
WRITE_ONCE(base_crng.generation, next_gen);
|
WRITE_ONCE(base_crng.generation, next_gen);
|
||||||
WRITE_ONCE(base_crng.birth, jiffies);
|
WRITE_ONCE(base_crng.birth, jiffies);
|
||||||
if (!crng_ready()) {
|
if (!crng_ready()) {
|
||||||
crng_init = 2;
|
crng_init = CRNG_READY;
|
||||||
finalize_init = true;
|
finalize_init = true;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&base_crng.lock, flags);
|
spin_unlock_irqrestore(&base_crng.lock, flags);
|
||||||
|
@ -377,7 +377,7 @@ static void crng_make_state(u32 chacha_state[CHACHA_STATE_WORDS],
|
||||||
* For the fast path, we check whether we're ready, unlocked first, and
|
* For the fast path, we check whether we're ready, unlocked first, and
|
||||||
* then re-check once locked later. In the case where we're really not
|
* then re-check once locked later. In the case where we're really not
|
||||||
* ready, we do fast key erasure with the base_crng directly, extracting
|
* ready, we do fast key erasure with the base_crng directly, extracting
|
||||||
* when crng_init==0.
|
* when crng_init is CRNG_EMPTY.
|
||||||
*/
|
*/
|
||||||
if (!crng_ready()) {
|
if (!crng_ready()) {
|
||||||
bool ready;
|
bool ready;
|
||||||
|
@ -385,7 +385,7 @@ static void crng_make_state(u32 chacha_state[CHACHA_STATE_WORDS],
|
||||||
spin_lock_irqsave(&base_crng.lock, flags);
|
spin_lock_irqsave(&base_crng.lock, flags);
|
||||||
ready = crng_ready();
|
ready = crng_ready();
|
||||||
if (!ready) {
|
if (!ready) {
|
||||||
if (crng_init == 0)
|
if (crng_init == CRNG_EMPTY)
|
||||||
extract_entropy(base_crng.key, sizeof(base_crng.key));
|
extract_entropy(base_crng.key, sizeof(base_crng.key));
|
||||||
crng_fast_key_erasure(base_crng.key, chacha_state,
|
crng_fast_key_erasure(base_crng.key, chacha_state,
|
||||||
random_data, random_data_len);
|
random_data, random_data_len);
|
||||||
|
@ -739,8 +739,8 @@ EXPORT_SYMBOL(get_random_bytes_arch);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
POOL_BITS = BLAKE2S_HASH_SIZE * 8,
|
POOL_BITS = BLAKE2S_HASH_SIZE * 8,
|
||||||
POOL_INIT_BITS = POOL_BITS, /* No point in settling for less. */
|
POOL_READY_BITS = POOL_BITS, /* When crng_init->CRNG_READY */
|
||||||
POOL_FAST_INIT_BITS = POOL_INIT_BITS / 2
|
POOL_EARLY_BITS = POOL_READY_BITS / 2 /* When crng_init->CRNG_EARLY */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
|
@ -835,13 +835,13 @@ static void credit_init_bits(size_t nbits)
|
||||||
init_bits = min_t(unsigned int, POOL_BITS, orig + add);
|
init_bits = min_t(unsigned int, POOL_BITS, orig + add);
|
||||||
} while (cmpxchg(&input_pool.init_bits, orig, init_bits) != orig);
|
} while (cmpxchg(&input_pool.init_bits, orig, init_bits) != orig);
|
||||||
|
|
||||||
if (!crng_ready() && init_bits >= POOL_INIT_BITS)
|
if (!crng_ready() && init_bits >= POOL_READY_BITS)
|
||||||
crng_reseed();
|
crng_reseed();
|
||||||
else if (unlikely(crng_init == 0 && init_bits >= POOL_FAST_INIT_BITS)) {
|
else if (unlikely(crng_init == CRNG_EMPTY && init_bits >= POOL_EARLY_BITS)) {
|
||||||
spin_lock_irqsave(&base_crng.lock, flags);
|
spin_lock_irqsave(&base_crng.lock, flags);
|
||||||
if (crng_init == 0) {
|
if (crng_init == CRNG_EMPTY) {
|
||||||
extract_entropy(base_crng.key, sizeof(base_crng.key));
|
extract_entropy(base_crng.key, sizeof(base_crng.key));
|
||||||
crng_init = 1;
|
crng_init = CRNG_EARLY;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&base_crng.lock, flags);
|
spin_unlock_irqrestore(&base_crng.lock, flags);
|
||||||
}
|
}
|
||||||
|
@ -1610,7 +1610,7 @@ const struct file_operations urandom_fops = {
|
||||||
*
|
*
|
||||||
* - write_wakeup_threshold - the amount of entropy in the input pool
|
* - write_wakeup_threshold - the amount of entropy in the input pool
|
||||||
* below which write polls to /dev/random will unblock, requesting
|
* below which write polls to /dev/random will unblock, requesting
|
||||||
* more entropy, tied to the POOL_INIT_BITS constant. It is writable
|
* more entropy, tied to the POOL_READY_BITS constant. It is writable
|
||||||
* to avoid breaking old userspaces, but writing to it does not
|
* to avoid breaking old userspaces, but writing to it does not
|
||||||
* change any behavior of the RNG.
|
* change any behavior of the RNG.
|
||||||
*
|
*
|
||||||
|
@ -1625,7 +1625,7 @@ const struct file_operations urandom_fops = {
|
||||||
#include <linux/sysctl.h>
|
#include <linux/sysctl.h>
|
||||||
|
|
||||||
static int sysctl_random_min_urandom_seed = CRNG_RESEED_INTERVAL / HZ;
|
static int sysctl_random_min_urandom_seed = CRNG_RESEED_INTERVAL / HZ;
|
||||||
static int sysctl_random_write_wakeup_bits = POOL_INIT_BITS;
|
static int sysctl_random_write_wakeup_bits = POOL_READY_BITS;
|
||||||
static int sysctl_poolsize = POOL_BITS;
|
static int sysctl_poolsize = POOL_BITS;
|
||||||
static u8 sysctl_bootid[UUID_SIZE];
|
static u8 sysctl_bootid[UUID_SIZE];
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче