random: add back async readiness notifier
This is required by vsprint, because it can't do things synchronously from hardirq context, and it will be useful for an EFI notifier as well. I didn't initially want to do this, but with two potential consumers now, it seems worth it. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
@@ -84,6 +84,7 @@ static DEFINE_STATIC_KEY_FALSE(crng_is_ready);
|
|||||||
/* Various types of waiters for crng_init->CRNG_READY transition. */
|
/* 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 ATOMIC_NOTIFIER_HEAD(random_ready_notifier);
|
||||||
|
|
||||||
/* Control how we warn userspace. */
|
/* Control how we warn userspace. */
|
||||||
static struct ratelimit_state urandom_warning =
|
static struct ratelimit_state urandom_warning =
|
||||||
@@ -140,6 +141,26 @@ int wait_for_random_bytes(void)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(wait_for_random_bytes);
|
EXPORT_SYMBOL(wait_for_random_bytes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a callback function that will be invoked when the crng is initialised,
|
||||||
|
* or immediately if it already has been. Only use this is you are absolutely
|
||||||
|
* sure it is required. Most users should instead be able to test
|
||||||
|
* `rng_is_initialized()` on demand, or make use of `get_random_bytes_wait()`.
|
||||||
|
*/
|
||||||
|
int __cold execute_with_initialized_rng(struct notifier_block *nb)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&random_ready_notifier.lock, flags);
|
||||||
|
if (crng_ready())
|
||||||
|
nb->notifier_call(nb, 0, NULL);
|
||||||
|
else
|
||||||
|
ret = raw_notifier_chain_register((struct raw_notifier_head *)&random_ready_notifier.head, nb);
|
||||||
|
spin_unlock_irqrestore(&random_ready_notifier.lock, flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#define warn_unseeded_randomness() \
|
#define warn_unseeded_randomness() \
|
||||||
if (IS_ENABLED(CONFIG_WARN_ALL_UNSEEDED_RANDOM) && !crng_ready()) \
|
if (IS_ENABLED(CONFIG_WARN_ALL_UNSEEDED_RANDOM) && !crng_ready()) \
|
||||||
printk_deferred(KERN_NOTICE "random: %s called from %pS with crng_init=%d\n", \
|
printk_deferred(KERN_NOTICE "random: %s called from %pS with crng_init=%d\n", \
|
||||||
@@ -697,6 +718,7 @@ static void __cold _credit_init_bits(size_t bits)
|
|||||||
crng_reseed(NULL); /* Sets crng_init to CRNG_READY under base_crng.lock. */
|
crng_reseed(NULL); /* Sets crng_init to CRNG_READY under base_crng.lock. */
|
||||||
if (static_key_initialized)
|
if (static_key_initialized)
|
||||||
execute_in_process_context(crng_set_ready, &set_ready);
|
execute_in_process_context(crng_set_ready, &set_ready);
|
||||||
|
atomic_notifier_call_chain(&random_ready_notifier, 0, NULL);
|
||||||
wake_up_interruptible(&crng_init_wait);
|
wake_up_interruptible(&crng_init_wait);
|
||||||
kill_fasync(&fasync, SIGIO, POLL_IN);
|
kill_fasync(&fasync, SIGIO, POLL_IN);
|
||||||
pr_notice("crng init done\n");
|
pr_notice("crng init done\n");
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ void __init random_init_early(const char *command_line);
|
|||||||
void __init random_init(void);
|
void __init random_init(void);
|
||||||
bool rng_is_initialized(void);
|
bool rng_is_initialized(void);
|
||||||
int wait_for_random_bytes(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).
|
/* Calls wait_for_random_bytes() and then calls get_random_bytes(buf, nbytes).
|
||||||
* Returns the result of the call to wait_for_random_bytes. */
|
* Returns the result of the call to wait_for_random_bytes. */
|
||||||
|
|||||||
Reference in New Issue
Block a user