
LibreSSL's PRNG is Unsafe on Linux - agwa
https://www.agwa.name/blog/post/libressls_prng_is_unsafe_on_linux
======
quotemstr
There's also pthread_atfork. Use that to reset the PRNG. It's a bad interface,
but it'll work for this purpose. It bothers me when people very solemnly and
seriously condemn systems for problems that are, in fact, amenable to
reasonable solutions.

~~~
agwa
> There's also pthread_atfork.

That requires linking with libpthread, which a single-threaded program would
not normally do. Otherwise, it's not a bad suggestion.

Still, on top of everything LibreSSL does to automatically detect forks, it
should _still_ expose a way to explicitly reseed the PRNG in an OpenSSL-
compatible way, since OpenSSL has made guarantees that certain functions will
re-seed the PRNG, and there may be some scenarios where even the best
automatic fork detection fails (imagine a program calling the clone syscall
directly for whatever reason, in which case pthread_atfork handlers won't be
called). Since LibreSSL is billed as a drop-in replacement for OpenSSL, you
should not be able to write a valid program that's safe under OpenSSL's
guarantees but not when linked with LibreSSL.

~~~
quotemstr
The libc on my system, Ubuntu 14.04, exports __register_atfork, which is
documented here:

> [http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-
> generic/LSB...](http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-
> generic/LSB-Core-generic/baselib--register-atfork.html)

pthread_atfork itself really should be moved into libc, however. (And POSIX
should stop treating it as a redheaded stepchild: it's useful!)

~~~
pavpanchekha
A threading interface was standardized into C 2011, so pthreads should
eventually stop being necessary. In a sense, not just POSIX, but C proper has
adopted a threading interface.

~~~
quotemstr
The C threads interface is missing important functionality --- priority
inheritance and static mutex initializers come to mind. C11 threads.h is a
lowest-common-denominator portability shim, not a general-purpose pthreads
replacement.

~~~
coder23
threads.h are the lowest common denominator. If you want system specific
functionality you can always wrap those functions.

Static mutex init can be emulated with call_once() function, with some
limitations of its own of course.

------
syncsynchalt
As a developer who's integrated with openssl several times (generally on
Linux), I couldn't be more pleased with the results coming out of the libreSSL
effort.

Even if we end up with a list of linux-specific gotchas (and I don't think we
will), it is more a case of ten steps forward, one step back.

------
hsivonen
Can we, please, have a syscall in Linux that returns random bytes from the
system CSPRNG or blocks if not seeded yet and doesn't involve dealing with
file descriptors?

But even while one isn't available, why is LibreSSL trying to use a userland
CSPRNG instead of always reading from /dev/urandom and aborting when that
fails?

~~~
AlyssaRowan
Yes. Actually, the relevant IETF list is now calling for that: Linux needs
getentropy(2). I may cook up my own and submit it to LKML, or perhaps someone
else can, but there's no way out of this one without kernel support.

I don't know why the rest of the function even exists. It's the kind of cruft
libReSSL is trying to get rid of.

I am not entirely sure a PRNG should even exist in the library, and
personally, I'd pass it onto /dev/urandom or /dev/random or the relevant
syscall.

I agree with making it (154-156) a hard kill for a TLS library not to be able
to get entropy.

And, this is great! This is exactly the kind of thing we're able to find now
that some of the code isn't a hedge-maze.

~~~
vidarh
The comments in the code makes it exceedingly clear that a part of the reason
for this code to exist is to make a point, and it seems they've succeeded very
well at that.

------
rlpb
Why must it have its own PRNG? Is there a problem asking the kernel (via
/dev/urandom) for all required entropy, at the time it is needed? Or would
this cause a real-world performance problem?

Surely this is an obvious first question that all commentators are stepping
over?

~~~
orik
It isn't about performance, but instead /dev/urandom is believed to be a poor
source of entropy by the OpenBSD developers.

I believe the heart of the issue it that /dev/urandom will give you a string
even if it has very low entropy at the time.

You can find all sorts of articles for and against /dev/urandom and I don't
really know enough to comment on it's security, but I trust the that the team
working on this fork more than I trust the OpenSSL foundation.

~~~
vidarh
The issue is not that they believe /dev/urandom to be bad, but that it flat
out isn't guaranteed to be available: If you're chroot'ed, chances are you
won't have read access (or see) /dev/urandom. Furthermore, if you've run out
of file handles (maybe intentionally - because someone figures they can try to
DOS you to attack the PRNG), it is not a given you'll be able to open it even
if it's visible.

LibreSSL tries /dev/urandom first, then falls back on a deprecated sysctl()
interface, then tries it's own "last resort fallback".

~~~
xorcist
Then abort if it's not available? A lot of software (most?) doesn't work with
an empty /dev. At least null is othen required, so why not throw urandom in
there as well?

~~~
vidarh
The source explains why the developers does not see aborting as acceptable: It
opens a huge security hole on systems where core files are insufficiently
secured. On systems that are properly secured, it's a single define to cause
it to fail hard when it can't use either /dev/urandom or sysctl().

~~~
xorcist
I see, but I am not convinced. I think the argument still stands. There are
always other ways to crash.

------
dobbsbob
>First, LibreSSL should raise an error if it can't get a good source of
entropy.

Comments for getentropy_linux.c explain this [http://www.openbsd.org/cgi-
bin/cvsweb/src/lib/libcrypto/cryp...](http://www.openbsd.org/cgi-
bin/cvsweb/src/lib/libcrypto/crypto/getentropy_linux.c?rev=1.2;content-
type=text%2Fplain)

We have very few options:

\- Even syslog_r is unsafe to call at this low level, so there is no way to
alert the user or program. \- Cannot call abort() because some systems have
unsafe corefiles.

~~~
agwa
The comments don't justify why going to the sketchy entropy is better than
SIGKILLing the process, except with:

> This code path exists to bring light to the issue that Linux does not
> provide a failsafe API for entropy collection.

Trying to make a point about Linux doesn't seem like a very good reason to me.

~~~
dobbsbob
The sketchy entropy is only an example, and is a work in progress. Comments
read "XXX Should be replaced with a proper entropy measure." and is only
called if entropy collection via /dev/urandom and sysctl have failed. If the
sysctl method is depreciated it does raise(SIGKILL). They also rearranged
getentroy_linux.c so that the main function with the important comments is at
the top in hopes whoever is porting reads it.

If you were porting this to a GNU/Linux distro, you can read their list of
options and raise (SIGKILL) resulting in silent termination if that's what
your platform decided to do if both entropy methods fail, or test for it
earlier and fail. Since they are BSD developers they leave it up to whoever is
porting to decide.

------
blahrf
You can't simply seed it before a chroot. Look at the code. chacha adds
entropy periodically and folds it in. You need entropy in the chroot. The
author should probably read 10 lines below the same code he posted in the
article. While I'd love to see a solution for this particular contrived
example, considering in the much more common use cases it actually is more
secure than OpenSSL's. Especially so if your kernel has sysctl in it.

~~~
agwa
> chacha adds entropy periodically and folds it in. You need entropy in the
> chroot.

If that's the case then the fix will not be as simple as I envisioned it.
Still, the point stands that LibreSSL should allow you to initialize the PRNG
once, before you chroot, so that you can use the PRNG safely once inside the
chroot. This could be accomplished by keeping a file descriptor to
/dev/urandom open.

~~~
blahrf
"If that's the case?" \- Didn't you read the code? :) Sounds like you would
prefer no stirring of any new entropy after you chroot... Looks to me like
they're trying to require that additional entropy be available, always. (and
if you don't have a completely hacked up kernel sysctl is still there..) -
maybe we might get something better before it (sysctl) goes away for real
instead of just in c-library-du-jour.

~~~
agwa
You're correct :-) - it does periodically stir in new entropy.

I'm fine with stirring in new entropy after chrooting - I just don't want to
see sketchy entropy being used, especially for the initial entropy source. If
you could make LibreSSL open (and keep open) /dev/urandom before you chroot,
LibreSSL could read additional entropy from the already open file descriptor,
even after chrooting.

In any case, note that the chroot issue is a bit of a sideshow compared to the
much more serious fork issue.

~~~
blahrf
Not sure how a library is going to keep a caller from closing a descriptor -
I've certainly seen people attempt to close them all in code before a fork,
but that's probably pathological. However that doesn't work across a re-exec,
which would also be good practice in many situations (ASLR) - so having to
keep a descriptor open to do this would actually discourage secure programming
practices because the library would screw you then. What's here will work in
that case from the look of it. (assuming sysctl is there, or the voodoo isn't
really that bad, I can't tell myself yet... still looking)

~~~
agwa
Those are good points. Really, Linux needs a proper, non-deprecated, syscall
for this.

------
cnst
What _agwa_ wants from LibreSSL is to behave in every little bit _exactly_ as
OpenSSL does, even though OpenSSL itself is a complete and utter mess.

OpenSSL allowed developers to interfere with RNG freely, so LibreSSL must do
that, too? [Even if times have
changed?]([http://permalink.gmane.org/gmane.os.openbsd.cvs/129485](http://permalink.gmane.org/gmane.os.openbsd.cvs/129485))

Well, you can't really go at improving and cleaning up the library if you have
to keep up all the old bugs and the whole crusty API around.

It's inconceivable to expect LibreSSL to be both better than OpenSSL, yet to
have the exact same API and the exact same set of bugs and nuances as the
original OpenSSL.

LibreSSL is meant to be a simple-enough replacement of OpenSSL for most modern
software out there ([http://ports.su/](http://ports.su/)) — possibly with some
minimal patching
([http://permalink.gmane.org/gmane.os.openbsd.tech/37599](http://permalink.gmane.org/gmane.os.openbsd.tech/37599))
of some of the outside software — and not a one-to-one drop-in-replacement for
random edge cases that depend on random and deprecated OpenSSL craft.

------
amalcon
Note that the usual post-fork catch-all security advice (having the child
process exec() to wipe process state, thereby making a state leak really hard)
solves the fork safety problem by giving the child a whole new PRNG instance,
but actually makes it harder to solve the chroot safety problem.

There are various tricks to get a limited number of bytes from /dev/urandom
into the chroot jail (such as by writing them to a regular file and secure-
erasing that file when finished) to get around that.

~~~
agwa
How about passing the /dev/urandom file descriptor to the new process? That
seems like the most robust solution to me.

~~~
vidarh
That assumes that first process after the chroot knows how to receive and pass
on that filedescriptor to the process that will eventually use libressl, which
is not a given.

------
waterhouse
Looks like this issue has been addressed and fixes have been pushed. The fix
involves something similar to the pthread_atfork solution a couple of people
have suggested.

[http://opensslrampage.org/post/91910269738/fix-for-the-
libre...](http://opensslrampage.org/post/91910269738/fix-for-the-libressl-
prng-issue-under-linux)

------
nwmcsween
This is just due to ignorance, Linux provides a AT_RANDOM auxv on process
creation that could be used to seed the prng.

~~~
enjolras
look at the code. AT_RANDOM is. used when it's avaible in the fallback
function. For some reason, the devs don't seem to trust it much, according to
the comment.

~~~
edwintorok
Is it guaranteed to at least be different for different processes? They could
use that in addition to the PID test to know when to reseed.

~~~
wahern
No. It's only filled on execve, not fork.

------
blahrf
Even though it looks like it won't get called, I'm wondering how bad the
voodoo is? Anyone looked at what it is spitting into that hash function? How
predictable are those clocks as they change between the memory fetches. Will
Linux have predictable memory access times where those pages land?

------
ars
Is LibreSSL written by the same team that wrote this incorrect article?
[https://news.ycombinator.com/item?id=7700312](https://news.ycombinator.com/item?id=7700312)

------
darthsitius
How can 2 processes have the same PID, even if it is grandparent and
grandchild? When I try killing a process using the PID, how the kernel know
which to kill?

~~~
ryan-c
Assume a fairly busy system

* Original process with PID 17519

* PID 17519 forks producing a new process with PID 26606

* PID 17519 produces some "random" bytes then exits

* PID 26606 forks producing a new process with the now unused PID 17519

* New PID 17519 produces some "random" bytes, which will be the same as the "random" bytes produced by original PID 17519, causing a raptor to attack the user.

~~~
pbhjpbhj
So, PID is used as part of the CSPRNG?

If I get a block from /dev/urandom, then another one at some later time, what
are the chances it's identical? Isn't that what you're saying here (or was the
whole post intended to be comical and not just the last line).

[If only it had been raining it would have taken days longer for the raptor to
attack, or something /random]

~~~
edwintorok
The problem is that (Libre|Open)SSL doesn't use /dev/urandom directly and
instead implements a CSPRNG in user-space (seeded from /dev/urandom). And then
you need to be careful to reseed the CSPRNG after fork or you'll generate the
same random number that the other process did.

You could mix in the parent's PID too, but that would only delay the problem
(you'd need more layers of fork before triggering the shared-state bug again).

Why can't LibreSSL just open /dev/urandom once, on first call to
RAND_poll/RAND_bytes/some-other-init-function, etc. and then always read from
it directly. If that first open fails then you return an error from
RAND_poll/RAND_bytes.

~~~
ryan-c
/dev/urandom is pretty slow on Linux. OpenSSL's CSPRNG is several times
faster. On my workstation just now, I get 13MB/sec from /dev/urandom and
61MB/sec from OpenSSL's CSPRNG.

You can't just add the parent pid because that information is lost when the
process's parent exits (the ppid becomes 1).

------
bydo
Schadenfreude?

~~~
talideon
Hardly. LibreSSL works just fine on OpenBSD and doesn't have this issue.
Portability to Linux is a secondary concern, and this is only an initial stab
at the portability layer for Linux.

------
algorithm_dk
We need to stop useless forks.

------
tormeh
Can't the LibreSSL process just reseed whenever it is started? I guess forks
don't actually copy the program counter so they'll have to go through main,
right?

~~~
cjg_
It does copy the PC. Actually it just return from the fork call twice, one in
the parent and one in the child, with different return values, the pid of the
child to the parent and zero to the child.

See [http://linux.die.net/man/2/fork](http://linux.die.net/man/2/fork) for
more details

------
meshko
It is not entirely clear what is the risk of this strange scenario involving a
grandchild process and pids wrapping around in an alarmingly quick way.

~~~
pavpanchekha
The risk is that in some situations (it should not matter how often; the
environment might be somewhat attacker-controlled) two processes produce
identical random numbers. This is bad, because this breaks the assumption that
random numbers are independent. A program may reasonably fork into two
processes, one which uses random numbers to generate RSA keys and one which
outputs random numbers to anyone who wants them. LibreSSL's flaw may allow
these two processes to destroy each other's security guarantee.

~~~
blahrf
Ahh, not really - while the process thing the author describes is real - what
you're saying is that any two processes show the same values, and that isn't
the case. the bad guy needs to control one process to read the values in a
useful way, have it exit, and be able to maniuplate the system by killing or
creating processes until his intended victim comes up on his selected PID.
While that's far from impossible to do (just as the author's program does it)
It is likely going to imply enough access to your system by the attacker that
you're already pretty much p0wned.

~~~
agwa
An attacker doesn't necessarily need to know the random values themselves to
pull off an attack. For example, if a nonce is re-used, an attacker might be
able to decrypt data sniffed from the network. Also, creating processes to
force a PID wraparound might be as simple as making repeated requests to a
server.

------
_pmf_
Don't rain on their parade. OpenSSL has been determined to be a laughing stock
by super-informed internet forum people, and we need to keep up pretending
that a rewrite of a major piece of internet infrastructure is feasible and
makes sense.

------
jodiscr
Given things like the Debian OpenSSL fiasco and Heartbleed, can we honestly
put as much faith into open source crypto as it's well-funded proprietary
counterparts?

I honestly prefer open source and recognize the problem the author points out
as clearly significant problem - as well as the benefits of LibreSSL, but I'm
just not convinced there are enough eyeballs looking at open source crypto.

~~~
wbl
Ever hear of BSAFE? They took a million dollars from the NSA to implant a
backdoor. How do you evaluate code you cannot see?

~~~
jodiscr
yes, but I'm talking about RNG from likes of Microsoft or Apple...

~~~
nitrogen
If you can't evaluate it, you can't trust it. Plus, Apple had gotofail, and MS
has had its share of issues as well.

~~~
jodiscr
can't evaluate > not enough funds to evaluate

In other words, with proprietary sw, at least SOMEBODY evaluated it and placed
their seal/name on it. With open source, you are relying on a hope that
somebody out there somewhere does it. And in various cases, we've seen how
that turned out.

~~~
boomlinde
... and in some cases, we've seen how using proprietary software turned out.

You're not making a substantial argument, but if someone has a track record of
writing completely safe software that doesn't have to be secured through third
party products, like Microsoft, I will be willing to listen.

