Merge tag 'char-misc-5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-2.6-microblaze.git] / drivers / char / random.c
index d3beed0..c2f7de9 100644 (file)
@@ -1732,6 +1732,56 @@ void get_random_bytes(void *buf, int nbytes)
 }
 EXPORT_SYMBOL(get_random_bytes);
 
+
+/*
+ * Each time the timer fires, we expect that we got an unpredictable
+ * jump in the cycle counter. Even if the timer is running on another
+ * CPU, the timer activity will be touching the stack of the CPU that is
+ * generating entropy..
+ *
+ * Note that we don't re-arm the timer in the timer itself - we are
+ * happy to be scheduled away, since that just makes the load more
+ * complex, but we do not want the timer to keep ticking unless the
+ * entropy loop is running.
+ *
+ * So the re-arming always happens in the entropy loop itself.
+ */
+static void entropy_timer(struct timer_list *t)
+{
+       credit_entropy_bits(&input_pool, 1);
+}
+
+/*
+ * If we have an actual cycle counter, see if we can
+ * generate enough entropy with timing noise
+ */
+static void try_to_generate_entropy(void)
+{
+       struct {
+               unsigned long now;
+               struct timer_list timer;
+       } stack;
+
+       stack.now = random_get_entropy();
+
+       /* Slow counter - or none. Don't even bother */
+       if (stack.now == random_get_entropy())
+               return;
+
+       timer_setup_on_stack(&stack.timer, entropy_timer, 0);
+       while (!crng_ready()) {
+               if (!timer_pending(&stack.timer))
+                       mod_timer(&stack.timer, jiffies+1);
+               mix_pool_bytes(&input_pool, &stack.now, sizeof(stack.now));
+               schedule();
+               stack.now = random_get_entropy();
+       }
+
+       del_timer_sync(&stack.timer);
+       destroy_timer_on_stack(&stack.timer);
+       mix_pool_bytes(&input_pool, &stack.now, sizeof(stack.now));
+}
+
 /*
  * Wait for the urandom pool to be seeded and thus guaranteed to supply
  * cryptographically secure random numbers. This applies to: the /dev/urandom
@@ -1746,7 +1796,17 @@ int wait_for_random_bytes(void)
 {
        if (likely(crng_ready()))
                return 0;
-       return wait_event_interruptible(crng_init_wait, crng_ready());
+
+       do {
+               int ret;
+               ret = wait_event_interruptible_timeout(crng_init_wait, crng_ready(), HZ);
+               if (ret)
+                       return ret > 0 ? 0 : ret;
+
+               try_to_generate_entropy();
+       } while (!crng_ready());
+
+       return 0;
 }
 EXPORT_SYMBOL(wait_for_random_bytes);