]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
crypto: Add option to use getrandom()
authorLubomir Rintel <lkundrak@v3.sk>
Mon, 18 Sep 2017 12:58:07 +0000 (14:58 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 1 Jan 2019 23:24:18 +0000 (01:24 +0200)
According to random(4) manual, /dev/random is essentially deprecated on
Linux for quite some time:

"The /dev/random interface is considered a legacy interface, and
/dev/urandom is preferred and sufficient in all use cases, with the
exception of applications which require randomness during early boot
time; for these applications, getrandom(2) must be used instead, because
it will block until the entropy pool is initialized."

An attempt to use it would cause unnecessary blocking on machines
without a good hwrng even when it shouldn't be needed. Since Linux 3.17,
a getrandom(2) call is available that will block only until the
randomness pool has been seeded.

It is probably not a good default yet as it requires a fairly recent
kernel and glibc (3.17 and 2.25 respectively).

Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
hostapd/Makefile
hostapd/defconfig
src/crypto/random.c
wpa_supplicant/Makefile
wpa_supplicant/defconfig

index 5fa174b969608a876842149bb699d682b17e540e..dd3816e0d440776b708015b9adc20e4c19fcec67 100644 (file)
@@ -1101,6 +1101,9 @@ endif
 ifdef CONFIG_NO_RANDOM_POOL
 CFLAGS += -DCONFIG_NO_RANDOM_POOL
 else
+ifdef CONFIG_GETRANDOM
+CFLAGS += -DCONFIG_GETRANDOM
+endif
 OBJS += ../src/crypto/random.o
 HOBJS += ../src/crypto/random.o
 HOBJS += ../src/utils/eloop.o
index 58e525dfaed0edae60402c4d013bed824cb3ff48..aeac13a67d578268755df45f0505d3ab12c33512 100644 (file)
@@ -252,6 +252,11 @@ CONFIG_IPV6=y
 # requirements described above.
 #CONFIG_NO_RANDOM_POOL=y
 
+# Should we attempt to use the getrandom(2) call that provides more reliable
+# yet secure randomness source than /dev/random on Linux 3.17 and newer.
+# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
+#CONFIG_GETRANDOM=y
+
 # Should we use poll instead of select? Select is used by default.
 #CONFIG_ELOOP_POLL=y
 
index c278d9cb9de94f3c2dc12ee6330d026dead11bf2..1cabf3f4b9a42458f6b925fb82314e0b6a8f581c 100644 (file)
@@ -25,6 +25,9 @@
 #include "utils/includes.h"
 #ifdef __linux__
 #include <fcntl.h>
+#ifdef CONFIG_GETRANDOM
+#include <sys/random.h>
+#endif /* CONFIG_GETRANDOM */
 #endif /* __linux__ */
 
 #include "utils/common.h"
@@ -228,30 +231,52 @@ int random_pool_ready(void)
                return 1; /* Already initialized - good to continue */
 
        /*
-        * Try to fetch some more data from the kernel high quality
-        * /dev/random. There may not be enough data available at this point,
+        * Try to fetch some more data from the kernel high quality RNG.
+        * There may not be enough data available at this point,
         * so use non-blocking read to avoid blocking the application
         * completely.
         */
-       fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
-       if (fd < 0) {
-               wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
-                          strerror(errno));
-               return -1;
-       }
 
-       res = read(fd, dummy_key + dummy_key_avail,
-                  sizeof(dummy_key) - dummy_key_avail);
+#ifdef CONFIG_GETRANDOM
+       res = getrandom(dummy_key + dummy_key_avail,
+                       sizeof(dummy_key) - dummy_key_avail, GRND_NONBLOCK);
        if (res < 0) {
-               wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
-                          "%s", strerror(errno));
-               res = 0;
+               if (errno == ENOSYS) {
+                       wpa_printf(MSG_DEBUG,
+                                  "random: getrandom() not supported, falling back to /dev/random");
+               } else {
+                       wpa_printf(MSG_INFO,
+                                  "random: no data from getrandom(): %s",
+                                  strerror(errno));
+                       res = 0;
+               }
+       }
+#else /* CONFIG_GETRANDOM */
+       res = -1;
+#endif /* CONFIG_GETRANDOM */
+       if (res < 0) {
+               fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+               if (fd < 0) {
+                       wpa_printf(MSG_ERROR,
+                                  "random: Cannot open /dev/random: %s",
+                                  strerror(errno));
+                       return -1;
+               }
+
+               res = read(fd, dummy_key + dummy_key_avail,
+                          sizeof(dummy_key) - dummy_key_avail);
+               if (res < 0) {
+                       wpa_printf(MSG_ERROR,
+                                  "random: Cannot read from /dev/random: %s",
+                                  strerror(errno));
+                       res = 0;
+               }
+               close(fd);
        }
-       wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from "
-                  "/dev/random", (unsigned) res,
+
+       wpa_printf(MSG_DEBUG, "random: Got %u/%u random bytes", (unsigned) res,
                   (unsigned) (sizeof(dummy_key) - dummy_key_avail));
        dummy_key_avail += res;
-       close(fd);
 
        if (dummy_key_avail == sizeof(dummy_key)) {
                if (own_pool_ready < MIN_READY_MARK)
@@ -261,7 +286,7 @@ int random_pool_ready(void)
        }
 
        wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
-                  "random data available from /dev/random",
+                  "random data available",
                   (unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
 
        if (own_pool_ready >= MIN_READY_MARK ||
@@ -413,6 +438,19 @@ void random_init(const char *entropy_file)
        if (random_fd >= 0)
                return;
 
+#ifdef CONFIG_GETRANDOM
+       {
+               u8 dummy;
+
+               if (getrandom(&dummy, 0, GRND_NONBLOCK) == 0 ||
+                   errno != ENOSYS) {
+                       wpa_printf(MSG_DEBUG,
+                                  "random: getrandom() support available");
+                       return;
+               }
+       }
+#endif /* CONFIG_GETRANDOM */
+
        random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
        if (random_fd < 0) {
                wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
index 958ea97c2030e235dc89feb09a923d928ed1008d..e55e062872cac9df8d8832876d5ffe83abb7a85e 100644 (file)
@@ -1532,6 +1532,9 @@ endif
 ifdef CONFIG_NO_RANDOM_POOL
 CFLAGS += -DCONFIG_NO_RANDOM_POOL
 else
+ifdef CONFIG_GETRANDOM
+CFLAGS += -DCONFIG_GETRANDOM
+endif
 OBJS += ../src/crypto/random.o
 endif
 
index da0b3f126069abac19824346831ee9b334d1ead0..0a082529e53635a17a6b51fbfcfa12b3269d8cf8 100644 (file)
@@ -461,6 +461,11 @@ CONFIG_BACKEND=file
 # that meet the requirements described above.
 #CONFIG_NO_RANDOM_POOL=y
 
+# Should we attempt to use the getrandom(2) call that provides more reliable
+# yet secure randomness source than /dev/random on Linux 3.17 and newer.
+# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
+#CONFIG_GETRANDOM=y
+
 # IEEE 802.11n (High Throughput) support (mainly for AP mode)
 #CONFIG_IEEE80211N=y