From: draht@suse.com Subject: /etc/gcrypt/rngseed symlink logic error in evaluation of routine to open /dev/{u,}random or /etc/gcrypt/rngseed (open_device()) causes abort() in cases where do_randomize(nbytes, level) is called with level == 1 (GCRY_STRONG_RANDOM). References: bnc#724841 https://bugzilla.novell.com/show_bug.cgi?id=724841 --- random/random-csprng.c | 2 +- random/random-fips.c | 10 +++++----- random/rndlinux.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 48 insertions(+), 12 deletions(-) Index: libgcrypt-1.5.2/random/random-csprng.c =================================================================== --- libgcrypt-1.5.2.orig/random/random-csprng.c +++ libgcrypt-1.5.2/random/random-csprng.c @@ -827,7 +827,7 @@ read_seed_file (void) * entropy drivers, however the rndlinux driver will use * /dev/urandom and return some stuff - Do not read too much as we * want to be friendly to the scare system entropy resource. */ - read_random_source ( RANDOM_ORIGIN_INIT, 16, GCRY_WEAK_RANDOM ); + read_random_source ( RANDOM_ORIGIN_INIT, 16, -1 ); allow_seed_file_update = 1; return 1; Index: libgcrypt-1.5.2/random/random-fips.c =================================================================== --- libgcrypt-1.5.2.orig/random/random-fips.c +++ libgcrypt-1.5.2/random/random-fips.c @@ -27,10 +27,10 @@ There are 3 random context which map to the different levels of random quality: - Generator Seed and Key Kernel entropy (init/reseed) - ------------------------------------------------------------ - GCRY_VERY_STRONG_RANDOM /dev/random 256/128 bits - GCRY_STRONG_RANDOM /dev/random 256/128 bits + Generator Seed and Key Kernel entropy (init/reseed) + --------------------------------------------------------------------------------------- + GCRY_VERY_STRONG_RANDOM /etc/gcrypt/rngseed+/dev/urandom 256/128 bits + GCRY_STRONG_RANDOM /etc/gcrypt/rngseed+/dev/urandom 256/128 bits gcry_create_nonce GCRY_STRONG_RANDOM n/a All random generators return their data in 128 bit blocks. If the @@ -562,7 +562,7 @@ get_entropy (size_t nbytes) #if USE_RNDLINUX rc = _gcry_rndlinux_gather_random (entropy_collect_cb, 0, X931_AES_KEYLEN, - GCRY_VERY_STRONG_RANDOM); + -1); #elif USE_RNDW32 do { Index: libgcrypt-1.5.2/random/rndlinux.c =================================================================== --- libgcrypt-1.5.2.orig/random/rndlinux.c +++ libgcrypt-1.5.2/random/rndlinux.c @@ -36,7 +36,8 @@ #include "g10lib.h" #include "rand-internal.h" -static int open_device ( const char *name ); +static int open_device ( const char *name, int fatal ); +#define NAME_OF_CFG_RNGSEED "/etc/gcrypt/rngseed" static int @@ -57,13 +58,17 @@ set_cloexec_flag (int fd) * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists)). */ static int -open_device ( const char *name ) +open_device ( const char *name, int fatal) { int fd; fd = open ( name, O_RDONLY ); if ( fd == -1 ) - log_fatal ("can't open %s: %s\n", name, strerror(errno) ); + { + if (fatal) + log_fatal ("can't open %s: %s\n", name, strerror(errno) ); + return fd; + } if (set_cloexec_flag (fd)) log_error ("error setting FD_CLOEXEC on fd %d: %s\n", @@ -92,10 +97,12 @@ _gcry_rndlinux_gather_random (void (*add { static int fd_urandom = -1; static int fd_random = -1; + static int fd_configured = -1; int fd; int n; byte buffer[768]; size_t n_hw; + size_t orig_length = length; size_t want = length; size_t last_so_far = 0; int any_need_entropy = 0; @@ -110,16 +117,42 @@ _gcry_rndlinux_gather_random (void (*add length -= n_hw; /* Open the requested device. */ + + /* Clarification: path how "level == -1" comes about: + gcry_random_bytes( ... , GCRY_STRONG_RANDOM) (public) -> + do_randomize(buffer, nbytes, level) -> + _gcry_rngcsprng_randomize(buffer, length, level) -> + read_pool (p, n, level) -> + read_seed_file(), + random_poll() -> + read_random_source(..., ..., GCRY_STRONG_RANDOM), + read_random_source(... , ..., , -1 ) (note: -1) -> + slow_gather_fnc(..., ..., ..., level) + function pointer set by getfnc_gather_random() to + _gcry_rndlinux_gather_random() , which is here. + */ + + + if (level == -1) + { + if (fd_configured == -1) + fd_configured = open_device ( NAME_OF_CFG_RNGSEED, 0 ); + fd = fd_configured; + if (fd == -1) + level = 1; + } + + if (level >= 2) { if( fd_random == -1 ) - fd_random = open_device ( NAME_OF_DEV_RANDOM ); + fd_random = open_device ( NAME_OF_DEV_RANDOM, 1 ); fd = fd_random; } - else + else if (level != -1) { if( fd_urandom == -1 ) - fd_urandom = open_device ( NAME_OF_DEV_URANDOM ); + fd_urandom = open_device ( NAME_OF_DEV_URANDOM, 1 ); fd = fd_urandom; } @@ -187,6 +220,9 @@ _gcry_rndlinux_gather_random (void (*add } memset(buffer, 0, sizeof(buffer) ); + if (level == -1) + _gcry_rndlinux_gather_random(add, origin, orig_length, 1); + if (any_need_entropy) _gcry_random_progress ("need_entropy", 'X', (int)want, (int)want);