Fix a problem with select and high fds.
authorWerner Koch <wk@gnupg.org>
Thu, 8 Sep 2011 08:53:12 +0000 (10:53 +0200)
committerWerner Koch <wk@gnupg.org>
Thu, 8 Sep 2011 08:53:12 +0000 (10:53 +0200)
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
random/rndlinux.c
random/rndunix.c

index 7784d44..b7a0d5a 100644 (file)
@@ -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
index 5b84a19..b304cc9 100644 (file)
@@ -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
index cc5eb14..1b810d7 100644 (file)
@@ -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;