summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin LI <delphij@FreeBSD.org>2018-08-20 02:17:55 +0000
committerXin LI <delphij@FreeBSD.org>2018-08-20 02:17:55 +0000
commit59488f25ad9d2e804f85a48d38e38df9e94ae61d (patch)
tree1139d89f388a20b1284e686ae4aba1d31c8dcb5c
parentbeacffb30d89c29505f2303d91396e3603f54dd9 (diff)
Notes
-rw-r--r--lib/libc/gen/getentropy.c37
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. */