LCOV - code coverage report
Current view: top level - random - rndlinux.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 67 105 63.8 %
Date: 2017-03-02 16:44:37 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             : #if defined(__linux__) && defined(HAVE_SYSCALL)
      36             : # include <sys/syscall.h>
      37             : #endif
      38             : 
      39             : #include "types.h"
      40             : #include "g10lib.h"
      41             : #include "rand-internal.h"
      42             : 
      43             : static int open_device (const char *name, int retry);
      44             : 
      45             : 
      46             : static int
      47          20 : set_cloexec_flag (int fd)
      48             : {
      49             :   int oldflags;
      50             : 
      51          20 :   oldflags= fcntl (fd, F_GETFD, 0);
      52          20 :   if (oldflags < 0)
      53           0 :     return oldflags;
      54          20 :   oldflags |= FD_CLOEXEC;
      55          20 :   return fcntl (fd, F_SETFD, oldflags);
      56             : }
      57             : 
      58             : 
      59             : 
      60             : /*
      61             :  * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it
      62             :  * exists)).  If RETRY is true, the function does not terminate with
      63             :  * a fatal error but retries until it is able to reopen the device.
      64             :  */
      65             : static int
      66          20 : open_device (const char *name, int retry)
      67             : {
      68             :   int fd;
      69             : 
      70          20 :   if (retry)
      71           0 :     _gcry_random_progress ("open_dev_random", 'X', 1, 0);
      72             :  again:
      73          20 :   fd = open (name, O_RDONLY);
      74          20 :   if (fd == -1 && retry)
      75             :     {
      76             :       struct timeval tv;
      77             : 
      78           0 :       tv.tv_sec = 5;
      79           0 :       tv.tv_usec = 0;
      80           0 :       _gcry_random_progress ("wait_dev_random", 'X', 0, (int)tv.tv_sec);
      81           0 :       select (0, NULL, NULL, NULL, &tv);
      82           0 :       goto again;
      83             :     }
      84          20 :   if (fd == -1)
      85           0 :     log_fatal ("can't open %s: %s\n", name, strerror(errno) );
      86             : 
      87          20 :   if (set_cloexec_flag (fd))
      88           0 :     log_error ("error setting FD_CLOEXEC on fd %d: %s\n",
      89           0 :                fd, strerror (errno));
      90             : 
      91             :   /* We used to do the following check, however it turned out that this
      92             :      is not portable since more OSes provide a random device which is
      93             :      sometimes implemented as another device type.
      94             : 
      95             :      struct stat sb;
      96             : 
      97             :      if( fstat( fd, &sb ) )
      98             :         log_fatal("stat() off %s failed: %s\n", name, strerror(errno) );
      99             :      if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) )
     100             :         log_fatal("invalid random device!\n" );
     101             :   */
     102          20 :   return fd;
     103             : }
     104             : 
     105             : 
     106             : /* Note that the caller needs to make sure that this function is only
     107             :    called by one thread at a time.  The function returns 0 on success
     108             :    or true on failure (in which case the caller will signal a fatal
     109             :    error).  */
     110             : int
     111         458 : _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
     112             :                                           enum random_origins),
     113             :                               enum random_origins origin,
     114             :                               size_t length, int level )
     115             : {
     116             :   static int fd_urandom = -1;
     117             :   static int fd_random = -1;
     118             :   static unsigned char ever_opened;
     119             :   int fd;
     120             :   int n;
     121             :   byte buffer[768];
     122             :   size_t n_hw;
     123         458 :   size_t want = length;
     124         458 :   size_t last_so_far = 0;
     125         458 :   int any_need_entropy = 0;
     126             :   int delay;
     127             : 
     128         458 :   if (!add)
     129             :     {
     130             :       /* Special mode to close the descriptors.  */
     131           0 :       if (fd_random != -1)
     132             :         {
     133           0 :           close (fd_random);
     134           0 :           fd_random = -1;
     135             :         }
     136           0 :       if (fd_urandom != -1)
     137             :         {
     138           0 :           close (fd_urandom);
     139           0 :           fd_urandom = -1;
     140             :         }
     141           0 :       return 0;
     142             :     }
     143             : 
     144             : 
     145             :   /* First read from a hardware source.  However let it account only
     146             :      for up to 50% (or 25% for RDRAND) of the requested bytes.  */
     147         458 :   n_hw = _gcry_rndhw_poll_slow (add, origin);
     148         458 :   if ((_gcry_get_hw_features () & HWF_INTEL_RDRAND))
     149             :     {
     150           0 :       if (n_hw > length/4)
     151           0 :         n_hw = length/4;
     152             :     }
     153             :   else
     154             :     {
     155         458 :       if (n_hw > length/2)
     156           0 :         n_hw = length/2;
     157             :     }
     158         458 :   if (length > 1)
     159         458 :     length -= n_hw;
     160             : 
     161             :   /* Open the requested device.  The first time a device is to be
     162             :      opened we fail with a fatal error if the device does not exists.
     163             :      In case the device has ever been closed, further open requests
     164             :      will however retry indefinitely.  The rationale for this behaviour is
     165             :      that we always require the device to be existent but want a more
     166             :      graceful behaviour if the rarely needed close operation has been
     167             :      used and the device needs to be re-opened later. */
     168         458 :   if (level >= 2)
     169             :     {
     170           2 :       if (fd_random == -1)
     171             :         {
     172           2 :           fd_random = open_device (NAME_OF_DEV_RANDOM, (ever_opened & 1));
     173           2 :           ever_opened |= 1;
     174             :         }
     175           2 :       fd = fd_random;
     176             :     }
     177             :   else
     178             :     {
     179         456 :       if (fd_urandom == -1)
     180             :         {
     181          18 :           fd_urandom = open_device (NAME_OF_DEV_URANDOM, (ever_opened & 2));
     182          18 :           ever_opened |= 2;
     183             :         }
     184         456 :       fd = fd_urandom;
     185             :     }
     186             : 
     187             :   /* Enter the read loop.  */
     188         458 :   delay = 0;  /* Start with 0 seconds so that we do no block on the
     189             :                  first iteration and in turn call the progress function
     190             :                  before blocking.  To give the OS a better chance to
     191             :                  return with something we will actually use 100ms. */
     192        1374 :   while (length)
     193             :     {
     194             :       fd_set rfds;
     195             :       struct timeval tv;
     196             :       int rc;
     197             : 
     198             :       /* If we have a modern Linux kernel and we want to read from the
     199             :        * the non-blocking /dev/urandom, we first try to use the new
     200             :        * getrandom syscall.  That call guarantees that the kernel's
     201             :        * RNG has been properly seeded before returning any data.  This
     202             :        * is different from /dev/urandom which may, due to its
     203             :        * non-blocking semantics, return data even if the kernel has
     204             :        * not been properly seeded.  Unfortunately we need to use a
     205             :        * syscall and not a new device and thus we are not able to use
     206             :        * select(2) to have a timeout. */
     207             : #if defined(__linux__) && defined(HAVE_SYSCALL) && defined(__NR_getrandom)
     208         458 :       if (fd == fd_urandom)
     209             :         {
     210             :           long ret;
     211             :           size_t nbytes;
     212             : 
     213             :           do
     214             :             {
     215         456 :               nbytes = length < sizeof(buffer)? length : sizeof(buffer);
     216         456 :               if (nbytes > 256)
     217           0 :                 nbytes = 256;
     218         456 :               _gcry_pre_syscall ();
     219         456 :               ret = syscall (__NR_getrandom,
     220             :                              (void*)buffer, (size_t)nbytes, (unsigned int)0);
     221         456 :               _gcry_post_syscall ();
     222             :             }
     223         456 :           while (ret == -1 && errno == EINTR);
     224         456 :           if (ret == -1 && errno == ENOSYS)
     225             :             ; /* The syscall is not supported - fallback to /dev/urandom.  */
     226             :           else
     227             :             { /* The syscall is supported.  Some sanity checks.  */
     228         456 :               if (ret == -1)
     229           0 :                 log_fatal ("unexpected error from getrandom: %s\n",
     230           0 :                            strerror (errno));
     231         456 :               else if (ret != nbytes)
     232           0 :                 log_fatal ("getrandom returned only"
     233             :                            " %ld of %zu requested bytes\n", ret, nbytes);
     234             : 
     235         456 :               (*add)(buffer, nbytes, origin);
     236         456 :               length -= nbytes;
     237         912 :               continue; /* until LENGTH is zero.  */
     238             :             }
     239             :         }
     240             : #endif
     241             : 
     242             :       /* If we collected some bytes update the progress indicator.  We
     243             :          do this always and not just if the select timed out because
     244             :          often just a few bytes are gathered within the timeout
     245             :          period.  */
     246           2 :       if (any_need_entropy || last_so_far != (want - length) )
     247             :         {
     248           0 :           last_so_far = want - length;
     249           0 :           _gcry_random_progress ("need_entropy", 'X',
     250             :                                  (int)last_so_far, (int)want);
     251           0 :           any_need_entropy = 1;
     252             :         }
     253             : 
     254             :       /* If the system has no limit on the number of file descriptors
     255             :          and we encounter an fd which is larger than the fd_set size,
     256             :          we don't use the select at all.  The select code is only used
     257             :          to emit progress messages.  A better solution would be to
     258             :          fall back to poll() if available.  */
     259             : #ifdef FD_SETSIZE
     260           2 :       if (fd < FD_SETSIZE)
     261             : #endif
     262             :         {
     263           2 :           FD_ZERO(&rfds);
     264           2 :           FD_SET(fd, &rfds);
     265           2 :           tv.tv_sec = delay;
     266           2 :           tv.tv_usec = delay? 0 : 100000;
     267           2 :           _gcry_pre_syscall ();
     268           2 :           rc = select (fd+1, &rfds, NULL, NULL, &tv);
     269           2 :           _gcry_post_syscall ();
     270           2 :           if (!rc)
     271             :             {
     272           0 :               any_need_entropy = 1;
     273           0 :               delay = 3; /* Use 3 seconds henceforth.  */
     274           0 :               continue;
     275             :             }
     276           2 :           else if( rc == -1 )
     277             :             {
     278           0 :               log_error ("select() error: %s\n", strerror(errno));
     279           0 :               if (!delay)
     280           0 :                 delay = 1; /* Use 1 second if we encounter an error before
     281             :                               we have ever blocked.  */
     282           0 :               continue;
     283             :             }
     284             :         }
     285             : 
     286             :       do
     287             :         {
     288             :           size_t nbytes;
     289             : 
     290           2 :           nbytes = length < sizeof(buffer)? length : sizeof(buffer);
     291           2 :           n = read (fd, buffer, nbytes);
     292           2 :           if (n >= 0 && n > nbytes)
     293             :             {
     294           0 :               log_error("bogus read from random device (n=%d)\n", n );
     295           0 :               n = nbytes;
     296             :             }
     297             :         }
     298           2 :       while (n == -1 && errno == EINTR);
     299           2 :       if  (n == -1)
     300           0 :         log_fatal("read error on random device: %s\n", strerror(errno));
     301           2 :       (*add)(buffer, n, origin);
     302           2 :       length -= n;
     303             :     }
     304         458 :   wipememory (buffer, sizeof buffer);
     305             : 
     306         458 :   if (any_need_entropy)
     307           0 :     _gcry_random_progress ("need_entropy", 'X', (int)want, (int)want);
     308             : 
     309         458 :   return 0; /* success */
     310             : }

Generated by: LCOV version 1.13