mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC PATCH v1 22/50] lib/random32: Use random_ready_callback for seeding.
@ 2019-03-25  5:22 George Spelvin
  0 siblings, 0 replies; only message in thread
From: George Spelvin @ 2019-03-25  5:22 UTC (permalink / raw)
  To: linux-kernel, lkml
  Cc: Daniel Borkmann, Stephen Hemminger, Hannes Frederic Sowa

The whole seeding code was a mess, and triggered boot-time warnings
about crng_init=0.  Clean it up to use the random_ready_callback
exported from drivers/char/random.c.

Particular changes:
* prandom_reseed_late() was dead code
* All the locking in __prandom_reseed is unnecessary and deleted
* Moved __prandom_timer to a more logical place, in addition to
  other changes.  Sorry for the larger diff.
* Use round_jiffies on the reseed timer
* Use mod_timer is simpler to use than add_timer

Signed-off-by: George Spelvin <lkml@sdf.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Stephen Hemminger <stephen@networkplumber.org>
Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
 include/linux/random.h |   1 -
 lib/random32.c         | 157 +++++++++++++++++++----------------------
 2 files changed, 71 insertions(+), 87 deletions(-)

diff --git a/include/linux/random.h b/include/linux/random.h
index 9e30f0bb3e50b..4a325f5cf298f 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -112,7 +112,6 @@ unsigned long randomize_page(unsigned long start, unsigned long range);
 u32 prandom_u32(void);
 void prandom_bytes(void *buf, size_t nbytes);
 void prandom_seed(u32 seed);
-void prandom_reseed_late(void);
 
 struct rnd_state {
 	__u32 s[4];
diff --git a/lib/random32.c b/lib/random32.c
index 5d8483243c410..5191da383dd18 100644
--- a/lib/random32.c
+++ b/lib/random32.c
@@ -167,12 +167,17 @@ void prandom_bytes(void *buf, size_t bytes)
 }
 EXPORT_SYMBOL(prandom_bytes);
 
+/*
+ * Prefer arch_get_random_int (x86 RDRAND instruction) over
+ * arch_get_random_seed_int (x86 RDSEED) for this application,
+ * as it's good enough, and cheaper.
+ */
 static u32 __extract_hwseed(void)
 {
 	unsigned int val = 0;
 
-	(void)(arch_get_random_seed_int(&val) ||
-	       arch_get_random_int(&val));
+	(void)(arch_get_random_int(&val) ||
+	       arch_get_random_seed_int(&val));
 
 	return val;
 }
@@ -205,9 +210,7 @@ static u32 mix32(u32 x)
  *	@seed: seed value
  *	@mix_with_hwseed: flag enabling use of hardware entropy, if avaiable
  *
- *	This initializes the state without using the /dev/random pool
- *	(which is assumed to not be ready yet).  If @mix_with_hwseed is
- *	%false, the seeding is repeatable.
+ *	This avoids using /dev/urandom, which is not ready yet.
  *
  *	The test for an all-zero state is arguably pointless.  It is
  *	impossible if @mix_with_hwseed is %false, and has probability of
@@ -215,7 +218,7 @@ static u32 mix32(u32 x)
  */
 void prandom_seed_early(struct rnd_state *state, u32 seed, bool mix_with_hwseed)
 {
-	uint32_t bits;
+	u32 bits;
 
 	do {
 		int i;
@@ -231,6 +234,31 @@ void prandom_seed_early(struct rnd_state *state, u32 seed, bool mix_with_hwseed)
 }
 EXPORT_SYMBOL(prandom_seed_early);
 
+/**
+ *	prandom_init - Initial weak seeding of the prandom_u32() engine
+ */
+static int __init prandom_init(void)
+{
+	int i;
+
+	prandom_state_selftest();
+
+	for_each_possible_cpu(i) {
+		struct rnd_state *state = &per_cpu(net_rand_state, i);
+		u32 weak_seed = mix32(i + jiffies) ^ random_get_entropy();
+
+		prandom_seed_early(state, weak_seed, true);
+	}
+
+	return 0;
+}
+core_initcall(prandom_init);
+
+/*
+ * When /dev/urandom is ready, we reseed the generator completely, then
+ * do periodic minor reseeding.  The following code manages that.
+ */
+
 /**
  *	prandom_seed - add entropy to pseudo random number generator
  *	@entropy: entropy value
@@ -280,52 +308,6 @@ void prandom_seed(u32 entropy)
 }
 EXPORT_SYMBOL(prandom_seed);
 
-/*
- *	Generate some initially weak seeding values to allow
- *	to start the prandom_u32() engine.
- */
-static int __init prandom_init(void)
-{
-	int i;
-
-	prandom_state_selftest();
-
-	for_each_possible_cpu(i) {
-		struct rnd_state *state = &per_cpu(net_rand_state, i);
-		u32 weak_seed = (i + jiffies) ^ random_get_entropy();
-
-		prandom_seed_early(state, weak_seed, true);
-	}
-
-	return 0;
-}
-core_initcall(prandom_init);
-
-static void __prandom_timer(struct timer_list *unused);
-
-static DEFINE_TIMER(seed_timer, __prandom_timer);
-
-static void __prandom_timer(struct timer_list *unused)
-{
-	u32 entropy;
-	unsigned long expires;
-
-	get_random_bytes(&entropy, sizeof(entropy));
-	prandom_seed(entropy);
-
-	/* reseed every ~60 seconds, in [40 .. 80) interval with slack */
-	expires = 40 * HZ + prandom_u32_max(40 * HZ);
-	seed_timer.expires = jiffies + expires;
-
-	add_timer(&seed_timer);
-}
-
-static void __init __prandom_start_seed_timer(void)
-{
-	seed_timer.expires = jiffies + 40 * HZ;
-	add_timer(&seed_timer);
-}
-
 /**
  *	prandom_seed_full_state - Reseed PRNG with full entropy
  *	@pcpu_state: Per-CPU state to update
@@ -351,48 +333,51 @@ void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
 }
 EXPORT_SYMBOL(prandom_seed_full_state);
 
+static void __prandom_timer(struct timer_list *unused);
+
+static DEFINE_TIMER(seed_timer, __prandom_timer);
+
+static void __prandom_timer(struct timer_list *unused)
+{
+	unsigned long expires;
+	static bool seeded = false;
+
+	if (seeded) {
+		prandom_seed(get_random_u32());
+	} else if (rng_is_initialized()) {
+		/* First time, do a full reseed */
+		seeded = true;
+		prandom_seed_full_state(&net_rand_state);
+	}
+
+	/* reseed every ~60 seconds, in [40 .. 80) interval with slack */
+	expires = round_jiffies(jiffies + 40 * HZ + prandom_u32_max(40 * HZ));
+	mod_timer(&seed_timer, expires);
+}
+
 /*
- *	Generate better values after random number generator
- *	is fully initialized.
+ * The random ready callback can be called from almost any interrupt.
+ * 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_reseed(bool late)
+static void prandom_timer_start(struct random_ready_callback *unused)
 {
-	unsigned long flags;
-	static bool latch = false;
-	static DEFINE_SPINLOCK(lock);
-
-	/* Asking for random bytes might result in bytes getting
-	 * moved into the nonblocking pool and thus marking it
-	 * as initialized. In this case we would double back into
-	 * this function and attempt to do a late reseed.
-	 * Ignore the pointless attempt to reseed again if we're
-	 * already waiting for bytes when the nonblocking pool
-	 * got initialized.
-	 */
-
-	/* only allow initial seeding (late == false) once */
-	if (!spin_trylock_irqsave(&lock, flags))
-		return;
-
-	if (latch && !late)
-		goto out;
-
-	latch = true;
-	prandom_seed_full_state(&net_rand_state);
-out:
-	spin_unlock_irqrestore(&lock, flags);
+	mod_timer(&seed_timer, jiffies);
 }
 
-void prandom_reseed_late(void)
-{
-	__prandom_reseed(true);
-}
+static struct random_ready_callback random_ready = {
+        .func = prandom_timer_start
+};
 
 static int __init prandom_reseed(void)
 {
-	__prandom_reseed(false);
-	__prandom_start_seed_timer();
-	return 0;
+	int ret = add_random_ready_callback(&random_ready);
+
+	if (ret == -EALREADY) {
+		prandom_timer_start(&random_ready);
+		ret = 0;
+	}
+	return ret;
 }
 late_initcall(prandom_reseed);
 
-- 
2.26.0


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-03-28 16:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-25  5:22 [RFC PATCH v1 22/50] lib/random32: Use random_ready_callback for seeding George Spelvin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®