LCOV - code coverage report
Current view: top level - random - rndlinux.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 50 82 61.0 %
Date: 2015-11-05 17:08:00 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* rndlinux.c  -  raw random number for OSes with /dev/random
       2             :  * Copyright (C) 1998, 2001, 2002, 2003, 2007,
       3             :  *               2009  Free Software Foundation, Inc.
       4             :  *
       5             :  * This file is part of Libgcrypt.
       6             :  *
       7             :  * Libgcrypt is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU Lesser General Public License as
       9             :  * published by the Free Software Foundation; either version 2.1 of
      10             :  * the License, or (at your option) any later version.
      11             :  *
      12             :  * Libgcrypt is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : 
      22             : #include <config.h>
      23             : #include <stdio.h>
      24             : #include <stdlib.h>
      25             : #include <errno.h>
      26             : #include <sys/time.h>
      27             : #include <sys/types.h>
      28             : #include <sys/stat.h>
      29             : #ifdef HAVE_GETTIMEOFDAY
      30             : # include <sys/times.h>
      31             : #endif
      32             : #include <string.h>
      33             : #include <unistd.h>
      34             : #include <fcntl.h>
      35             : #include "types.h"
      36             : #include "g10lib.h"
      37             : #include "rand-internal.h"
      38             : 
      39             : static int open_device (const char *name, int retry);
      40             : 
      41             : 
      42             : static int
      43          18 : set_cloexec_flag (int fd)
      44             : {
      45             :   int oldflags;
      46             : 
      47          18 :   oldflags= fcntl (fd, F_GETFD, 0);
      48          18 :   if (oldflags < 0)
      49           0 :     return oldflags;
      50          18 :   oldflags |= FD_CLOEXEC;
      51          18 :   return fcntl (fd, F_SETFD, oldflags);
      52             : }
      53             : 
      54             : 
      55             : 
      56             : /*
      57             :  * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it
      58             :  * exists)).  If RETRY is true, the function does not terminate with
      59             :  * a fatal error but retries until it is able to reopen the device.
      60             :  */
      61             : static int
      62          18 : open_device (const char *name, int retry)
      63             : {
      64             :   int fd;
      65             : 
      66          18 :   if (retry)
      67           0 :     _gcry_random_progress ("open_dev_random", 'X', 1, 0);
      68             :  again:
      69          18 :   fd = open (name, O_RDONLY);
      70          18 :   if (fd == -1 && retry)
      71             :     {
      72             :       struct timeval tv;
      73             : 
      74           0 :       tv.tv_sec = 5;
      75           0 :       tv.tv_usec = 0;
      76           0 :       _gcry_random_progress ("wait_dev_random", 'X', 0, (int)tv.tv_sec);
      77           0 :       select (0, NULL, NULL, NULL, &tv);
      78           0 :       goto again;
      79             :     }
      80          18 :   if (fd == -1)
      81           0 :     log_fatal ("can't open %s: %s\n", name, strerror(errno) );
      82             : 
      83          18 :   if (set_cloexec_flag (fd))
      84           0 :     log_error ("error setting FD_CLOEXEC on fd %d: %s\n",
      85           0 :                fd, strerror (errno));
      86             : 
      87             :   /* We used to do the following check, however it turned out that this
      88             :      is not portable since more OSes provide a random device which is
      89             :      sometimes implemented as another device type.
      90             : 
      91             :      struct stat sb;
      92             : 
      93             :      if( fstat( fd, &sb ) )
      94             :         log_fatal("stat() off %s failed: %s\n", name, strerror(errno) );
      95             :      if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) )
      96             :         log_fatal("invalid random device!\n" );
      97             :   */
      98          18 :   return fd;
      99             : }
     100             : 
     101             : 
     102             : /* Note that the caller needs to make sure that this function is only
     103             :    called by one thread at a time.  The function returns 0 on success
     104             :    or true on failure (in which case the caller will signal a fatal
     105             :    error).  */
     106             : int
     107         430 : _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
     108             :                                           enum random_origins),
     109             :                               enum random_origins origin,
     110             :                               size_t length, int level )
     111             : {
     112             :   static int fd_urandom = -1;
     113             :   static int fd_random = -1;
     114             :   static unsigned char ever_opened;
     115             :   int fd;
     116             :   int n;
     117             :   byte buffer[768];
     118             :   size_t n_hw;
     119         430 :   size_t want = length;
     120         430 :   size_t last_so_far = 0;
     121         430 :   int any_need_entropy = 0;
     122             :   int delay;
     123             : 
     124         430 :   if (!add)
     125             :     {
     126             :       /* Special mode to close the descriptors.  */
     127           0 :       if (fd_random != -1)
     128             :         {
     129           0 :           close (fd_random);
     130           0 :           fd_random = -1;
     131             :         }
     132           0 :       if (fd_urandom != -1)
     133             :         {
     134           0 :           close (fd_urandom);
     135           0 :           fd_urandom = -1;
     136             :         }
     137           0 :       return 0;
     138             :     }
     139             : 
     140             : 
     141             :   /* First read from a hardware source.  However let it account only
     142             :      for up to 50% of the requested bytes.  */
     143         430 :   n_hw = _gcry_rndhw_poll_slow (add, origin);
     144         430 :   if (n_hw > length/2)
     145           0 :     n_hw = length/2;
     146         430 :   if (length > 1)
     147         430 :     length -= n_hw;
     148             : 
     149             :   /* Open the requested device.  The first time a device is to be
     150             :      opened we fail with a fatal error if the device does not exists.
     151             :      In case the device has ever been closed, further open requests
     152             :      will however retry indefinitely.  The rationale for this behaviour is
     153             :      that we always require the device to be existent but want a more
     154             :      graceful behaviour if the rarely needed close operation has been
     155             :      used and the device needs to be re-opened later. */
     156         430 :   if (level >= 2)
     157             :     {
     158           2 :       if (fd_random == -1)
     159             :         {
     160           1 :           fd_random = open_device (NAME_OF_DEV_RANDOM, (ever_opened & 1));
     161           1 :           ever_opened |= 1;
     162             :         }
     163           2 :       fd = fd_random;
     164             :     }
     165             :   else
     166             :     {
     167         428 :       if (fd_urandom == -1)
     168             :         {
     169          17 :           fd_urandom = open_device (NAME_OF_DEV_URANDOM, (ever_opened & 2));
     170          17 :           ever_opened |= 2;
     171             :         }
     172         428 :       fd = fd_urandom;
     173             :     }
     174             : 
     175             :   /* Enter the read loop.  */
     176         430 :   delay = 0;  /* Start with 0 seconds so that we do no block on the
     177             :                  first iteration and in turn call the progress function
     178             :                  before blocking.  To give the OS a better chance to
     179             :                  return with something we will actually use 100ms. */
     180        1290 :   while (length)
     181             :     {
     182             :       fd_set rfds;
     183             :       struct timeval tv;
     184             :       int rc;
     185             : 
     186             :       /* If we collected some bytes update the progress indicator.  We
     187             :          do this always and not just if the select timed out because
     188             :          often just a few bytes are gathered within the timeout
     189             :          period.  */
     190         430 :       if (any_need_entropy || last_so_far != (want - length) )
     191             :         {
     192           0 :           last_so_far = want - length;
     193           0 :           _gcry_random_progress ("need_entropy", 'X',
     194             :                                  (int)last_so_far, (int)want);
     195           0 :           any_need_entropy = 1;
     196             :         }
     197             : 
     198             :       /* If the system has no limit on the number of file descriptors
     199             :          and we encounter an fd which is larger than the fd_set size,
     200             :          we don't use the select at all.  The select code is only used
     201             :          to emit progress messages.  A better solution would be to
     202             :          fall back to poll() if available.  */
     203             : #ifdef FD_SETSIZE
     204         430 :       if (fd < FD_SETSIZE)
     205             : #endif
     206             :         {
     207         430 :           FD_ZERO(&rfds);
     208         430 :           FD_SET(fd, &rfds);
     209         430 :           tv.tv_sec = delay;
     210         430 :           tv.tv_usec = delay? 0 : 100000;
     211         430 :           if ( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) )
     212             :             {
     213           0 :               any_need_entropy = 1;
     214           0 :               delay = 3; /* Use 3 seconds henceforth.  */
     215           0 :               continue;
     216             :             }
     217         430 :           else if( rc == -1 )
     218             :             {
     219           0 :               log_error ("select() error: %s\n", strerror(errno));
     220           0 :               if (!delay)
     221           0 :                 delay = 1; /* Use 1 second if we encounter an error before
     222             :                               we have ever blocked.  */
     223           0 :               continue;
     224             :             }
     225             :         }
     226             : 
     227             :       do
     228             :         {
     229             :           size_t nbytes;
     230             : 
     231         430 :           nbytes = length < sizeof(buffer)? length : sizeof(buffer);
     232         430 :           n = read (fd, buffer, nbytes);
     233         430 :           if (n >= 0 && n > nbytes)
     234             :             {
     235           0 :               log_error("bogus read from random device (n=%d)\n", n );
     236           0 :               n = nbytes;
     237             :             }
     238             :         }
     239         430 :       while (n == -1 && errno == EINTR);
     240         430 :       if  (n == -1)
     241           0 :         log_fatal("read error on random device: %s\n", strerror(errno));
     242         430 :       (*add)(buffer, n, origin);
     243         430 :       length -= n;
     244             :     }
     245         430 :   wipememory (buffer, sizeof buffer);
     246             : 
     247         430 :   if (any_need_entropy)
     248           0 :     _gcry_random_progress ("need_entropy", 'X', (int)want, (int)want);
     249             : 
     250         430 :   return 0; /* success */
     251             : }

Generated by: LCOV version 1.11