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

FYI/RFC: early-rng-init-tools



Hello fellow developers (and some users),

I would like to present a recent (this week) project of mine.
Background story:

In buster/sid, I noticed a massive delay booting up my laptop
and some virtual machines, which was reduced by hitting the
Shift and Ctrl keys multiple times randomly during boot; a
message “random: crng init done” would appear, and boot would
continue.

This is a well-known problem, and there are several bugs about
this; new in buster/sid compared to stretch is that it also
blocks urandom reads (I was first hit in the tomcat init script
from this). This is especially noticeable if you use a sysvinit
non-parallel boot, but I’m sure it also affects all others.

There’s already code, in both sysv-rc/initscripts and systemd,
to store some random seed file and load it on reboot. The problem
with that is that it’s just written to /dev/urandom but the kernel
is not told “hey I just gave you X bits worth of entropy”, and it
happens much too late, especially during parallel boot.

I’ve written something, a linux-any package, that…

• during postinst, creates a 128-byte random seed file in /
• updates that in a daily cronjob (using same tool as during
  boot except with more bits taken from the kernel)
• updates (the second 64-byte half, from urandom) it on shutdown
• hooks into initramfs to…
  – on x86, use “Jytter” (CPU jitter) to try and get some more
    random bytes (not accredited, just written to the pool)
  – makes it mount the root filesystem, after fsck, read-write
    instead of deferring that to the init scripts (this should
    be safe, though, as initramfs *does* fsck)
  – after the root filesystem is read-write,
    ‣ reads from the seed file (128 bytes)
    ‣ uses that and a number of other things (to make it differ)…
      ← md5sum of dmesg
      ← 3 random bytes written into initramfs during update-initramfs
      ← the current time
      ← a bit of kernel entropy (from AT_RANDOM auxvec, set anyway)
      ← on x86, Jytter and the TSC
      to initialise a stretching RNG (arc4random)
    ‣ writes between 32 and 256 bytes to /dev/urandom (but does not
      accredit them yet, just remembers the amount written)
    ‣ updates the seed file with 128 bytes from the SRNG
    ‣ fsync(2)s and close(2)s the seed file to ensure the next run
      will be different
    ‣ now tells the kernel X random bits were added, where X is…
      → the number of bytes written earlier…
      → times 6 (so we count at best six bits per byte)…
      → capped at 128*7 bits, to both not overwhelm and because our
        seed is only 128 bytes in size, estimated conservatively

tl;dr: it adds entropy during initramfs/as early as possible during
boot *and* tells the kernel it did so, to make its crng initialised,
and ensures a subsequent boot has a different seed, also updated
periodically and on shutdown for added entropy carry-over.

I’d like people to use it, experiment with it and criticise it.

Packages (.dsc / some .deb):
 http://fish.mirbsd.org/~tg/Debs/dists/sid/wtf/Pkgs/early-rng-init-tools/

Repository:
 https://evolvis.org/plugins/scmgit/cgi-bin/gitweb.cgi?p=alioth/early-rng-init-tools.git;a=tree
 git clone https://evolvis.org/anonscm/git/alioth/early-rng-init-tools.git

Licence: MirOS, some parts ISC, some x86-only parts LGPL.

I am fully aware that it is not suitable for everyone:
• it’s Linux-only (the RNG on kFreeBSD is very different, and
  I didn’t even look into Hurd’s urandom translator)
• it prevents you from booting with / mounted read-only
  ‣ although the checkroot init script remounts / read-only when needed
  ‣ perhaps we could remount / read-only ourselves afterwards,
    but that can be tricky to get right too…
• it means you trust a seed file and the arc4random algorithm (to make
  a uniform enough stream from the various seeds)
• klibc lacks clock_gettime (#923098) so we cannot add the monotonic
  clock, which would be interesting in the cronjob/shutdown hook
• it links statically against klibc, because getting Depends on the
  /lib/klibc-*.so file right is unchartered territory
• it does not use/add CPU RNG output where present
  ‣ though Linux can now do that itself, some command-line flag…
• nor is there any jitter code on nōn-x86

On the plus side, I’ve tested it on i386, amd64, x32 (although klibc
for x32 is actually amd64 so I tested that with glibc) and as a nōn-x86
architecture m68k. It also works on MirBSD, should do OpenBSD, too…

Perhaps this helps someone. While too late for buster, unless there
is any justified concern, I’ll upload it to Debian (and provide it
via buster-backports) in a while.

Enjoy,
//mirabilos
PS: please keep me in Cc, I am not subscribed to d-devel
PPS: feel free to forward/distribute this elsewhere
-- 
18:47⎜<mirabilos:#!/bin/mksh> well channels… you see, I see everything in the
same window anyway      18:48⎜<xpt:#!/bin/mksh> i know, you have some kind of
telnet with automatic pong         18:48⎜<mirabilos:#!/bin/mksh> haha, yes :D
18:49⎜<mirabilos:#!/bin/mksh> though that's more tinyirc – sirc is more comfy


Reply to: