From 27516979c14459d5519700b47765c8fd684d29cc 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 040aa117d..ae3d2d5b6 100644 --- a/library/entropy_poll.c +++ b/library/entropy_poll.c @@ -99,6 +99,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 ) { @@ -108,47 +109,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__ */ @@ -159,22 +121,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 5e0924cb52965169eadc73410061454610338026 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 513f24f3a..a7e41100b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,9 @@ Bugfix invalidated keys of a lifetime of less than a 1s. Fixes #1968. * Fix failure in hmac_drbg in the benchmark sample application, when MBEDTLS_THREADING_C is defined. Found by TrinityTonic, #1095 + * 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 * Add tests for session resumption in DTLS. From 9772da8792a75881d935db6eb9e073fb112d5888 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 ae3d2d5b6..4556f88a5 100644 --- a/library/entropy_poll.c +++ b/library/entropy_poll.c @@ -135,7 +135,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;