[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