Skip to content

Commit

Permalink
random: replace custom notifier chain with standard one
Browse files Browse the repository at this point in the history
commit 5acd354 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>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
zx2c4 authored and gregkh committed May 30, 2022
1 parent bdfa599 commit 367c559
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 64 deletions.
67 changes: 19 additions & 48 deletions drivers/char/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -147,72 +147,43 @@ 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);

/*
* 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);

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) \
Expand Down
10 changes: 3 additions & 7 deletions include/linux/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@

#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);
Expand All @@ -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
Expand Down
12 changes: 7 additions & 5 deletions lib/random32.c
Original file line number Diff line number Diff line change
Expand Up @@ -551,9 +551,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;
}

#ifdef CONFIG_RANDOM32_SELFTEST
Expand Down Expand Up @@ -617,13 +619,13 @@ core_initcall(prandom32_state_selftest);
*/
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;
Expand Down
10 changes: 6 additions & 4 deletions lib/vsprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -762,14 +762,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)
Expand All @@ -783,7 +785,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) {
Expand Down

0 comments on commit 367c559

Please sign in to comment.