]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
random: replace custom notifier chain with standard one
authorJason A. Donenfeld <Jason@zx2c4.com>
Tue, 1 Mar 2022 19:03:49 +0000 (20:03 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 25 Jun 2022 09:49:08 +0000 (11:49 +0200)
commit 5acd35487dc911541672b3ffc322851769c32a56 upstream.

We previously rolled our own randomness readiness notifier, which only
has two users in the whole kernel. Replace this with a more standard
atomic notifier block that serves the same purpose with less code. Also
unexport the symbols, because no modules use it, only unconditional
builtins. The only drawback is that it's possible for a notification
handler returning the "stop" code to prevent further processing, but
given that there are only two users, and that we're unexporting this
anyway, that doesn't seem like a significant drawback for the
simplification we receive here.

Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Dominik Brodowski <linux@dominikbrodowski.net>
[Jason: for stable, also backported to crypto/drbg.c, not unexporting.]
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
crypto/drbg.c
drivers/char/random.c
include/crypto/drbg.h
include/linux/random.h
lib/random32.c
lib/vsprintf.c

index bc52d956261102a5b6ae59e50ad56d21745abbcf..b7dc3ac39c0d312378caaa6373eeb2d7994a8c80 100644 (file)
@@ -1388,12 +1388,13 @@ static int drbg_generate_long(struct drbg_state *drbg,
        return 0;
 }
 
-static void drbg_schedule_async_seed(struct random_ready_callback *rdy)
+static int drbg_schedule_async_seed(struct notifier_block *nb, unsigned long action, void *data)
 {
-       struct drbg_state *drbg = container_of(rdy, struct drbg_state,
+       struct drbg_state *drbg = container_of(nb, struct drbg_state,
                                               random_ready);
 
        schedule_work(&drbg->seed_work);
+       return 0;
 }
 
 static int drbg_prepare_hrng(struct drbg_state *drbg)
@@ -1406,10 +1407,8 @@ static int drbg_prepare_hrng(struct drbg_state *drbg)
 
        INIT_WORK(&drbg->seed_work, drbg_async_seed);
 
-       drbg->random_ready.owner = THIS_MODULE;
-       drbg->random_ready.func = drbg_schedule_async_seed;
-
-       err = add_random_ready_callback(&drbg->random_ready);
+       drbg->random_ready.notifier_call = drbg_schedule_async_seed;
+       err = register_random_ready_notifier(&drbg->random_ready);
 
        switch (err) {
        case 0:
@@ -1420,7 +1419,7 @@ static int drbg_prepare_hrng(struct drbg_state *drbg)
                /* fall through */
 
        default:
-               drbg->random_ready.func = NULL;
+               drbg->random_ready.notifier_call = NULL;
                return err;
        }
 
@@ -1526,8 +1525,8 @@ free_everything:
  */
 static int drbg_uninstantiate(struct drbg_state *drbg)
 {
-       if (drbg->random_ready.func) {
-               del_random_ready_callback(&drbg->random_ready);
+       if (drbg->random_ready.notifier_call) {
+               unregister_random_ready_notifier(&drbg->random_ready);
                cancel_work_sync(&drbg->seed_work);
                crypto_free_rng(drbg->jent);
                drbg->jent = NULL;
index 2a6287dabbfeb86cfb98141850cb6c7609c46cdc..f1663a9be13debcfaa2b93da4868428ee995c307 100644 (file)
@@ -83,8 +83,8 @@ static int crng_init = 0;
 /* 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);
+static DEFINE_SPINLOCK(random_ready_chain_lock);
+static RAW_NOTIFIER_HEAD(random_ready_chain);
 
 /* Control how we warn userspace. */
 static struct ratelimit_state unseeded_warning =
@@ -147,72 +147,45 @@ EXPORT_SYMBOL(wait_for_random_bytes);
  *
  * 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)
+int register_random_ready_notifier(struct notifier_block *nb)
 {
-       struct module *owner;
        unsigned long flags;
-       int err = -EALREADY;
+       int ret = -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 ret;
 
-       return err;
+       spin_lock_irqsave(&random_ready_chain_lock, flags);
+       if (!crng_ready())
+               ret = raw_notifier_chain_register(&random_ready_chain, nb);
+       spin_unlock_irqrestore(&random_ready_chain_lock, flags);
+       return ret;
 }
-EXPORT_SYMBOL(add_random_ready_callback);
+EXPORT_SYMBOL(register_random_ready_notifier);
 
 /*
  * Delete a previously registered readiness callback function.
  */
-void del_random_ready_callback(struct random_ready_callback *rdy)
+int unregister_random_ready_notifier(struct notifier_block *nb)
 {
        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);
+       int ret;
 
-       module_put(owner);
+       spin_lock_irqsave(&random_ready_chain_lock, flags);
+       ret = raw_notifier_chain_unregister(&random_ready_chain, nb);
+       spin_unlock_irqrestore(&random_ready_chain_lock, flags);
+       return ret;
 }
-EXPORT_SYMBOL(del_random_ready_callback);
+EXPORT_SYMBOL(unregister_random_ready_notifier);
 
 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);
+       spin_lock_irqsave(&random_ready_chain_lock, flags);
+       raw_notifier_call_chain(&random_ready_chain, 0, NULL);
+       spin_unlock_irqrestore(&random_ready_chain_lock, flags);
 }
 
 #define warn_unseeded_randomness(previous) \
index 3fb581bf3b875b8ee90874f5caec1d2fb0d2c1d2..c027a1f7d013dcfeb9880f190905bfb9f9b928ac 100644 (file)
@@ -134,7 +134,7 @@ struct drbg_state {
        const struct drbg_state_ops *d_ops;
        const struct drbg_core *core;
        struct drbg_string test_data;
-       struct random_ready_callback random_ready;
+       struct notifier_block random_ready;
 };
 
 static inline __u8 drbg_statelen(struct drbg_state *drbg)
index 6148b8d1ccf34e448abf0378b4ede1732fe65528..d4abda9e23487274104b188f442a42ca04c59840 100644 (file)
 
 #include <uapi/linux/random.h>
 
-struct random_ready_callback {
-       struct list_head list;
-       void (*func)(struct random_ready_callback *rdy);
-       struct module *owner;
-};
+struct notifier_block;
 
 extern void add_device_randomness(const void *, size_t);
 extern void add_bootloader_randomness(const void *, size_t);
@@ -39,8 +35,8 @@ extern void get_random_bytes(void *buf, size_t nbytes);
 extern int wait_for_random_bytes(void);
 extern int __init rand_initialize(void);
 extern bool rng_is_initialized(void);
-extern int add_random_ready_callback(struct random_ready_callback *rdy);
-extern void del_random_ready_callback(struct random_ready_callback *rdy);
+extern int register_random_ready_notifier(struct notifier_block *nb);
+extern int unregister_random_ready_notifier(struct notifier_block *nb);
 extern size_t __must_check get_random_bytes_arch(void *buf, size_t nbytes);
 
 #ifndef MODULE
index 42cbb70e09d84edba6b037cddfdc8beddf8fd2e1..339624191b515925b90b099ca8b5687f8403326f 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/sched.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
+#include <linux/notifier.h>
 #include <asm/unaligned.h>
 
 /**
@@ -546,9 +547,11 @@ static void prandom_reseed(struct timer_list *unused)
  * To avoid worrying about whether it's safe to delay that interrupt
  * long enough to seed all CPUs, just schedule an immediate timer event.
  */
-static void prandom_timer_start(struct random_ready_callback *unused)
+static int prandom_timer_start(struct notifier_block *nb,
+                              unsigned long action, void *data)
 {
        mod_timer(&seed_timer, jiffies);
+       return 0;
 }
 
 /*
@@ -557,13 +560,13 @@ static void prandom_timer_start(struct random_ready_callback *unused)
  */
 static int __init prandom_init_late(void)
 {
-       static struct random_ready_callback random_ready = {
-               .func = prandom_timer_start
+       static struct notifier_block random_ready = {
+               .notifier_call = prandom_timer_start
        };
-       int ret = add_random_ready_callback(&random_ready);
+       int ret = register_random_ready_notifier(&random_ready);
 
        if (ret == -EALREADY) {
-               prandom_timer_start(&random_ready);
+               prandom_timer_start(&random_ready, 0, NULL);
                ret = 0;
        }
        return ret;
index c2619510636eb4eefaa1f4c61120af6f45d6a7aa..5e672480d3be2ae81b23f328526d37d96b053766 100644 (file)
@@ -1700,14 +1700,16 @@ static void enable_ptr_key_workfn(struct work_struct *work)
 
 static DECLARE_WORK(enable_ptr_key_work, enable_ptr_key_workfn);
 
-static void fill_random_ptr_key(struct random_ready_callback *unused)
+static int fill_random_ptr_key(struct notifier_block *nb,
+                              unsigned long action, void *data)
 {
        /* This may be in an interrupt handler. */
        queue_work(system_unbound_wq, &enable_ptr_key_work);
+       return 0;
 }
 
-static struct random_ready_callback random_ready = {
-       .func = fill_random_ptr_key
+static struct notifier_block random_ready = {
+       .notifier_call = fill_random_ptr_key
 };
 
 static int __init initialize_ptr_random(void)
@@ -1721,7 +1723,7 @@ static int __init initialize_ptr_random(void)
                return 0;
        }
 
-       ret = add_random_ready_callback(&random_ready);
+       ret = register_random_ready_notifier(&random_ready);
        if (!ret) {
                return 0;
        } else if (ret == -EALREADY) {