philanc / luatweetnacl

Lua wrapper arount the Tweet NaCl cryptographic library
MIT License
17 stars 5 forks source link

Use getrandom syscall when available #4

Open daurnimator opened 7 years ago

daurnimator commented 7 years ago

Support was added to glibc in version 2.25.

philanc commented 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?

daurnimator commented 7 years ago

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)

daurnimator commented 7 years ago

While you're working on randombytes, there's a few other changes to make:

philanc commented 7 years ago

I 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.

daurnimator commented 7 years ago

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.