> Date: Sat, 2 May 2020 12:22:20 +0000 > From: m...@netbsd.org > > The getrandom interface intentionally traps people to make questionable > design choices.
I agree that the getrandom interface is not perfect, and I found the Linux documentation rather confusing, but after having reimplemented the semantics I realized the confusion is mostly a matter of documentation, which is why I addressed this in my original message: ### Why were you initially reluctant to adopt them and what changed? - I found the Linux documentation for getrandom difficult to follow, and I suspect most other people do too. It is hard to see what configuration of flags give you the semantics you want, and with eight different choices for the three separate flags it seemed like a good way to have lots of people shoot themselves in the foot. However, after implementing the semantics and distilling it, I realized that it cleanly breaks down into only three usage models (with an nonblocking option -- meaning when it would block, it returns EAGAIN/EWOULDBLOCK instead), two of which are reasonable (flags=0 and flags=GRND_INSECURE), and one of which we didn't already have a pathway for. So the cost of adopting a silly operation (flags=GRND_RANDOM) strikes me as quite small in exchange for the benefit of source compatibility, and I tried to address the confusing API by writing short usage guidelines with clear examples in the man page <https://www.netbsd.org/~riastradh/tmp/20200430/getrandom.html> for what the flags argument can be. If in doubt, use flags=0. In the end, getrandom(...,0) is the _only_ API to reliably block once after boot and then return arbirarily much data across many operating systems; neither /dev/random nor /dev/urandom nor getentropy nor sysctl kern.arandom nor anything else does that reliably on many operating systes. So I think it is worthwhile to adopt that API, and if we have that it takes very little to get source compatibility with the other getrandom options -- getrandom(...,GRND_INSECURE) is just another name for what we already have as sysctl(kern.arandom,...), and getrandom(..., GRND_RANDOM) is just another name for reading from /dev/random. > We might immediately take https://www.2uo.de/myths-about-urandom/ > > And re-write bits about /dev/random as being about getrandom(...,GRND_RANDOM). This would be a reasonable article to write, not because NetBSD might adopt getrandom(...,GRND_RANDOM) as a silly quirk, but because lots of other systems support _and advertise_ getrandom(...,GRND_RANDOM), like <https://blogs.oracle.com/solaris/solaris-new-system-calls%3a-getentropy2-and-getrandom2-v2> and <http://man7.org/linux/man-pages/man2/getrandom.2.html>. > Calling it "/dev/random" behaviour is ambiguous. Didn't you fix > /dev/random to not have this limitation, and be more like > getrandom(...,0)? getrandom(...,GRND_RANDOM) has a small limit on the data it will return, as in Linux. The same has been true of /dev/random for a long time -- ask to read 1000 bytes, and you might get 16. /dev/random has never been appropriate for large reads; GRND_RANDOM is the same. Generally GRND_RANDOM is silly, and I don't think it's worth spending time on it, except for the sake of source compatibility with Linux and everyone else, and to point out in the man page that it's a bad idea and to decline to give examples of using it. > Having compat shims in libc is as good as having compat shims in syscall > because it isn't possible to share raw syscall code between NetBSD and > other operating systems -- our calling convention is different. I agree -- any sort of compatibility between the underlying syscalls is _not_ the point of adding a new getrandom syscall. The point, from my original message, is that we simply don't have a path in the kernel that blocks the way getrandom is expected to, without access to the /dev/random file, so we need to add _some_ underlying syscall or other interface to the kernel: ### Why a new getrandom system call? Why not a userland libc wrapper? While getentropy(p,n) is essentially the same as sysctl(kern.arandom,p,n), the semantics of getrandom(p,n,0) (and the slightly silly semantics of getrandom(p,n,GRND_RANDOM)) requires a potentially blocking code path that is currently available to userland only via /dev/random. In other words, we have no path accessible from userland to simultaneously to satisfy desiderata (2) and (4). So if we want to satisfy them, we need a new path into the kernel.