From 89a7cdd690b48a0c56380cf4609442ed13527f44 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 18 Sep 2017 14:58:07 +0200 Subject: [PATCH] crypto: Add option to use getrandom() 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 --- hostapd/Makefile | 3 ++ hostapd/defconfig | 5 +++ src/crypto/random.c | 74 ++++++++++++++++++++++++++++++---------- wpa_supplicant/Makefile | 3 ++ wpa_supplicant/defconfig | 5 +++ 5 files changed, 72 insertions(+), 18 deletions(-) diff --git a/hostapd/Makefile b/hostapd/Makefile index 5fa174b96..dd3816e0d 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -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 diff --git a/hostapd/defconfig b/hostapd/defconfig index 58e525dfa..aeac13a67 100644 --- a/hostapd/defconfig +++ b/hostapd/defconfig @@ -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 diff --git a/src/crypto/random.c b/src/crypto/random.c index c278d9cb9..1cabf3f4b 100644 --- a/src/crypto/random.c +++ b/src/crypto/random.c @@ -25,6 +25,9 @@ #include "utils/includes.h" #ifdef __linux__ #include +#ifdef CONFIG_GETRANDOM +#include +#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; + +#ifdef CONFIG_GETRANDOM + res = getrandom(dummy_key + dummy_key_avail, + sizeof(dummy_key) - dummy_key_avail, GRND_NONBLOCK); + if (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); } - 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; - } - 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", diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 958ea97c2..e55e06287 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -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 diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index da0b3f126..0a082529e 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -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