From 061b11de60415e228f33599270d66aafe4b88d72 Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Thu, 8 Sep 2011 10:53:12 +0200
Subject: [PATCH 04/17] 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(-)

diff --git a/random/ChangeLog b/random/ChangeLog
index 7784d44..b7a0d5a 100644
--- a/random/ChangeLog
+++ b/random/ChangeLog
@@ -1,3 +1,8 @@
+2011-09-08  Werner Koch  <wk@g10code.com>
+
+	* 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  <wk@g10code.com>
 
 	* rndw32.c (registry_poll): Disable performace fata gathering if
diff --git a/random/rndlinux.c b/random/rndlinux.c
index 5b84a19..b304cc9 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 cc5eb14..1b810d7 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;
 
-- 
1.7.10.4

