bug-guix
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#37501: [core-updates] Entropy starvation during boot


From: Marius Bakke
Subject: bug#37501: [core-updates] Entropy starvation during boot
Date: Fri, 04 Oct 2019 00:10:29 +0200
User-agent: Notmuch/0.29.1 (https://notmuchmail.org) Emacs/26.2 (x86_64-pc-linux-gnu)

Ludovic Courtès <address@hidden> writes:

> Hi again,
>
> Marius Bakke <address@hidden> skribis:
>
>> After reconfiguring on the 'core-updates' branch, systems using the
>> OpenSSH service will occasionally (not always!) hang forever during
>> boot, waiting for entropy.  Moving the mouse or mashing the keyboard
>> allows the boot to proceed.
>>
>> I don't think this is limited to OpenSSH, but anything that calls
>> getrandom() during startup.
>>
>> There is some information about this problem and various workarounds
>> here, including links to recent LKML discussions:
>>
>> https://daniel-lange.com/archives/152-hello-buster.html
>
> I read some of these, and our ‘urandom-seed-service-type’ has the same
> bug as <https://github.com/systemd/systemd/issues/4271>.  Namely, we
> write the previous seed to /dev/urandom but we don’t credit the
> entropy.
>
> The attached patch fixes that, and I think it should fix the problem you
> reported.  Could people give it a try?

Good catch, LGTM.  Unfortunately it does not fix the problem.

> I’m interested in seeing the value of
> /proc/sys/kernel/random/entropy_avail with and without this patch right
> after boot (don’t try it in ‘guix system vm’ because there’s no seed
> there.)

before -  243
after  - 2419

I don't know why this change was insufficient.  Perhaps the kernel
does not consider such a seed alone trustworthy enough?  I also tried to
increase the seed size to no avail.

I found this patch in the 5.4 kernel tree after reading the commit log
of random.c:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3f2dc2798b81531fd93a3b9b7c39da47ec689e55

...which *does* solve the problem.

The comments in the merge commit suggests that it is not necessarily a
good solution, so I think we should let it "settle" a bit upstream
before pushing it.  It does look rather sledgehammer-y...

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3f2dc2798b81531fd93a3b9b7c39da47ec689e55

Thoughts?

I have attached a patch that adds Linus' fix for the curious:

diff --git a/gnu/local.mk b/gnu/local.mk
index 9f8ce842b6..b9b6ea3ae7 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1078,6 +1078,7 @@ dist_patch_DATA =                                         
\
   %D%/packages/patches/lierolibre-remove-arch-warning.patch    \
   %D%/packages/patches/lierolibre-try-building-other-arch.patch        \
   %D%/packages/patches/linkchecker-tests-require-network.patch \
+  %D%/packages/patches/linux-libre-active-entropy.patch                \
   %D%/packages/patches/linux-pam-no-setfsuid.patch             \
   %D%/packages/patches/lirc-localstatedir.patch                        \
   %D%/packages/patches/lirc-reproducible-build.patch           \
diff --git a/gnu/packages/linux.scm b/gnu/packages/linux.scm
index 6664620c04..dda95c29ac 100644
--- a/gnu/packages/linux.scm
+++ b/gnu/packages/linux.scm
@@ -420,7 +420,8 @@ corresponding UPSTREAM-SOURCE (an origin), using the given 
DEBLOB-SCRIPTS."
 
 (define-public linux-libre-5.2-source
   (source-with-patches linux-libre-5.2-pristine-source
-                       (list %boot-logo-patch
+                       (list (search-patch "linux-libre-active-entropy.patch")
+                             %boot-logo-patch
                              
%linux-libre-arm-export-__sync_icache_dcache-patch)))
 
 (define-public linux-libre-4.19-source
diff --git a/gnu/packages/patches/linux-libre-active-entropy.patch 
b/gnu/packages/patches/linux-libre-active-entropy.patch
new file mode 100644
index 0000000000..8f081f4a19
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-active-entropy.patch
@@ -0,0 +1,86 @@
+Try to actively add entropy instead of waiting forever.
+Fixes <https://bugs.gnu.org/37501>.
+
+Taken from upstream:
+https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/?id=50ee7529ec4500c88f8664560770a7a1b65db72b
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index 5d5ea4ce1442..2fda6166c1dd 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -1731,6 +1731,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
+@@ -1745,7 +1795,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);
+ 

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]