From d97828e7afbc7c3bc5824083f79a2a6a73bc2420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 29 Apr 2015 14:03:28 +0200 Subject: [PATCH] Fix detection of getrandom() --- ChangeLog | 2 ++ library/entropy_poll.c | 66 ++++++++++++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index b0841ba6e..19382bc87 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,8 @@ Features errors on use of deprecated functions. Bugfix + * Fix detection of support for getrandom() on Linux (reported by syzzer) by + doing it at runtime (using uname) rather that compile time. * Fix handling of symlinks by "make install" (found by Gaƫl PORTAY). * Fix potential NULL pointer dereference (not trigerrable remotely) when ssl_write() is called before the handshake is finished (introduced in diff --git a/library/entropy_poll.c b/library/entropy_poll.c index 61eb3e78a..e0f9ae286 100644 --- a/library/entropy_poll.c +++ b/library/entropy_poll.c @@ -86,27 +86,46 @@ static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags ) { return( syscall( SYS_getrandom, buf, buflen, flags ) ); } -#endif /* SYS_getrandom */ -#endif /* __linux__ */ -#if defined(HAVE_GETRANDOM) - -#include - -int platform_entropy_poll( void *data, - unsigned char *output, size_t len, size_t *olen ) +#include +/* Check if version is at least 3.17.0 */ +static int check_version_3_17_plus( void ) { - int ret; - ((void) data); + int minor; + struct utsname un; + const char *ver; - if( ( ret = getrandom_wrapper( output, len, 0 ) ) < 0 ) - return( POLARSSL_ERR_ENTROPY_SOURCE_FAILED ); + /* 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 ); - *olen = ret; return( 0 ); } - -#else /* HAVE_GETRANDOM */ +static int has_getrandom = -1; +#endif /* SYS_getrandom */ +#endif /* __linux__ */ #include @@ -117,6 +136,22 @@ int platform_entropy_poll( void *data, size_t ret; ((void) data); +#if defined(HAVE_GETRANDOM) + if( has_getrandom == -1 ) + has_getrandom = ( check_version_3_17_plus() == 0 ); + + if( has_getrandom ) + { + int ret; + + if( ( ret = getrandom_wrapper( output, len, 0 ) ) < 0 ) + return( POLARSSL_ERR_ENTROPY_SOURCE_FAILED ); + + *olen = ret; + return( 0 ); + } +#endif /* HAVE_GETRANDOM */ + *olen = 0; file = fopen( "/dev/urandom", "rb" ); @@ -135,7 +170,6 @@ int platform_entropy_poll( void *data, return( 0 ); } -#endif /* HAVE_GETRANDOM */ #endif /* _WIN32 && !EFIX64 && !EFI32 */ #endif /* !POLARSSL_NO_PLATFORM_ENTROPY */