Re: [PATCH] s6-rc-update: avoid getrandom(2)

From: Rasmus Villemoes <rasmus.villemoes_at_prevas.dk>
Date: Wed, 27 Sep 2017 09:23:34 +0200

On 2017-09-26 17:47, Laurent Bercot wrote:
>
>> On a modern linux system, s6-rc-update ends up calling getrandom(2) via
>> the random_sauniquename() library function. But on embedded systems, and
>> especially during early initialization, that is likely to block, which
>> means that the entire boot process hangs.
>
> Yes. That's a feature. You *want* random byte generation to block
> until the entropy pool is filled up, else it can lead to security
> issues.

TYVM, I'm well aware of the reason getrandom(2) was introduced, and I
_do_ want (hope) that whatever utility programs I use that rely on
cryptographically strong random numbers (ssh-keygen and whatnot) have
been updated to use that (and thus block until they can get such strong
random numbers) when available. s6-rc-update does not have any use for
cryptographically strong random numbers.

>> No, writing 160 bytes of crap to /dev/urandom as random_init does makes
>> no difference; it does not in any way "speed up /dev/urandom
>> initialization".
>
> Indeed it doesn't, unfortunately. The point isn't to speed it up,
> it's to shuffle the seed a bit more.

src/librandom/random_makeseed.c says that that's precisely the point; I
was quoting verbatim.

     11 Certainly not cryptographically secure or 100% unpredictable,
     12 but we're only using this to speed up /dev/urandom
     13 initialization or to init an internal SURF PRNG.

But I'm glad we agree that the random_init voodoo does not, in fact,
have any effect on when getrandom(,,0) becomes non-blocking.

>> And no, we cannot just make sure the kernel's random number generator is
>> fully initialized before calling s6-rc-update, as s6-rc-update may very
>> well be the one that starts the service(s) that eventually ensures this
>> initialization (e.g., all the network-facing services).
>
> And that's what I don't understand. Why are you calling s6-rc-update
> as part of your boot process? s6-rc-update is designed for live
> service database replacement; at boot time, you don't have anything
> to replace. Isn't s6-rc-init + s6-rc enough for your booting
> procedure?

No, it's not. Roughly, the setup consists of a read-only rootfs
(squashfs, so really readonly), with a set of predefined services. As
part of the first s6-rc-init + s6-rc, a data partition is mounted, and
from the data located there, an additional set of services and/or
dependencies are generated, and only when that new service database is
compiled do we know precisely which services we need to be up at the end
of the init phase.

> As an aside, you cannot rely on network-facing services to fill up your
> entropy pool. Network-facing services typically use cryptography, and
> that is exactly the case where you _need_ a full entropy pool first
> and working around it is a very bad idea.

Yeah, slightly bad example, but the point is that until the system is
fully initialized, which includes ifup'ing some set of ethernet
interfaces, talking to some sensors, etc., we don't have a lot of
sources of entropy. Even _when_ the board is fully up, it takes up to 30
seconds before the 'random: nonblocking pool is initialized' message
appears. Neither the end users, developers, PMs nor the hardware
watchdog will tolerate a boot time of upwards of 30 seconds.

It's a sad fact, but nevertheless a fact, that many embedded systems out
there simply do not have a lot of sources of entropy, so relying on
getrandom(,,0) not blocking for too long is simply wrong on such systems.

>> In general, none of the infrastructure utilities (skaware or otherwise)
>> involved in the boot process can be allowed to make a possibly-blocking
>> getrandom() call.
>
> I agree. That is the reason why why s6-ftrigrd hardcodes the SURF PRNG
> for its temporary pipe name generation:
>
> https://git.skarnet.org/cgi-bin/cgit.cgi/s6/tree/src/libs6/ftrig1_make.c
>
> I don't like to do this any more than is strictly necessary, because
> I don't want to have to wonder about the predictability of the names;
> if a program isn't part of the early boot process and has no reason
> to be run before the entropy pool fills up, I'd rather rely on randomness
> given by the machine. Good, secure randomness.

But this part I don't understand. Why do you insist on using your own
homebrewed scheme (which will only ever try one - albeit I agree in
practice guaranteed to be universally unique - name), when perfectly
sane and safe standard functions exist that do the same? I mean, what is
the security issue you see with using mkstemp/mkdtemp? What can an
attacker possibly do by guessing the name before-hand that he could not
do by learning it with readdir() afterwards? You really don't need good,
secure randomness for generating a guaranteed-to-be-owned-by-you file/dir.

Yes, it's a pity that mkfifotemp and mksymlinktemp do not exist; but
it's really not hard to implement them in a way that avoids relying on
true random numbers.

> I'm open to being convinced that s6-rc-update has a legit reason to be
> run before the entropy pool fills up, but that's really not how I see
> things; so please elaborate on why your setup is the way it is.

I don't understand how you can have a whitelist of programs that
(paraphrasing) "may be part of the early boot process and thus may have
a reason to run before the entropy pool fills up" - at least, I haven't
seen any notice in any skaware documentation that says "don't call this
during your init procedure - may effectively deadlock the machine". How
should the user know which s6-programs can be used and which cannot?

Rasmus

-- 
Rasmus Villemoes
Software Developer
Prevas A/S
Hedeager 1
DK-8200 Aarhus N
+45 51210274
rasmus.villemoes_at_prevas.dk
www.prevas.dk
Received on Wed Sep 27 2017 - 07:23:34 UTC

This archive was generated by hypermail 2.3.0 : Sun May 09 2021 - 19:38:49 UTC