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>
[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>
  • Loading branch information
zx2c4 authored and gregkh committed May 30, 2022
1 parent 6630742 commit 849e7b7
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 74 deletions.
17 changes: 8 additions & 9 deletions crypto/drbg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1490,12 +1490,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)
Expand All @@ -1510,10 +1511,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:
Expand All @@ -1524,7 +1523,7 @@ static int drbg_prepare_hrng(struct drbg_state *drbg)
fallthrough;

default:
drbg->random_ready.func = NULL;
drbg->random_ready.notifier_call = NULL;
return err;
}

Expand Down Expand Up @@ -1628,8 +1627,8 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,
*/
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);
}

Expand Down
69 changes: 21 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,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) \
Expand Down
2 changes: 1 addition & 1 deletion include/crypto/drbg.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,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)
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
13 changes: 8 additions & 5 deletions lib/random32.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <linux/sched.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/notifier.h>
#include <asm/unaligned.h>

/**
Expand Down Expand Up @@ -551,9 +552,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 +620,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 @@ -756,14 +756,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 @@ -777,7 +779,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 849e7b7

Please sign in to comment.