Changeset View
Changeset View
Standalone View
Standalone View
head/lib/libc/gen/getentropy.c
Show All 28 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/random.h> | #include <sys/random.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <signal.h> | |||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include "libc_private.h" | #include "libc_private.h" | ||||
/* First __FreeBSD_version bump after introduction of getrandom(2) (r331279) */ | /* First __FreeBSD_version bump after introduction of getrandom(2) (r331279) */ | ||||
#define GETRANDOM_FIRST 1200061 | #define GETRANDOM_FIRST 1200061 | ||||
extern int __sysctl(int *, u_int, void *, size_t *, void *, size_t); | extern int __sysctl(int *, u_int, void *, size_t *, void *, size_t); | ||||
static inline void | |||||
_getentropy_fail(void) | |||||
{ | |||||
raise(SIGKILL); | |||||
} | |||||
static size_t | static size_t | ||||
arnd_sysctl(u_char *buf, size_t size) | arnd_sysctl(u_char *buf, size_t size) | ||||
{ | { | ||||
int mib[2]; | int mib[2]; | ||||
size_t len, done; | size_t len, done; | ||||
mib[0] = CTL_KERN; | mib[0] = CTL_KERN; | ||||
mib[1] = KERN_ARND; | mib[1] = KERN_ARND; | ||||
Show All 27 Lines | getentropy_fallback(void *buf, size_t buflen) | ||||
if (buf == NULL && buflen > 0) { | if (buf == NULL && buflen > 0) { | ||||
errno = EFAULT; | errno = EFAULT; | ||||
return (-1); | return (-1); | ||||
} | } | ||||
if (arnd_sysctl(buf, buflen) != buflen) { | if (arnd_sysctl(buf, buflen) != buflen) { | ||||
if (errno == EFAULT) | if (errno == EFAULT) | ||||
return (-1); | return (-1); | ||||
/* | /* | ||||
* This cannot happen. _arc4_sysctl() spins until the random | * This cannot happen. arnd_sysctl() spins until the random | ||||
* device is seeded and then repeatedly reads until the full | * device is seeded and then repeatedly reads until the full | ||||
* request is satisfied. The only way for this to return a zero | * 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 | * byte or short read is if sysctl(2) on the kern.arandom MIB | ||||
* fails. In this case, exceping the user-provided-a-bogus- | * fails. In this case, excepting the user-provided-a-bogus- | ||||
* buffer EFAULT, give up (like for arc4random(3)'s arc4_stir). | * buffer EFAULT, give up (like for arc4random(3)'s arc4_stir). | ||||
*/ | */ | ||||
abort(); | _getentropy_fail(); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
getentropy(void *buf, size_t buflen) | getentropy(void *buf, size_t buflen) | ||||
{ | { | ||||
ssize_t rd; | ssize_t rd; | ||||
Show All 18 Lines | if (have_getrandom) { | ||||
* caller is already in capability | * caller is already in capability | ||||
* mode, fallback to traditional | * mode, fallback to traditional | ||||
* method in this case. | * method in this case. | ||||
*/ | */ | ||||
have_getrandom = false; | have_getrandom = false; | ||||
continue; | continue; | ||||
case EINTR: | case EINTR: | ||||
continue; | continue; | ||||
default: | case EFAULT: | ||||
return (-1); | return (-1); | ||||
default: | |||||
_getentropy_fail(); | |||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
return (getentropy_fallback(buf, buflen)); | return (getentropy_fallback(buf, buflen)); | ||||
} | } | ||||
/* This cannot happen. */ | /* This cannot happen. */ | ||||
if (rd == 0) | if (rd == 0) | ||||
abort(); | _getentropy_fail(); | ||||
buf = (char *)buf + rd; | buf = (char *)buf + rd; | ||||
buflen -= rd; | buflen -= rd; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } |