(root)/
coreutils-9.4/
lib/
randread.c
       1  /* Generate buffers of random data.
       2  
       3     Copyright (C) 2006-2023 Free Software Foundation, Inc.
       4  
       5     This program is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU General Public License as published by
       7     the Free Software Foundation, either version 3 of the License, or
       8     (at your option) any later version.
       9  
      10     This program is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13     GNU General Public License for more details.
      14  
      15     You should have received a copy of the GNU General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  /* Written by Paul Eggert.  */
      19  
      20  /* FIXME: Improve performance by adding support for the RDRAND machine
      21     instruction if available (e.g., Ivy Bridge processors).  */
      22  
      23  #include <config.h>
      24  
      25  #include "randread.h"
      26  
      27  #include <errno.h>
      28  #include <error.h>
      29  #include <exitfail.h>
      30  #include <fcntl.h>
      31  #include <quote.h>
      32  #include <stdint.h>
      33  #include <stdio.h>
      34  #include <stdlib.h>
      35  #include <string.h>
      36  #include <sys/random.h>
      37  
      38  #include "gettext.h"
      39  #define _(msgid) gettext (msgid)
      40  
      41  #include "assure.h"
      42  #include "minmax.h"
      43  #include "rand-isaac.h"
      44  #include "stdio-safer.h"
      45  #include "unlocked-io.h"
      46  #include "xalloc.h"
      47  
      48  #if _STRING_ARCH_unaligned || _STRING_INLINE_unaligned
      49  # define ALIGNED_POINTER(ptr, type) true
      50  #else
      51  # define ALIGNED_POINTER(ptr, type) ((size_t) (ptr) % alignof (type) == 0)
      52  #endif
      53  
      54  /* The maximum buffer size used for reads of random data.  Using the
      55     value 2 * ISAAC_BYTES makes this the largest power of two that
      56     would not otherwise cause struct randread_source to grow.  */
      57  #define RANDREAD_BUFFER_SIZE (2 * ISAAC_BYTES)
      58  
      59  /* A source of random data for generating random buffers.  */
      60  struct randread_source
      61  {
      62    /* Stream to read random bytes from.  If null, the current
      63       implementation uses an internal PRNG (ISAAC).  */
      64    FILE *source;
      65  
      66    /* Function to call, and its argument, if there is an input error or
      67       end of file when reading from the stream; errno is nonzero if
      68       there was an error.  If this function returns, it should fix the
      69       problem before returning.  The default handler assumes that
      70       handler_arg is the file name of the source.  */
      71    void (*handler) (void const *);
      72    void const *handler_arg;
      73  
      74    /* The buffer for SOURCE.  It's kept here to simplify storage
      75       allocation and to make it easier to clear out buffered random
      76       data.  */
      77    union
      78    {
      79      /* The stream buffer, if SOURCE is not null.  */
      80      char c[RANDREAD_BUFFER_SIZE];
      81  
      82      /* The buffered ISAAC pseudorandom buffer, if SOURCE is null.  */
      83      struct isaac
      84      {
      85        /* The number of bytes that are buffered at the end of data.b.  */
      86        size_t buffered;
      87  
      88        /* State of the ISAAC generator.  */
      89        struct isaac_state state;
      90  
      91        /* Up to a buffer's worth of pseudorandom data.  */
      92        union
      93        {
      94          isaac_word w[ISAAC_WORDS];
      95          unsigned char b[ISAAC_BYTES];
      96        } data;
      97      } isaac;
      98    } buf;
      99  };
     100  
     101  
     102  /* The default error handler.  */
     103  
     104  static void
     105  randread_error (void const *file_name)
     106  {
     107    affirm (exit_failure);
     108    error (exit_failure, errno,
     109           errno == 0 ? _("%s: end of file") : _("%s: read error"),
     110           quote (file_name));
     111  }
     112  
     113  /* Simply return a new randread_source object with the default error
     114     handler.  */
     115  
     116  static struct randread_source *
     117  simple_new (FILE *source, void const *handler_arg)
     118  {
     119    struct randread_source *s = xmalloc (sizeof *s);
     120    s->source = source;
     121    s->handler = randread_error;
     122    s->handler_arg = handler_arg;
     123    return s;
     124  }
     125  
     126  /* Put a nonce value into BUFFER, with size BUFSIZE.
     127     Return true on success, false (setting errno) on failure.  */
     128  
     129  static bool
     130  get_nonce (void *buffer, size_t bufsize)
     131  {
     132    char *buf = buffer, *buflim = buf + bufsize;
     133    while (buf < buflim)
     134      {
     135  #if defined __sun
     136  # define MAX_GETRANDOM 1024
     137  #else
     138  # define MAX_GETRANDOM SIZE_MAX
     139  #endif
     140        size_t max_bytes = MIN (buflim - buf, MAX_GETRANDOM);
     141        ssize_t nbytes = getrandom (buf, max_bytes, 0);
     142        if (0 <= nbytes)
     143          buf += nbytes;
     144        else if (errno != EINTR)
     145          return false;
     146      }
     147    return true;
     148  }
     149  
     150  /* Body of randread_free, broken out to pacify gcc -Wmismatched-dealloc.  */
     151  
     152  static int
     153  randread_free_body (struct randread_source *s)
     154  {
     155    FILE *source = s->source;
     156    explicit_bzero (s, sizeof *s);
     157    free (s);
     158    return source ? fclose (source) : 0;
     159  }
     160  
     161  /* Create and initialize a random data source from NAME, or use a
     162     reasonable default source if NAME is null.  BYTES_BOUND is an upper
     163     bound on the number of bytes that will be needed.  If zero, it is a
     164     hard bound; otherwise it is just an estimate.
     165  
     166     If NAME is not null, NAME is saved for use as the argument of the
     167     default handler.  Unless a non-default handler is used, NAME's
     168     lifetime should be at least that of the returned value.
     169  
     170     Return nullptr (setting errno) on failure.  */
     171  
     172  struct randread_source *
     173  randread_new (char const *name, size_t bytes_bound)
     174  {
     175    if (bytes_bound == 0)
     176      return simple_new (nullptr, nullptr);
     177    else
     178      {
     179        FILE *source = nullptr;
     180        struct randread_source *s;
     181  
     182        if (name)
     183          if (! (source = fopen_safer (name, "rb")))
     184            return nullptr;
     185  
     186        s = simple_new (source, name);
     187  
     188        if (source)
     189          setvbuf (source, s->buf.c, _IOFBF, MIN (sizeof s->buf.c, bytes_bound));
     190        else
     191          {
     192            s->buf.isaac.buffered = 0;
     193            if (! get_nonce (s->buf.isaac.state.m,
     194                             MIN (sizeof s->buf.isaac.state.m, bytes_bound)))
     195              {
     196                int e = errno;
     197                randread_free_body (s);
     198                errno = e;
     199                return nullptr;
     200              }
     201            isaac_seed (&s->buf.isaac.state);
     202          }
     203  
     204        return s;
     205      }
     206  }
     207  
     208  
     209  /* Set S's handler and its argument.  HANDLER (HANDLER_ARG) is called
     210     when there is a read error or end of file from the random data
     211     source; errno is nonzero if there was an error.  If HANDLER
     212     returns, it should fix the problem before returning.  The default
     213     handler assumes that handler_arg is the file name of the source; it
     214     does not return.  */
     215  
     216  void
     217  randread_set_handler (struct randread_source *s, void (*handler) (void const *))
     218  {
     219    s->handler = handler;
     220  }
     221  
     222  void
     223  randread_set_handler_arg (struct randread_source *s, void const *handler_arg)
     224  {
     225    s->handler_arg = handler_arg;
     226  }
     227  
     228  
     229  /* Place SIZE random bytes into the buffer beginning at P, using
     230     the stream in S.  */
     231  
     232  static void
     233  readsource (struct randread_source *s, unsigned char *p, size_t size)
     234  {
     235    while (true)
     236      {
     237        size_t inbytes = fread (p, sizeof *p, size, s->source);
     238        int fread_errno = errno;
     239        p += inbytes;
     240        size -= inbytes;
     241        if (size == 0)
     242          break;
     243        errno = (ferror (s->source) ? fread_errno : 0);
     244        s->handler (s->handler_arg);
     245      }
     246  }
     247  
     248  
     249  /* Place SIZE pseudorandom bytes into the buffer beginning at P, using
     250     the buffered ISAAC generator in ISAAC.  */
     251  
     252  static void
     253  readisaac (struct isaac *isaac, void *p, size_t size)
     254  {
     255    size_t inbytes = isaac->buffered;
     256  
     257    while (true)
     258      {
     259        char *char_p = p;
     260  
     261        if (size <= inbytes)
     262          {
     263            memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, size);
     264            isaac->buffered = inbytes - size;
     265            return;
     266          }
     267  
     268        memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, inbytes);
     269        p = char_p + inbytes;
     270        size -= inbytes;
     271  
     272        /* If P is aligned, write to *P directly to avoid the overhead
     273           of copying from the buffer.  */
     274        if (ALIGNED_POINTER (p, isaac_word))
     275          {
     276            isaac_word *wp = p;
     277            while (ISAAC_BYTES <= size)
     278              {
     279                isaac_refill (&isaac->state, wp);
     280                wp += ISAAC_WORDS;
     281                size -= ISAAC_BYTES;
     282                if (size == 0)
     283                  {
     284                    isaac->buffered = 0;
     285                    return;
     286                  }
     287              }
     288            p = wp;
     289          }
     290  
     291        isaac_refill (&isaac->state, isaac->data.w);
     292        inbytes = ISAAC_BYTES;
     293      }
     294  }
     295  
     296  
     297  /* Consume random data from *S to generate a random buffer BUF of size
     298     SIZE.  */
     299  
     300  void
     301  randread (struct randread_source *s, void *buf, size_t size)
     302  {
     303    if (s->source)
     304      readsource (s, buf, size);
     305    else
     306      readisaac (&s->buf.isaac, buf, size);
     307  }
     308  
     309  
     310  /* Clear *S so that it no longer contains undelivered random data, and
     311     deallocate any system resources associated with *S.  Return 0 if
     312     successful, a negative number (setting errno) if not (this is rare,
     313     but can occur in theory if there is an input error).  */
     314  
     315  int
     316  randread_free (struct randread_source *s)
     317  {
     318    return randread_free_body (s);
     319  }