random: group initialization wait functions
commit 5f1bb112006b104b3e2a1e1b39bbb9b2617581e6 upstream. This pulls all of the readiness waiting-focused functions into the first 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
6c9cee1555
commit
6b1ffb3b5a
@@ -201,6 +201,185 @@
|
|||||||
#include <asm/irq_regs.h>
|
#include <asm/irq_regs.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* Initialization and readiness waiting.
|
||||||
|
*
|
||||||
|
* Much of the RNG infrastructure is devoted to various dependencies
|
||||||
|
* being able to wait until the RNG has collected enough entropy and
|
||||||
|
* is ready for safe consumption.
|
||||||
|
*
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* crng_init = 0 --> Uninitialized
|
||||||
|
* 1 --> Initialized
|
||||||
|
* 2 --> Initialized from input_pool
|
||||||
|
*
|
||||||
|
* crng_init is protected by base_crng->lock, and only increases
|
||||||
|
* its value (from 0->1->2).
|
||||||
|
*/
|
||||||
|
static int crng_init = 0;
|
||||||
|
#define crng_ready() (likely(crng_init > 1))
|
||||||
|
/* Various types of waiters for crng_init->2 transition. */
|
||||||
|
static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
|
||||||
|
static struct fasync_struct *fasync;
|
||||||
|
static DEFINE_SPINLOCK(random_ready_list_lock);
|
||||||
|
static LIST_HEAD(random_ready_list);
|
||||||
|
|
||||||
|
/* Control how we warn userspace. */
|
||||||
|
static struct ratelimit_state unseeded_warning =
|
||||||
|
RATELIMIT_STATE_INIT("warn_unseeded_randomness", HZ, 3);
|
||||||
|
static struct ratelimit_state urandom_warning =
|
||||||
|
RATELIMIT_STATE_INIT("warn_urandom_randomness", HZ, 3);
|
||||||
|
static int ratelimit_disable __read_mostly;
|
||||||
|
module_param_named(ratelimit_disable, ratelimit_disable, int, 0644);
|
||||||
|
MODULE_PARM_DESC(ratelimit_disable, "Disable random ratelimit suppression");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns whether or not the input pool has been seeded and thus guaranteed
|
||||||
|
* to supply cryptographically secure random numbers. This applies to: the
|
||||||
|
* /dev/urandom device, the get_random_bytes function, and the get_random_{u32,
|
||||||
|
* ,u64,int,long} family of functions.
|
||||||
|
*
|
||||||
|
* Returns: true if the input pool has been seeded.
|
||||||
|
* false if the input pool has not been seeded.
|
||||||
|
*/
|
||||||
|
bool rng_is_initialized(void)
|
||||||
|
{
|
||||||
|
return crng_ready();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(rng_is_initialized);
|
||||||
|
|
||||||
|
/* Used by wait_for_random_bytes(), and considered an entropy collector, below. */
|
||||||
|
static void try_to_generate_entropy(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for the input pool to be seeded and thus guaranteed to supply
|
||||||
|
* cryptographically secure random numbers. This applies to: the /dev/urandom
|
||||||
|
* device, the get_random_bytes function, and the get_random_{u32,u64,int,long}
|
||||||
|
* family of functions. Using any of these functions without first calling
|
||||||
|
* this function forfeits the guarantee of security.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the input pool has been seeded.
|
||||||
|
* -ERESTARTSYS if the function was interrupted by a signal.
|
||||||
|
*/
|
||||||
|
int wait_for_random_bytes(void)
|
||||||
|
{
|
||||||
|
if (likely(crng_ready()))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
int ret;
|
||||||
|
ret = wait_event_interruptible_timeout(crng_init_wait, crng_ready(), HZ);
|
||||||
|
if (ret)
|
||||||
|
return ret > 0 ? 0 : ret;
|
||||||
|
|
||||||
|
try_to_generate_entropy();
|
||||||
|
} while (!crng_ready());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(wait_for_random_bytes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a callback function that will be invoked when the input
|
||||||
|
* pool is initialised.
|
||||||
|
*
|
||||||
|
* returns: 0 if callback is successfully added
|
||||||
|
* -EALREADY if pool is already initialised (callback not called)
|
||||||
|
* -ENOENT if module for callback is not alive
|
||||||
|
*/
|
||||||
|
int add_random_ready_callback(struct random_ready_callback *rdy)
|
||||||
|
{
|
||||||
|
struct module *owner;
|
||||||
|
unsigned long flags;
|
||||||
|
int err = -EALREADY;
|
||||||
|
|
||||||
|
if (crng_ready())
|
||||||
|
return err;
|
||||||
|
|
||||||
|
owner = rdy->owner;
|
||||||
|
if (!try_module_get(owner))
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&random_ready_list_lock, flags);
|
||||||
|
if (crng_ready())
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
owner = NULL;
|
||||||
|
|
||||||
|
list_add(&rdy->list, &random_ready_list);
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_unlock_irqrestore(&random_ready_list_lock, flags);
|
||||||
|
|
||||||
|
module_put(owner);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(add_random_ready_callback);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete a previously registered readiness callback function.
|
||||||
|
*/
|
||||||
|
void del_random_ready_callback(struct random_ready_callback *rdy)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct module *owner = NULL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&random_ready_list_lock, flags);
|
||||||
|
if (!list_empty(&rdy->list)) {
|
||||||
|
list_del_init(&rdy->list);
|
||||||
|
owner = rdy->owner;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&random_ready_list_lock, flags);
|
||||||
|
|
||||||
|
module_put(owner);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(del_random_ready_callback);
|
||||||
|
|
||||||
|
static void process_random_ready_list(void)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct random_ready_callback *rdy, *tmp;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&random_ready_list_lock, flags);
|
||||||
|
list_for_each_entry_safe(rdy, tmp, &random_ready_list, list) {
|
||||||
|
struct module *owner = rdy->owner;
|
||||||
|
|
||||||
|
list_del_init(&rdy->list);
|
||||||
|
rdy->func(rdy);
|
||||||
|
module_put(owner);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&random_ready_list_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define warn_unseeded_randomness(previous) \
|
||||||
|
_warn_unseeded_randomness(__func__, (void *)_RET_IP_, (previous))
|
||||||
|
|
||||||
|
static void _warn_unseeded_randomness(const char *func_name, void *caller, void **previous)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_WARN_ALL_UNSEEDED_RANDOM
|
||||||
|
const bool print_once = false;
|
||||||
|
#else
|
||||||
|
static bool print_once __read_mostly;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (print_once || crng_ready() ||
|
||||||
|
(previous && (caller == READ_ONCE(*previous))))
|
||||||
|
return;
|
||||||
|
WRITE_ONCE(*previous, caller);
|
||||||
|
#ifndef CONFIG_WARN_ALL_UNSEEDED_RANDOM
|
||||||
|
print_once = true;
|
||||||
|
#endif
|
||||||
|
if (__ratelimit(&unseeded_warning))
|
||||||
|
printk_deferred(KERN_NOTICE "random: %s called from %pS with crng_init=%d\n",
|
||||||
|
func_name, caller, crng_init);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
POOL_BITS = BLAKE2S_HASH_SIZE * 8,
|
POOL_BITS = BLAKE2S_HASH_SIZE * 8,
|
||||||
POOL_MIN_BITS = POOL_BITS /* No point in settling for less. */
|
POOL_MIN_BITS = POOL_BITS /* No point in settling for less. */
|
||||||
@@ -210,34 +389,8 @@ enum {
|
|||||||
* Static global variables
|
* Static global variables
|
||||||
*/
|
*/
|
||||||
static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
|
static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
|
||||||
static struct fasync_struct *fasync;
|
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(random_ready_list_lock);
|
|
||||||
static LIST_HEAD(random_ready_list);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* crng_init = 0 --> Uninitialized
|
|
||||||
* 1 --> Initialized
|
|
||||||
* 2 --> Initialized from input_pool
|
|
||||||
*
|
|
||||||
* crng_init is protected by primary_crng->lock, and only increases
|
|
||||||
* its value (from 0->1->2).
|
|
||||||
*/
|
|
||||||
static int crng_init = 0;
|
|
||||||
#define crng_ready() (likely(crng_init > 1))
|
|
||||||
static int crng_init_cnt = 0;
|
static int crng_init_cnt = 0;
|
||||||
static void process_random_ready_list(void);
|
|
||||||
static void _get_random_bytes(void *buf, size_t nbytes);
|
|
||||||
|
|
||||||
static struct ratelimit_state unseeded_warning =
|
|
||||||
RATELIMIT_STATE_INIT("warn_unseeded_randomness", HZ, 3);
|
|
||||||
static struct ratelimit_state urandom_warning =
|
|
||||||
RATELIMIT_STATE_INIT("warn_urandom_randomness", HZ, 3);
|
|
||||||
|
|
||||||
static int ratelimit_disable __read_mostly;
|
|
||||||
|
|
||||||
module_param_named(ratelimit_disable, ratelimit_disable, int, 0644);
|
|
||||||
MODULE_PARM_DESC(ratelimit_disable, "Disable random ratelimit suppression");
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
*
|
*
|
||||||
@@ -322,22 +475,6 @@ static void fast_mix(u32 pool[4])
|
|||||||
pool[2] = c; pool[3] = d;
|
pool[2] = c; pool[3] = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_random_ready_list(void)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
struct random_ready_callback *rdy, *tmp;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&random_ready_list_lock, flags);
|
|
||||||
list_for_each_entry_safe(rdy, tmp, &random_ready_list, list) {
|
|
||||||
struct module *owner = rdy->owner;
|
|
||||||
|
|
||||||
list_del_init(&rdy->list);
|
|
||||||
rdy->func(rdy);
|
|
||||||
module_put(owner);
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&random_ready_list_lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void credit_entropy_bits(size_t nbits)
|
static void credit_entropy_bits(size_t nbits)
|
||||||
{
|
{
|
||||||
unsigned int entropy_count, orig, add;
|
unsigned int entropy_count, orig, add;
|
||||||
@@ -387,8 +524,6 @@ static DEFINE_PER_CPU(struct crng, crngs) = {
|
|||||||
.lock = INIT_LOCAL_LOCK(crngs.lock),
|
.lock = INIT_LOCAL_LOCK(crngs.lock),
|
||||||
};
|
};
|
||||||
|
|
||||||
static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* crng_fast_load() can be called by code in the interrupt service
|
* crng_fast_load() can be called by code in the interrupt service
|
||||||
* path. So we can't afford to dilly-dally. Returns the number of
|
* path. So we can't afford to dilly-dally. Returns the number of
|
||||||
@@ -909,29 +1044,6 @@ static bool drain_entropy(void *buf, size_t nbytes)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define warn_unseeded_randomness(previous) \
|
|
||||||
_warn_unseeded_randomness(__func__, (void *)_RET_IP_, (previous))
|
|
||||||
|
|
||||||
static void _warn_unseeded_randomness(const char *func_name, void *caller, void **previous)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_WARN_ALL_UNSEEDED_RANDOM
|
|
||||||
const bool print_once = false;
|
|
||||||
#else
|
|
||||||
static bool print_once __read_mostly;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (print_once || crng_ready() ||
|
|
||||||
(previous && (caller == READ_ONCE(*previous))))
|
|
||||||
return;
|
|
||||||
WRITE_ONCE(*previous, caller);
|
|
||||||
#ifndef CONFIG_WARN_ALL_UNSEEDED_RANDOM
|
|
||||||
print_once = true;
|
|
||||||
#endif
|
|
||||||
if (__ratelimit(&unseeded_warning))
|
|
||||||
printk_deferred(KERN_NOTICE "random: %s called from %pS with crng_init=%d\n",
|
|
||||||
func_name, caller, crng_init);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is the exported kernel interface. It returns some
|
* This function is the exported kernel interface. It returns some
|
||||||
* number of good random numbers, suitable for key generation, seeding
|
* number of good random numbers, suitable for key generation, seeding
|
||||||
@@ -1032,107 +1144,6 @@ static void try_to_generate_entropy(void)
|
|||||||
mix_pool_bytes(&stack.now, sizeof(stack.now));
|
mix_pool_bytes(&stack.now, sizeof(stack.now));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Wait for the urandom pool to be seeded and thus guaranteed to supply
|
|
||||||
* cryptographically secure random numbers. This applies to: the /dev/urandom
|
|
||||||
* device, the get_random_bytes function, and the get_random_{u32,u64,int,long}
|
|
||||||
* family of functions. Using any of these functions without first calling
|
|
||||||
* this function forfeits the guarantee of security.
|
|
||||||
*
|
|
||||||
* Returns: 0 if the urandom pool has been seeded.
|
|
||||||
* -ERESTARTSYS if the function was interrupted by a signal.
|
|
||||||
*/
|
|
||||||
int wait_for_random_bytes(void)
|
|
||||||
{
|
|
||||||
if (likely(crng_ready()))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
int ret;
|
|
||||||
ret = wait_event_interruptible_timeout(crng_init_wait, crng_ready(), HZ);
|
|
||||||
if (ret)
|
|
||||||
return ret > 0 ? 0 : ret;
|
|
||||||
|
|
||||||
try_to_generate_entropy();
|
|
||||||
} while (!crng_ready());
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(wait_for_random_bytes);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns whether or not the urandom pool has been seeded and thus guaranteed
|
|
||||||
* to supply cryptographically secure random numbers. This applies to: the
|
|
||||||
* /dev/urandom device, the get_random_bytes function, and the get_random_{u32,
|
|
||||||
* ,u64,int,long} family of functions.
|
|
||||||
*
|
|
||||||
* Returns: true if the urandom pool has been seeded.
|
|
||||||
* false if the urandom pool has not been seeded.
|
|
||||||
*/
|
|
||||||
bool rng_is_initialized(void)
|
|
||||||
{
|
|
||||||
return crng_ready();
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(rng_is_initialized);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add a callback function that will be invoked when the nonblocking
|
|
||||||
* pool is initialised.
|
|
||||||
*
|
|
||||||
* returns: 0 if callback is successfully added
|
|
||||||
* -EALREADY if pool is already initialised (callback not called)
|
|
||||||
* -ENOENT if module for callback is not alive
|
|
||||||
*/
|
|
||||||
int add_random_ready_callback(struct random_ready_callback *rdy)
|
|
||||||
{
|
|
||||||
struct module *owner;
|
|
||||||
unsigned long flags;
|
|
||||||
int err = -EALREADY;
|
|
||||||
|
|
||||||
if (crng_ready())
|
|
||||||
return err;
|
|
||||||
|
|
||||||
owner = rdy->owner;
|
|
||||||
if (!try_module_get(owner))
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&random_ready_list_lock, flags);
|
|
||||||
if (crng_ready())
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
owner = NULL;
|
|
||||||
|
|
||||||
list_add(&rdy->list, &random_ready_list);
|
|
||||||
err = 0;
|
|
||||||
|
|
||||||
out:
|
|
||||||
spin_unlock_irqrestore(&random_ready_list_lock, flags);
|
|
||||||
|
|
||||||
module_put(owner);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(add_random_ready_callback);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Delete a previously registered readiness callback function.
|
|
||||||
*/
|
|
||||||
void del_random_ready_callback(struct random_ready_callback *rdy)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
struct module *owner = NULL;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&random_ready_list_lock, flags);
|
|
||||||
if (!list_empty(&rdy->list)) {
|
|
||||||
list_del_init(&rdy->list);
|
|
||||||
owner = rdy->owner;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&random_ready_list_lock, flags);
|
|
||||||
|
|
||||||
module_put(owner);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(del_random_ready_callback);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function will use the architecture-specific hardware random
|
* This function will use the architecture-specific hardware random
|
||||||
* number generator if it is available. It is not recommended for
|
* number generator if it is available. It is not recommended for
|
||||||
|
Reference in New Issue
Block a user