[OpenWrt-Devel] [PATCH] openssl: Fix longer booting times by unblocking getrandom
Etienne Champetier
champetier.etienne at gmail.com
Fri Mar 15 09:46:09 EDT 2019
Hi All,
Le ven. 15 mars 2019 à 09:29, Petr Štetiar <ynezz at true.cz> a écrit :
>
> While testing simple firmware image for x86/64 in QEMU I've discovered
> some weird behavior today. This image contains simple package with
> simple init script to bootstrap the device UCI configuration from
> network server. This init script uses uclient-fetch and libustream-openssl.
>
> This image was booting fine until today, usually finished booting under
> 10s, but today it was booting much slowly, boot times were in range from
> 60s to a few minutes. I was also unable to power off the QEMU with
> poweroff command.
>
> I've found out, that it's all happening because of uclient-fetch being
> blocked in getrandom syscall, leading for example to following:
>
> root at OpenWrt:~# time uclient-fetch
> ^CCommand terminated by signal 2
> real 8m 31.08s
>
> The problem passes away after `random: crng init done` hits
> the system log, but this step can take ages in some cases (usually when there
> are more processes calling getrandom in parallel), but I couldn't get it
> under 60s on my QEMU machine. I've similar weird reports from users on
> MIPS devices as well.
>
> [ 13.786576] random: fast init done
> ...
> [ 653.153740] random: crng init done
>
> I've bisected the problem down to the following commit (reverting it
> fixed the problem):
>
> # first bad commit: [d872d00b2f] openssl: update to version 1.1.1a
>
> So this patch tries to fix this issue by making getrandom syscall
> nonblocking, and also removes possible usage of getentropy libc call,
> which in case of musl libc results again in use of getrandom syscall in
> blocking mode.
>
> I've also added new config option just in case someone would prefer to
> have probably safer but much slower boot times on some devices.
Just a side note, on first boot we save a random seed using getrandom()
https://github.com/openwrt/openwrt/blob/master/package/base-files/files/etc/init.d/urandom_seed
https://github.com/openwrt/openwrt/blob/master/package/base-files/files/sbin/urandom_seed
And we restore it in preinit
https://github.com/openwrt/openwrt/blob/master/package/base-files/files/lib/preinit/81_urandom_seed
So even if kernel PRNG is considered not initialized, in reality it
is, so starting from second boot we are ~ok
I'm not sure if we block on getrandom to generate ssh keys (and any
other keys) on first boot though
Regards
Etienne
>
> Fixes: d872d00b2f ("openssl: update to version 1.1.1a")
> Reviewed-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
> Signed-off-by: Petr Štetiar <ynezz at true.cz>
> ---
> package/libs/openssl/Config.in | 12 ++++++
> package/libs/openssl/Makefile | 7 +++-
> .../openssl/patches/150-unblock-getrandom.patch | 45 ++++++++++++++++++++++
> 3 files changed, 63 insertions(+), 1 deletion(-)
> create mode 100644 package/libs/openssl/patches/150-unblock-getrandom.patch
>
> diff --git a/package/libs/openssl/Config.in b/package/libs/openssl/Config.in
> index ecb9eea..0809afa 100644
> --- a/package/libs/openssl/Config.in
> +++ b/package/libs/openssl/Config.in
> @@ -70,6 +70,18 @@ config OPENSSL_WITH_ERROR_MESSAGES
> This option aids debugging, but increases package size and
> memory usage.
>
> +config OPENSSL_BLOCKING_GETRANDOM
> + bool
> + prompt "Enable back getrandom in blocking mode"
> + help
> + Enable back the default (upstream) blocking behavior. By default, when
> + reading from the random source, getrandom() blocks if no random bytes are
> + available, and when reading from the urandom source, it blocks if the entropy
> + pool has not yet been initialized.
> +
> + Please note, that turning this option on may affect the boot time, which can
> + in some cases take minutes.
> +
> comment "Protocol Support"
>
> config OPENSSL_WITH_TLS13
> diff --git a/package/libs/openssl/Makefile b/package/libs/openssl/Makefile
> index 56e95af..6e7a603 100644
> --- a/package/libs/openssl/Makefile
> +++ b/package/libs/openssl/Makefile
> @@ -11,7 +11,7 @@ PKG_NAME:=openssl
> PKG_BASE:=1.1.1
> PKG_BUGFIX:=b
> PKG_VERSION:=$(PKG_BASE)$(PKG_BUGFIX)
> -PKG_RELEASE:=3
> +PKG_RELEASE:=4
> PKG_USE_MIPS16:=0
> ENGINES_DIR=engines-1.1
>
> @@ -30,6 +30,7 @@ PKG_LICENSE:=OpenSSL
> PKG_LICENSE_FILES:=LICENSE
> PKG_CPE_ID:=cpe:/a:openssl:openssl
> PKG_CONFIG_DEPENDS:= \
> + CONFIG_OPENSSL_BLOCKING_GETRANDOM \
> CONFIG_OPENSSL_ENGINE \
> CONFIG_OPENSSL_ENGINE_BUILTIN \
> CONFIG_OPENSSL_ENGINE_BUILTIN_AFALG \
> @@ -327,6 +328,10 @@ ifdef CONFIG_i386
> endif
> endif
>
> +ifdef CONFIG_OPENSSL_BLOCKING_GETRANDOM
> + OPENSSL_OPTIONS += -DOPENSSL_BLOCKING_GETRANDOM
> +endif
> +
> OPENSSL_TARGET:=linux-$(call qstrip,$(CONFIG_ARCH))-openwrt
>
> STAMP_CONFIGURED := $(STAMP_CONFIGURED)_$(shell echo $(OPENSSL_OPTIONS) | mkhash md5)
> diff --git a/package/libs/openssl/patches/150-unblock-getrandom.patch b/package/libs/openssl/patches/150-unblock-getrandom.patch
> new file mode 100644
> index 0000000..f74abaa
> --- /dev/null
> +++ b/package/libs/openssl/patches/150-unblock-getrandom.patch
> @@ -0,0 +1,45 @@
> +--- a/crypto/rand/rand_unix.c
> ++++ b/crypto/rand/rand_unix.c
> +@@ -20,6 +20,7 @@
> + #include "internal/dso.h"
> + #if defined(__linux)
> + # include <sys/syscall.h>
> ++# include <sys/random.h>
> + #endif
> + #if defined(__FreeBSD__)
> + # include <sys/types.h>
> +@@ -292,7 +293,8 @@ static ssize_t syscall_random(void *buf,
> + */
> +
> + /*
> +- * Do runtime detection to find getentropy().
> ++ * Do runtime detection to find getentropy(). Please note, that at least
> ++ * on musl libc (version 1.2.21) getentropy() uses getrandom() in blocking mode.
> + *
> + * Known OSs that should support this:
> + * - Darwin since 16 (OSX 10.12, IOS 10.0).
> +@@ -301,6 +303,7 @@ static ssize_t syscall_random(void *buf,
> + * - Linux since 3.17 with glibc 2.25
> + * - FreeBSD since 12.0 (1200061)
> + */
> ++# if defined(OPENSSL_BLOCKING_GETRANDOM)
> + # if defined(__GNUC__) && __GNUC__>=2 && defined(__ELF__) && !defined(__hpux)
> + extern int getentropy(void *buffer, size_t length) __attribute__((weak));
> +
> +@@ -322,10 +325,15 @@ static ssize_t syscall_random(void *buf,
> + if (p_getentropy.p != NULL)
> + return p_getentropy.f(buf, buflen) == 0 ? (ssize_t)buflen : -1;
> + # endif
> ++# endif /* defined(OPENSSL_BLOCKING_GETRANDOM) */
> +
> + /* Linux supports this since version 3.17 */
> + # if defined(__linux) && defined(SYS_getrandom)
> +- return syscall(SYS_getrandom, buf, buflen, 0);
> ++ unsigned int flags = 0;
> ++# if !defined(OPENSSL_BLOCKING_GETRANDOM)
> ++ flags = GRND_NONBLOCK;
> ++# endif
> ++ return syscall(SYS_getrandom, buf, buflen, flags);
> + # elif (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND)
> + return sysctl_random(buf, buflen);
> + # else
> --
> 1.9.1
>
>
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel at lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel
More information about the openwrt-devel
mailing list