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.6.0/random/random-csprng.c =================================================================== --- libgcrypt-1.6.0.orig/random/random-csprng.c +++ libgcrypt-1.6.0/random/random-csprng.c @@ -832,7 +832,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.6.0/random/random-fips.c =================================================================== --- libgcrypt-1.6.0.orig/random/random-fips.c +++ libgcrypt-1.6.0/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.6.0/random/rndlinux.c =================================================================== --- libgcrypt-1.6.0.orig/random/rndlinux.c +++ libgcrypt-1.6.0/random/rndlinux.c @@ -36,7 +36,8 @@ #include "g10lib.h" #include "rand-internal.h" -static int open_device (const char *name, int retry); +static int open_device (const char *name, int retry, int fatal); +#define NAME_OF_CFG_RNGSEED "/etc/gcrypt/rngseed" static int @@ -59,7 +60,7 @@ set_cloexec_flag (int fd) * a fatal error but retries until it is able to reopen the device. */ static int -open_device (const char *name, int retry) +open_device (const char *name, int retry, int fatal) { int fd; @@ -77,8 +78,11 @@ open_device (const char *name, int retry select (0, NULL, NULL, NULL, &tv); goto again; } - 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", @@ -111,11 +115,13 @@ _gcry_rndlinux_gather_random (void (*add { static int fd_urandom = -1; static int fd_random = -1; + static int fd_configured = -1; static unsigned char ever_opened; 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; @@ -153,20 +159,46 @@ _gcry_rndlinux_gather_random (void (*add that we always require the device to be existent but want a more graceful behaviour if the rarely needed close operation has been used and the device needs to be re-opened later. */ + + /* 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, 0); + fd = fd_configured; + if (fd == -1) + level = 1; + } + + if (level >= 2) { if (fd_random == -1) { - fd_random = open_device (NAME_OF_DEV_RANDOM, (ever_opened & 1)); + fd_random = open_device (NAME_OF_DEV_RANDOM, (ever_opened & 1), 1); ever_opened |= 1; } fd = fd_random; } - else + else if (level != -1) { if (fd_urandom == -1) { - fd_urandom = open_device (NAME_OF_DEV_URANDOM, (ever_opened & 2)); + fd_urandom = open_device (NAME_OF_DEV_URANDOM, (ever_opened & 2), 1); ever_opened |= 2; } fd = fd_urandom; @@ -242,6 +274,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);