diff options
author | Xin LI <delphij@FreeBSD.org> | 2018-08-20 02:17:55 +0000 |
---|---|---|
committer | Xin LI <delphij@FreeBSD.org> | 2018-08-20 02:17:55 +0000 |
commit | 59488f25ad9d2e804f85a48d38e38df9e94ae61d (patch) | |
tree | 1139d89f388a20b1284e686ae4aba1d31c8dcb5c | |
parent | beacffb30d89c29505f2303d91396e3603f54dd9 (diff) |
Notes
-rw-r--r-- | lib/libc/gen/getentropy.c | 37 |
1 files changed, 29 insertions, 8 deletions
diff --git a/lib/libc/gen/getentropy.c b/lib/libc/gen/getentropy.c index 2e0f649a15be..4e91afc6a6a1 100644 --- a/lib/libc/gen/getentropy.c +++ b/lib/libc/gen/getentropy.c @@ -34,10 +34,14 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <errno.h> +#include <stdbool.h> #include <stdlib.h> #include "libc_private.h" +/* First __FreeBSD_version bump after introduction of getrandom(2) (r331279) */ +#define GETRANDOM_FIRST 1200061 + extern int __sysctl(int *, u_int, void *, size_t *, void *, size_t); static size_t @@ -99,21 +103,38 @@ int getentropy(void *buf, size_t buflen) { ssize_t rd; + bool have_getrandom; if (buflen > 256) { errno = EIO; return (-1); } + have_getrandom = (__getosreldate() >= GETRANDOM_FIRST); + while (buflen > 0) { - rd = getrandom(buf, buflen, 0); - if (rd == -1) { - if (errno == EINTR) - continue; - else if (errno == ENOSYS || errno == ECAPMODE) - return (getentropy_fallback(buf, buflen)); - else - return (-1); + if (have_getrandom) { + rd = getrandom(buf, buflen, 0); + if (rd == -1) { + switch (errno) { + case ECAPMODE: + /* + * Kernel >= r331280 and < r337999 + * will return ECAPMODE when the + * caller is already in capability + * mode, fallback to traditional + * method in this case. + */ + have_getrandom = false; + continue; + case EINTR: + continue; + default: + return (-1); + } + } + } else { + return (getentropy_fallback(buf, buflen)); } /* This cannot happen. */ |