]> git.itanic.dy.fi Git - linux-stable/commitdiff
random: add back async readiness notifier
authorJason A. Donenfeld <Jason@zx2c4.com>
Wed, 16 Nov 2022 16:16:37 +0000 (17:16 +0100)
committerJason A. Donenfeld <Jason@zx2c4.com>
Tue, 22 Nov 2022 13:53:00 +0000 (14:53 +0100)
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>
drivers/char/random.c
include/linux/random.h

index 65ee6989696710ab002fa7ecbe021d22f17ab9ec..a2a18bd3d7d73c55bdf153bf0e8924309aeb7ad0 100644 (file)
@@ -84,6 +84,7 @@ static DEFINE_STATIC_KEY_FALSE(crng_is_ready);
 /* Various types of waiters for crng_init->CRNG_READY transition. */
 static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
 static struct fasync_struct *fasync;
+static ATOMIC_NOTIFIER_HEAD(random_ready_notifier);
 
 /* Control how we warn userspace. */
 static struct ratelimit_state urandom_warning =
@@ -140,6 +141,26 @@ int wait_for_random_bytes(void)
 }
 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() \
        if (IS_ENABLED(CONFIG_WARN_ALL_UNSEEDED_RANDOM) && !crng_ready()) \
                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. */
                if (static_key_initialized)
                        execute_in_process_context(crng_set_ready, &set_ready);
+               atomic_notifier_call_chain(&random_ready_notifier, 0, NULL);
                wake_up_interruptible(&crng_init_wait);
                kill_fasync(&fasync, SIGIO, POLL_IN);
                pr_notice("crng init done\n");
index 579117d83eb81e8613ad15496045ffa124897877..b1a34181eed6992a6dbedc8313f261baabf06818 100644 (file)
@@ -120,6 +120,7 @@ void __init random_init_early(const char *command_line);
 void __init random_init(void);
 bool rng_is_initialized(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).
  * Returns the result of the call to wait_for_random_bytes. */