Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!

Bug 835926

Summary: sys-apps/openrc: entropy seed regresses in quality and does not init RNG
Product: Gentoo Security Reporter: Jason A. Donenfeld <zx2c4>
Component: VulnerabilitiesAssignee: Gentoo Security <security>
Status: RESOLVED INVALID    
Severity: normal CC: blueness, dwfreed, gentoo, idl0r, openrc, patrick, sam, security-audit, vapier, williamh
Priority: Normal Keywords: PullRequest
Version: unspecified   
Hardware: All   
OS: Linux   
URL: https://github.com/gentoo/gentoo/pull/24784
See Also: https://bugs.gentoo.org/show_bug.cgi?id=698590
https://github.com/gentoo/gentoo/pull/24784
Whiteboard:
Package list:
Runtime testing required: ---

Description Jason A. Donenfeld gentoo-dev 2022-03-24 14:20:57 UTC
There are two security problems with OpenRC's RNG initialization shell script.

1. Writing into /dev/{u}random doesn't actually initialize the RNG. It writes into the entropy pool, but no entropy is credited. It is impossible to actually credit from a shell script.

2. Reading a seed back immediately after writing into /dev/{u}random will regress in entropy at early boot, because /dev/{u}random doesn't actually start using the written seed until the RNG is initialized. This is bad news bears, as it means if you start with a good seed, you'll immediately get a bad, potentially deterministic, one.

There are two solutions:

a. To fix problem (2) with a shellscript, you can adopt this approach from buildroot: https://git.buildroot.net/buildroot/commit/?id=f0986de551f46e72268857fd817986e9be697cd0

b. To fix problem (1) and to more robustly address problem (2), you should use my seedrng.c code:
https://git.zx2c4.com/seedrng/about/
https://git.zx2c4.com/seedrng/tree/seedrng.c

I'm looking now into bringing seedrng into busybox for use in buildroot. It would also make sense to bring this into openrc. Alternatively, I could make a package out of it, but the actual intent of that code base is that it's pulled verbatim into various downstreams.

Since OpenRC/Gentoo is a rather nimble project, I'd recommend going straight to solution (b) and skipping over the intermediate solution (a).

Reproducible: Always
Comment 1 Jason A. Donenfeld gentoo-dev 2022-03-24 14:49:44 UTC
Just to reiterate my feeling on seedrng.c: that's C that's meant to be copied and pasted into openrc somewhere, and I don't mind if it gets reformatted/renamed/re-whatevered. It's meant to be mangled as needed. Maybe it's a thing for libexec; maybe it's a thing for sbin. I'm okay with whatever in that regard.
Comment 2 Jason A. Donenfeld gentoo-dev 2022-03-24 15:11:05 UTC
Looking closer at openrc, it'd probably make sense to call this `openrc-seedrng`, akin to `openrc-shutdown`:

  executable('openrc-shutdown',
    ['openrc-shutdown.c', 'broadcast.c', 'rc-sysvinit.c', rc_misc_c,
                usage_c, rc_wtmp_c, version_h],
    c_args : cc_branding_flags,
    include_directories: [incdir, einfo_incdir, rc_incdir],
    link_with: [libeinfo, librc],
    install: true,
    install_dir: sbindir)

And then you can adjust seedrng.c's printing to use libeinfo and all that jazz.
Comment 3 Jason A. Donenfeld gentoo-dev 2022-03-24 15:27:14 UTC
Reported this over on the Github tracker, as it seems that's what the OpenRC team prefers: https://github.com/OpenRC/openrc/issues/506
Comment 4 Jason A. Donenfeld gentoo-dev 2022-03-25 05:47:47 UTC
Implementing in https://github.com/OpenRC/openrc/pull/507
Comment 5 Jason A. Donenfeld gentoo-dev 2022-03-27 02:47:44 UTC
Fixed with:

commit 076c2552aeff88a27fe275dfaae61dedf4bb4bd5
Author: Jason A. Donenfeld <Jason@zx2c4.com>
Date:   Thu Mar 24 22:07:16 2022

    Use seedrng for seeding the random number generator
    
    The RNG can't actually be seeded from a shell script, due to the
    reliance on ioctls. For this reason, the seedrng project provides a
    basic script meant to be copy and pasted into projects like OpenRC and
    tweaked as needed: https://git.zx2c4.com/seedrng/about/
    
    This commit imports it into OpenRC and wires up /etc/init.d/urandom to
    call it. It shouldn't be called by other things on the system, so it
    lives in rc_sbindir.
    
    Closes #506.
    Closes #507.
    
    Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>


I'll keep this open so that security can do its usual tracking thing waiting for a release.
Comment 6 John Helmert III archtester Gentoo Infrastructure gentoo-dev Security 2022-03-28 01:35:19 UTC
(In reply to Jason A. Donenfeld from comment #0)
> There are two security problems with OpenRC's RNG initialization shell
> script.
> 
> 1. Writing into /dev/{u}random doesn't actually initialize the RNG. It
> writes into the entropy pool, but no entropy is credited. It is impossible
> to actually credit from a shell script.
> 
> 2. Reading a seed back immediately after writing into /dev/{u}random will
> regress in entropy at early boot, because /dev/{u}random doesn't actually
> start using the written seed until the RNG is initialized. This is bad news
> bears, as it means if you start with a good seed, you'll immediately get a
> bad, potentially deterministic, one.

How? And how likely is this worst case? This probably needs a CVE, especially now that the issue is public and patches are proliferating.

> There are two solutions:
> 
> a. To fix problem (2) with a shellscript, you can adopt this approach from
> buildroot:
> https://git.buildroot.net/buildroot/commit/
> ?id=f0986de551f46e72268857fd817986e9be697cd0
> 
> b. To fix problem (1) and to more robustly address problem (2), you should
> use my seedrng.c code:
> https://git.zx2c4.com/seedrng/about/
> https://git.zx2c4.com/seedrng/tree/seedrng.c
> 
> I'm looking now into bringing seedrng into busybox for use in buildroot. It
> would also make sense to bring this into openrc. Alternatively, I could make
> a package out of it, but the actual intent of that code base is that it's
> pulled verbatim into various downstreams.
> 
> Since OpenRC/Gentoo is a rather nimble project, I'd recommend going straight
> to solution (b) and skipping over the intermediate solution (a).
> 
> Reproducible: Always
Comment 7 John Helmert III archtester Gentoo Infrastructure gentoo-dev Security 2022-03-29 14:24:47 UTC
Jason replied to me in #gentoo-dev:

23:46 <@zx2c4> ajak: "this probably needs a CVE" -- i'm not sure it does actually
23:46 <@zx2c4> getrandom(0) will still block until enough entropy is acquired through other means
23:47 <@zx2c4> the current shellscripts are all wrong and bad for a bunch of reasons, but i dont think anything here is catastrophic
23:48 <@zx2c4> that's why im doing this out in the public step by step. it's just necessary infrastructure work that must be done. an irksome slog. but nothing here is super terrible

So, seems like this is less of a real security issue (because the bad entropy is not credited) and more of some RNG/entropy related logic bugs?
Comment 8 kfm 2022-03-29 18:30:42 UTC
(In reply to John Helmert III from comment #7)

> So, seems like this is less of a real security issue (because the bad
> entropy is not credited) and more of some RNG/entropy related logic bugs?

To obtain cryptographically secure entropy, the RNG must be known to have concluded its seeding process first (it writes a message to dmesg at that point). As such, any program that needs entropy of this grade ought to be using getrandom with a flags parameter of 0, so as to be blocked until that happens. If I were to encounter such a program that did not use this interface, I would consider it a bug in that program.

The quirk of the /dev/urandom interface - as implemented in Linux - has always been that it will not block prior to seeding having concluded, though that's not an impediment to programs that run early during boot and and only require entropy for non-crytographic purposes.

As for the /dev/random interface, it was a train wreck up until Linux 5.6, whereupon it was reworked so as to behave exactly as /dev/urandom does, with the sole exception of being prepared to block until seeding has concluded. Arguably, this is how it should have worked from the outset. As such, using /dev/random is no longer problematic but it will take a long time for the world to be rid of pre-5.6 kernels.

So, using /dev/random is already similar to using getentropy(0) on a recent kernel and nothing that requires entropy for cryptographic purposes should be using /dev/urandom anyway.

Finally, OpenRC's prior urandom script wrote out its seed in the context of the stop() function. As the cross-referenced bug demonstrates, some users have hardware that still struggles to initialise the RNG in a timely fashion. Presumably, if such a user were to shut down quickly enough, it's possible that it could be executed prior to the RNG having been initialised. Given that said seed was read from the non-blocking urandom interface, that's sufficient to raise an eyebrow. Still, I'm not sure that it's CVE-worthy, given that the seed was never afforded any credit prior to the introduction of Jason's commendable patch.
Comment 9 kfm 2022-03-29 18:35:55 UTC
(In reply to Kerin Millar from comment #8)
> (In reply to John Helmert III from comment #7)

> So, using /dev/random is already similar to using getentropy(0) on a recent
> kernel and nothing that requires entropy for cryptographic purposes should
> be using /dev/urandom anyway.

I'll word that a little differently as it potentially makes it sound as though I'm perpetuating the urandom-is-insecure meme. To be clear, urandom is otherwise fine but does not - and will probably never be made to - block until the RNG is ready. For that, using the syscall is always the best bet.