From 9487099071af4478d2882e633a0ade805801d6fa Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 8 Sep 2011 10:53:12 +0200 Subject: Fix a problem with select and high fds. If on systems where the maximum number of fds may be dynamically configured to a value of FD_MAXSIZE or higher and the RNG is first used after more than FD_SETSIZE-1 descriptors are in use, we disable the progress messages from the RNG. A better solution would be too use poll but that requires more tests. The same problem exists in rndunix.c - however this rng is only used on old Unices and I assume that they don't feature dynamically configured maximum fd sizes. --- random/ChangeLog | 5 +++++ random/rndlinux.c | 50 ++++++++++++++++++++++++++++++-------------------- random/rndunix.c | 3 ++- 3 files changed, 37 insertions(+), 21 deletions(-) (limited to 'random') diff --git a/random/ChangeLog b/random/ChangeLog index 7784d44e..b7a0d5a1 100644 --- a/random/ChangeLog +++ b/random/ChangeLog @@ -1,3 +1,8 @@ +2011-09-08 Werner Koch + + * rndlinux.c (_gcry_rndlinux_gather_random): Don't use select if + the fd number is too high. Reported by Jakub Bogusz. + 2010-10-18 Werner Koch * rndw32.c (registry_poll): Disable performace fata gathering if diff --git a/random/rndlinux.c b/random/rndlinux.c index 5b84a19c..b304cc9e 100644 --- a/random/rndlinux.c +++ b/random/rndlinux.c @@ -134,29 +134,39 @@ _gcry_rndlinux_gather_random (void (*add)(const void*, size_t, struct timeval tv; int rc; - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - tv.tv_sec = delay; - tv.tv_usec = delay? 0 : 100000; - if ( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) + /* If the system has no limit on the number of file descriptors + and we encounter an fd which is larger than the fd_set size, + we don't use the select at all. The select code is only used + to emit progress messages. A better solution would be to + fall back to poll() if available. */ +#ifdef FD_SETSIZE + if (fd < FD_SETSIZE) +#endif { - if (!any_need_entropy || last_so_far != (want - length) ) + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = delay; + tv.tv_usec = delay? 0 : 100000; + if ( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) { - last_so_far = want - length; - _gcry_random_progress ("need_entropy", 'X', - (int)last_so_far, (int)want); - any_need_entropy = 1; - } - delay = 3; /* Use 3 seconds henceforth. */ - continue; - } - else if( rc == -1 ) - { - log_error ("select() error: %s\n", strerror(errno)); - if (!delay) - delay = 1; /* Use 1 second if we encounter an error before + if (!any_need_entropy || last_so_far != (want - length) ) + { + last_so_far = want - length; + _gcry_random_progress ("need_entropy", 'X', + (int)last_so_far, (int)want); + any_need_entropy = 1; + } + delay = 3; /* Use 3 seconds henceforth. */ + continue; + } + else if( rc == -1 ) + { + log_error ("select() error: %s\n", strerror(errno)); + if (!delay) + delay = 1; /* Use 1 second if we encounter an error before we have ever blocked. */ - continue; + continue; + } } do diff --git a/random/rndunix.c b/random/rndunix.c index cc5eb145..1b810d72 100644 --- a/random/rndunix.c +++ b/random/rndunix.c @@ -551,7 +551,8 @@ slow_poll(FILE *dbgfp, int dbgall, size_t *nbytes ) #else #error O_NONBLOCK is missing #endif - + /* FIXME: We need to make sure that the fd is less than + FD_SETSIZE. */ FD_SET(dataSources[i].pipeFD, &fds); dataSources[i].length = 0; -- cgit v1.2.1