More randomness or less
CVE-2008-0166 is an infamous example of using uninitialized memory for random number generation. A Debian maintainer commented out two lines of code to silence Valgrind, which complained about the uses of uninitialized memory as a “bonus” source of entropy, and this change caused OpenSSL to generate bogus keys on Debian-based systems.
Actually, using uninitialized memory has always been a very bad idea, not only because it confuses developers and tools like Valgrind, but because a smart C compiler will kick you in the teeth. Here is one example in FreeBSD and Mac OS X libc.
srandomdev() function is used to seed
to its manpage, “suitable for cryptographic use.” It first
/dev/random, which is non-blocking on FreeBSD and Mac OS X;
if that fails, it falls back to using current time and pid, with
some amazing extra bits.
struct timeval tv; unsigned long junk; gettimeofday(&tv, NULL); srandom((getpid() << 16) ^ tv.tv_sec ^ tv.tv_usec ^ junk);
You can see that the seed is computed using results from
getpid(), mixed with the value of an uninitialized stack
junk. Here’s the corresponding assembly code (
from Mac OS X 10.6 (Snow Leopard).
leaq 0xe0(%rbp),%rdi xorl %esi,%esi callq 0x001422ca ; symbol stub for: _gettimeofday callq 0x00142270 ; symbol stub for: _getpid movq 0xe0(%rbp),%rdx movl 0xe8(%rbp),%edi xorl %edx,%edi shll $0x10,%eax xorl %eax,%edi xorl %ebx,%edi callq 0x00142d68 ; symbol stub for: _srandom
Everything looks good so far.
Now let’s look at the same code
from 10.7 (Lion) and 10.8 (Mountain Lion).
leaq 0xd8(%rbp),%rdi xorl %esi,%esi callq 0x000a427e ; symbol stub for: _gettimeofday callq 0x000a3882 ; symbol stub for: _getpid callq 0x000a4752 ; symbol stub for: _srandom
Wait, the entire seed computation is gone! The results of
getpid() are not used at all;
is called with some “garbage” value.
I guess Apple has switched from GCC to LLVM for compiling libc in
newer Mac OS X. Since the C code contains undefined behavior, the
use of uninitialized variable
junk, LLVM optimizes away the
computation more aggressively. You should see the same assembly
if compiling FreeBSD using LLVM.
There are several interesting questions to explore.
Is it possible to trigger this by somehow failing
/dev/randomon FreeBSD and Mac OS X?
How random is the
srandom()seed now compiled using LLVM, which is just the value of
%edi? Looks like it’s the lower 32 bits of the address of the stack variable
Does GCC generate “correct” code? Probably not. The last
%ebx, which is unlikely to correspond to the value of
junkbut the file descriptor of
movl %ebx,%edi callq 0x00141d48 ; symbol stub for: _close$NOCANCEL
In short, just don’t use uninitialized memory for more randomness.
The use of
in 1997. Google shows a bunch of similar usages and fixes.
sranddev()shares the same fall-back code.
DragonFly BSD developers added comments “XXX left uninitialized on purpose” for
OpenBSD developers removed the code in 2005.
Varnish developers fixed a similar usage, though the code is still being used by others. BTW, you can find an interesting comparison
fd >= 0there, where
fdis a pointer!