From 9a7fcd6a9760e50d7a175c3d242c2370c1714d74 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 18 Oct 2018 11:49:25 +0100 Subject: [PATCH 1/3] Entropy: Fall through to /dev/random if getrandom() syscall unknown This commit fixes issue #1212 related to platform-specific entropy polling in an syscall-emulated environment. Previously, the implementation of the entropy gathering function `mbedtls_platform_entropy_poll()` for linux machines used the following logic to determine how to obtain entropy from the kernel: 1. If the getrandom() system call identifier SYS_getrandom is present and the kernel version is 3.17 or higher, use syscall( SYS_getrandom, ... ) 2. Otherwise, fall back to reading from /dev/random. There are two issues with this: 1. Portability: When cross-compiling the code for a different architecture and running it through system call emulation in qemu, qemu reports the host kernel version through uname but, as of v.2.5.0, doesn't support emulating the getrandom() syscall. This leads to `mbedtls_platform_entropy_poll()` failing even though reading from /dev/random would have worked. 2. Style: Extracting the linux kernel version from the output of `uname` is slightly tedious. This commit fixes both by implementing the suggestion in #1212: - It removes the kernel-version detection through uname(). - Instead, it checks whether `syscall( SYS_getrandom, ... )` fails with errno set to ENOSYS indicating an unknown system call. If so, it falls through to trying to read from /dev/random. Fixes #1212. --- library/entropy_poll.c | 57 +++++++----------------------------------- 1 file changed, 9 insertions(+), 48 deletions(-) diff --git a/library/entropy_poll.c b/library/entropy_poll.c index 096c02398..b123ac25a 100644 --- a/library/entropy_poll.c +++ b/library/entropy_poll.c @@ -81,6 +81,7 @@ int mbedtls_platform_entropy_poll( void *data, unsigned char *output, size_t len #include #if defined(SYS_getrandom) #define HAVE_GETRANDOM +#include static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags ) { @@ -90,47 +91,8 @@ static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags ) memset( buf, 0, buflen ); #endif #endif - return( syscall( SYS_getrandom, buf, buflen, flags ) ); } - -#include -/* Check if version is at least 3.17.0 */ -static int check_version_3_17_plus( void ) -{ - int minor; - struct utsname un; - const char *ver; - - /* Get version information */ - uname(&un); - ver = un.release; - - /* Check major version; assume a single digit */ - if( ver[0] < '3' || ver[0] > '9' || ver [1] != '.' ) - return( -1 ); - - if( ver[0] - '0' > 3 ) - return( 0 ); - - /* Ok, so now we know major == 3, check minor. - * Assume 1 or 2 digits. */ - if( ver[2] < '0' || ver[2] > '9' ) - return( -1 ); - - minor = ver[2] - '0'; - - if( ver[3] >= '0' && ver[3] <= '9' ) - minor = 10 * minor + ver[3] - '0'; - else if( ver [3] != '.' ) - return( -1 ); - - if( minor < 17 ) - return( -1 ); - - return( 0 ); -} -static int has_getrandom = -1; #endif /* SYS_getrandom */ #endif /* __linux__ */ @@ -141,22 +103,21 @@ int mbedtls_platform_entropy_poll( void *data, { FILE *file; size_t read_len; + int ret; ((void) data); #if defined(HAVE_GETRANDOM) - if( has_getrandom == -1 ) - has_getrandom = ( check_version_3_17_plus() == 0 ); - - if( has_getrandom ) + ret = getrandom_wrapper( output, len, 0 ); + if( ret >= 0 ) { - int ret; - - if( ( ret = getrandom_wrapper( output, len, 0 ) ) < 0 ) - return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); - *olen = ret; return( 0 ); } + else if( errno != ENOSYS ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + /* Fall through if the system call isn't known. */ +#else + ((void) ret; #endif /* HAVE_GETRANDOM */ *olen = 0; From 42085fb92a7a6a83bd532da902b30f6e33c19fd2 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 18 Oct 2018 12:11:54 +0100 Subject: [PATCH 2/3] Adapt ChangeLog --- ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 7ef0342bc..14b73d894 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,9 @@ Bugfix program programs/x509/cert_write. Fixes #1422. * Ignore iv in mbedtls_cipher_set_iv() when the cipher mode is MBEDTLS_MODE_ECB Fix for #1091 raised by ezdevelop + * Fix runtime error in `mbedtls_platform_entropy_poll()` when run + through qemu user emulation. Reported and fix suggested by randombit + in #1212. Fixes #1212. Changes * "make apidoc" now generates the documentation for the current From 766ca32d2f9c9e0fcdefa8c92efa67c6e370b8c6 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 5 Nov 2018 11:43:07 +0000 Subject: [PATCH 3/3] Add missing bracket Wasn't spotted earlier because it's guarded by `! HAVE_GETRANDOM`. --- library/entropy_poll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/entropy_poll.c b/library/entropy_poll.c index b123ac25a..e73c71978 100644 --- a/library/entropy_poll.c +++ b/library/entropy_poll.c @@ -117,7 +117,7 @@ int mbedtls_platform_entropy_poll( void *data, return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); /* Fall through if the system call isn't known. */ #else - ((void) ret; + ((void) ret); #endif /* HAVE_GETRANDOM */ *olen = 0;