Open daurnimator opened 7 years ago
Thanks for the suggestion. For the moment I am stuck with glibc 2.23 (and musl 1.1.16) so, no getrandom() here.
How would you detect that getrandom is supported by the libc?
I have some defines available (system call, getrandom flags in linux/random.h), but they come with the kernel include files. Is there some #define in glibc 2.25 that I could test?
Can use:
#if defined __GLIBC_PREREQ && !defined __UCLIBC__
#define GLIBC_PREREQ(M, m) (__GLIBC_PREREQ(M, m))
#else
#define GLIBC_PREREQ(M, m) 0
#endif
#ifndef HAVE_GETRANDOM
#define HAVE_GETRANDOM (GLIBC_PREREQ(2,25) && __linux__)
#endif
Then inside randombytes, something like:
void randombytes(unsigned char *x,unsigned long long xlen)
{
int i;
#if HAVE_GETRANDOM
while (xlen > 0) {
i = getrandom(x, xlen, 0);
if (i == -1) break;
x += i;
xlen -= i;
}
#endif
Followed by the rest of the current randombytes function. (That way it falls back to current behaviour if your use a new glibc with an old kernel)
While you're working on randombytes, there's a few other changes to make:
O_CLOEXEC
to open
(don't want to leak it into children)read
return EINTR
then try again immediatelyarc4random_buf
for bsdsI didn't kow about __GLIBC_PREREQ. Will set up a more recent distro with a glibc 2.25+ to implement it. Thanks for the complete detection code.
re. O_CLOEXEC: I wiil use it.
re. EINTR: I consider retricting the randombytes function to 256 bytes at most. So If I get it right I should never get EINTR (either with getrandom() or with /dev/urandom.
re. arc4random_buf for bsds: I think the way to go with OpenBSD would be getentropy() (an inspiration for Linux' getrandom()), and for FreeBSD, /dev/urandom should be supported. I didn't research yet about NetBSD.
For the time being, I have no BSD installation handy, so I am not ready to support them.
re. EINTR: I consider retricting the randombytes function to 256 bytes at most. So If I get it right I should never get EINTR (either with getrandom() or with /dev/urandom.
EINTR occurs if a signal is pending when you call read
. the kernel will tell userspace to handle the signal; and then return EINTR
without returning anything from the read: its up to the application/library to retry the read
.
re. arc4random_buf for bsds: I think the way to go with OpenBSD would be getentropy() (an inspiration for Linux' getrandom()), and for FreeBSD, /dev/urandom should be supported. I didn't research yet about NetBSD. For the time being, I have no BSD installation handy, so I am not ready to support them.
Actually it's the other way around: arc4random_buf
is the inspiration for getrandom
, which they wanted to standardise, so they created getentropy
(which just doesn't have the linux specific flags), which I totally forgot existed.
Looks like getentropy
was also added in glibc 2.25, so you should just use that (as it's supported on more than just linux). For now, use the same style of #ifdef
that I showed above. Until you can do proper testing on bsd, if a bsd user wants to use getentropy they'll have to pass -DHAVE_GETENTROPY
to their compiler.
Support was added to glibc in version 2.25.