> Date: Sun, 3 May 2020 10:28:08 +0200 > From: Kurt Roeckx <k...@roeckx.be> > > [OpenBSD] seem to use RDRAND when it's available in the bootloader, or > something else when it's not. It's still my understanding that > the bootloader is responisble for providing the entropy. You can > argue that it might not contain as much entropy as you would like > in all cases. > [...] > Various of their drivers have support for RNGs that are available > on hardware, which seems to include: amdpm, glxsb, pchb, hifn, > safe, ccp, tpm, amlrng, bcmirng, bcmrng, mvrng, octrng, omrng, > rkrng, urng, uonerng. It's unclear to me if any of them are used > in the bootloader.
NetBSD has drivers for various hardware RNGs too which will generally gather entropy before userland starts (usually as soon as they are discovered during bus enumeration at boot), and on x86 NetBSD will gather entropy from RDRAND/RDSEED very early on in the kernel boot: https://nxr.netbsd.org/xref/src/sys/arch/amd64/amd64/machdep.c#1680 The NetBSD bootloader doesn't do anything with RDRAND/RDSEED, although I'm not sure it makes much of a difference to do it in the bootloader vs doing it this early on in the kernel proper. That's why I say that if what OpenBSD does satisfies you, what NetBSD does should probably satisfy you too. In any case, not every machine _has_ a hardware RNG, and not every machine is necessarily seeded, which is why NetBSD still adopts a blocking model available through /dev/random and perhaps soon through getrandom. > Date: Sun, 3 May 2020 10:48:41 +0200 > From: Kurt Roeckx <k...@roeckx.be> > > On Fri, May 01, 2020 at 07:19:09PM +0000, Taylor R Campbell wrote: > > +Despite the name, this is secure as long as you only do it > > +.Em after > > +at least one successful call without > > +.Dv GRND_INSECURE , > > +such as > > +.Li "getrandom(..., 0)" > > At which point calling with GRND_INSECURE is the same as calling > with 0 ... Generally yes, although the sysctl knob kern.entropy.depletion=1 may cause it to block again, so that you can easily test the impact of blocking on any application before you deploy it into the field where conditions may be different as a kind of fault injection, whereas getrandom(...,GRND_INSECURE) is guaranteed never to block as a reliable part of the API contract everywhere. Conceivably if a process in a VM were migrated from one host to another, getrandom(...,0) might also block twice in the same process. Point is: getrandom(...,0) has blocking as part of the API contract in edge cases, and getrandom(...,GRND_INSECURE) does not. But in normal operation without kern.entropy.depletion=1, yes, you are right. (If you want to discuss whether the Linux API should have GRND_INSECURE at all, that's more of a discussion for the LKML. The path has existed in most OSes for a couple decades, anyway -- whether via /dev/urandom, or via getentropy, or via kern.arandom.) > > +or > > +.Li "getrandom(..., GRND_RANDOM)" , > > +or after reading at least one byte from > > +.Pa /dev/random . > > Note that this is not the cases anymore on Linux. After reading 1 > byte from /dev/random, /dev/urandom can still be unintialized, and > so GRND_INSECURE is still insecure on Linux. In Linux 5.6, both getrandom(GRND_RANDOM) and /dev/random call wait_for_random_bytes(), which waits until crng_ready() is true, before returning a single byte: /dev/random: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/char/random.c?h=v5.6#n1836 getrandom(GRND_RANDOM): https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/char/random.c?h=v5.6#n2000 wait_for_random_bytes: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/char/random.c?h=v5.6#n1611 crng_ready() returns true only if crng_init > 1, which in turn is set only if (a) the CPU provided data via RDRAND/RDSEED or equivalent and all the PRNG state has been initialized, or (b) enough entropy has been gathered that that the system (via credit_entropy_bits) or the operator (via ioctl(RNDRESEEDCRNG)) decided to reseed: crng_ready(): https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/char/random.c?h=v5.6#n464 crng_init = 2, option (a): https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/char/random.c?h=v5.6#n804 crng_init = 2, option (b): https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/char/random.c?h=v5.6#n949 The bytes returned from /dev/random and getrandom(GRND_RANDOM) are then returned from the same source as /dev/urandom: getrandom(GRND_RANDOM): https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/char/random.c?h=v5.6#n2004 /dev/random: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/char/random.c?h=v5.6#n1839 /dev/urandom: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/char/random.c?h=v5.6#n1828 This has not changed since 5.6 in Linus's master branch; the only differences are around arch_get_random_* to initialize the pool with RDRAND/RDSEED or other architecture-specific equivalent, and to tweak the `entropy estimator'. So I'm pretty sure getting a byte out of /dev/random or GRND_RANDOM still implies that /dev/urandom or GRND_INSECURE is ready. I may have misread this, so I could be wrong -- but it would be a pretty weird bug for Linux to have introduced in unifying the code paths. > > +.It Dv GRND_RANDOM > > +Block until the system entropy pool has full entropy; then generate a > > +small amount of data. > > +Equivalent to reading from > > +.Pa /dev/random ; > > You might want to read https://lwn.net/Articles/808575/ > > The article states among other things that GRND_RANDOM is a noop, > it behaves just like passing 0. It is a noop in Linux 5.6, but it was not a noop in, say, Linux 4.14, which is still widely deployed. So, in general, you can't expect to be able to read more than a few bytes at a time out of GRND_RANDOM. I don't think it's worth spending a lot of time on GRND_RANDOM; the whole concept of GRND_RANDOM was silly to begin with and I'm only adding it to maintain source compatibility with Linux. Nobody should use it, and that's why I added a note to the man page that it is silly, and declined to add any usage examples. Thanks for the review!