Commit bbc7e1be authored by Jason A. Donenfeld's avatar Jason A. Donenfeld

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: default avatarJason A. Donenfeld <Jason@zx2c4.com>
parent 9148de31
...@@ -84,6 +84,7 @@ static DEFINE_STATIC_KEY_FALSE(crng_is_ready); ...@@ -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) ...@@ -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) ...@@ -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); ...@@ -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. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment