Index: head/lib/libc/gen/arc4random.c =================================================================== --- head/lib/libc/gen/arc4random.c +++ head/lib/libc/gen/arc4random.c @@ -111,8 +111,8 @@ rs.j = rs.i; } -static size_t -arc4_sysctl(u_char *buf, size_t size) +size_t +__arc4_sysctl(u_char *buf, size_t size) { int mib[2]; size_t len, done; @@ -143,7 +143,7 @@ arc4_init(); rs_initialized = 1; } - if (arc4_sysctl(rdat, KEYSIZE) != KEYSIZE) { + if (__arc4_sysctl(rdat, KEYSIZE) != KEYSIZE) { /* * The sysctl cannot fail. If it does fail on some FreeBSD * derivative or after some future change, just abort so that Index: head/lib/libc/gen/getentropy.c =================================================================== --- head/lib/libc/gen/getentropy.c +++ head/lib/libc/gen/getentropy.c @@ -37,6 +37,39 @@ #include "libc_private.h" +/* + * If a newer libc is accidentally installed on an older kernel, provide high + * quality random data anyway. The sysctl interface is not as fast and does + * not block by itself, but is provided by even very old kernels. + */ +static int +getentropy_fallback(void *buf, size_t buflen) +{ + /* + * oldp (buf) == NULL has a special meaning for sysctl that results in + * no EFAULT. For compatibility with the kernel getrandom(2), detect + * this case and return the appropriate error. + */ + if (buf == NULL && buflen > 0) { + errno = EFAULT; + return (-1); + } + if (__arc4_sysctl(buf, buflen) != buflen) { + if (errno == EFAULT) + return (-1); + /* + * This cannot happen. _arc4_sysctl() spins until the random + * device is seeded and then repeatedly reads until the full + * request is satisfied. The only way for this to return a zero + * byte or short read is if sysctl(2) on the kern.arandom MIB + * fails. In this case, exceping the user-provided-a-bogus- + * buffer EFAULT, give up (like for arc4random(3)'s arc4_stir). + */ + abort(); + } + return (0); +} + int getentropy(void *buf, size_t buflen) { @@ -53,7 +86,7 @@ if (errno == EINTR) continue; else if (errno == ENOSYS) - abort(); + return (getentropy_fallback(buf, buflen)); else return (-1); } Index: head/lib/libc/include/libc_private.h =================================================================== --- head/lib/libc/include/libc_private.h +++ head/lib/libc/include/libc_private.h @@ -405,6 +405,8 @@ int __sys_utimensat(int fd, const char *path, const struct timespec *times, int flag) __hidden; +__size_t __arc4_sysctl(unsigned char *, __size_t); + /* execve() with PATH processing to implement posix_spawnp() */ int _execvpe(const char *, char * const *, char * const *); Index: head/lib/libc/sys/Symbol.map =================================================================== --- head/lib/libc/sys/Symbol.map +++ head/lib/libc/sys/Symbol.map @@ -628,8 +628,6 @@ __sys_getppid; _getpriority; __sys_getpriority; - _getrandom; - __sys_getrandom; _getresgid; __sys_getresgid; _getresuid; Index: head/lib/libc/tests/gen/getentropy_test.c =================================================================== --- head/lib/libc/tests/gen/getentropy_test.c +++ head/lib/libc/tests/gen/getentropy_test.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -76,6 +77,8 @@ ATF_TP_ADD_TCS(tp) { + + signal(SIGSYS, SIG_IGN); ATF_TP_ADD_TC(tp, getentropy_count); ATF_TP_ADD_TC(tp, getentropy_fault);