First of all, there is a difference between writing to /dev/random
and/or /dev/urandom
and increasing the entropy count maintained in the Kernel.
This is the reasony why, by default, /dev/random
is world-writable - any input will only augment, but never replace the internal state of the RNG; if you write completely predictable data, you're doing no good, but no harm either.
If, on the other hand, you write to /dev/random using a special ioctl (and that does require superuser privileges), you can actually increase the entropy estimate.
If you are able to do that (and if you are, you could as easily replace /dev/random
with /dev/notsorandom
and be done with it), /dev/random
degenerates to the behavior of /dev/urandom
: Usually, reads from random
are supposed to block until at least as many bits of entropy have been written to the internal pool than are requrested, while urandom
returns as much "randomness" as requested.)
If you manage to write predictable bits to the pool, but tell the kernel to credit them as unpredictable data, the next reader(s) of /dev/random will receive random numbers that only deterministically depend on the current internal state of the entropy pools, and not on "truly random" events like disk seek times and keyboard inputs.
However, unless you are able to perform that attack from the very installation of the operating system, you don't actually know that internal state! Predicting it from /dev/random
outputs is at least as hard as reversing SHA-1 (and that's perceived to be very difficult). This is also why it can be reasoned that, for the exception of directly after a fresh OS install, urandom
can be considered to be "random enough" for all purposes, cryptographic or not.
Now let's have a look at the actual implementation of RdRand in drivers/char/random.c:
The only place the possibly malicious RdRand instruction is ever used is in the output functions of the random devices. It is XORed with the "actual" output of the "classical" Linux RNG right before that output is returned to the caller.
Since information theory tells us that when we XOR a chosen string with an unknown string, we can't predict anything about how the resulting string will look after the transformation, there is nothing to be gained from subverting the RdRand instruction, at least the way it is currently used in Linux.
Update:
Some suggest that a very clever CPU might interpret calls to RdRand as a trigger for a backdor that, for example, replaces the subsequent XOR with a MOV.
I'd say that's theoretically possible, but exponentially harder to implement than to just skew the output of RdRand directly, e.g. by returning the keystream of AES-CTR under a key known only to the adversary as "random numbers".
There would have to be checks for the specific code sequence used in the Kernel; if that ever changes (e.g. by surrounding the RdRand call with some dummy XOR operations), a microcode update to adapt the heuristic would have to be widely deployed or people would get suspicious very soon.
Treating the RdRand instruction (or an equivalent on a different architecture) as just another entropy input (without increasing the estimated entropy, to be safe), would probably make the RNG even harder to subvert.
Second update:
The issue has been discussed on the kernel mailing list twice: Once in 2011, started by a patch submitted by an Intel engineer and followed by a lot of discussion about security, and once again in 2012, which eventually lead to a patch implementing the current approach. Even the concerns about triggering a backdoor that changes the behavior of some instructions (e.g. XOR or MOV) has been mentioned. As far as the XOR construction is concerned: The Linux folks claim that the XOR approach is supposedly more secure than hashing the RdRand output into the entropy pool, though some of us here are not really persuaded about that.
get_random_bytes
function and silently change the return value to be whatever it wants? $\endgroup$