(root)/
glibc-2.38/
stdlib/
tst-getrandom.c
       1  /* Tests for the getentropy, getrandom functions.
       2     Copyright (C) 2016-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library 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 GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <stdbool.h>
      21  #include <stdio.h>
      22  #include <string.h>
      23  #include <sys/random.h>
      24  
      25  /* Set to true if any errors are encountered.  */
      26  static bool errors;
      27  
      28  /* Test getrandom with a single buffer length.  NB: The passed-in
      29     buffer must have room for four extra bytes after the specified
      30     length, which are used to test that getrandom leaves those bytes
      31     unchanged.  */
      32  static void
      33  test_length (char *buffer, size_t length, unsigned int flags)
      34  {
      35    memset (buffer, 0, length);
      36    strcpy (buffer + length, "123");
      37    ssize_t ret = getrandom (buffer, length, flags);
      38    if (ret < 0)
      39      {
      40        /* EAGAIN is an expected error with GRND_RANDOM and
      41           GRND_NONBLOCK.  */
      42        if ((flags & GRND_RANDOM)
      43            && (flags & GRND_NONBLOCK)
      44            && errno == EAGAIN)
      45          return;
      46        printf ("error: getrandom (%zu, 0x%x): %m\n", length, flags);
      47        errors = true;
      48        return;
      49      }
      50   if (ret != length)
      51      {
      52        if (flags & GRND_RANDOM)
      53          {
      54            if (ret == 0 || ret > length)
      55              {
      56                printf ("error: getrandom (%zu, 0x%x) returned %zd\n",
      57                        length, flags, ret);
      58                errors = true;
      59              }
      60          }
      61        else
      62          {
      63            printf ("error: getrandom (%zu, 0x%x) returned %zd\n",
      64                    length, flags, ret);
      65            errors = true;
      66          }
      67      }
      68    if (length >= 7)
      69      {
      70        /* One spurious test failure in 2**56 is sufficiently
      71           unlikely.  */
      72        int non_null = 0;
      73        for (int i = 0; i < length; ++i)
      74          non_null += buffer[i] != 0;
      75        if (non_null == 0)
      76          {
      77            printf ("error: getrandom (%zu, 0x%x) returned all-zero bytes\n",
      78                    length, flags);
      79            errors = true;
      80          }
      81      }
      82    if (memcmp (buffer + length, "123", 4) != 0)
      83      {
      84        printf ("error: getrandom (%zu, 0x%x) wrote spurious bytes\n",
      85                length, flags);
      86        errors = true;
      87      }
      88  }
      89  
      90  /* Call getrandom repeatedly to fill the buffer.  */
      91  static bool
      92  getrandom_full (char *buffer, size_t length, unsigned int flags)
      93  {
      94    char *end = buffer + length;
      95    while (buffer < end)
      96      {
      97        ssize_t ret = getrandom (buffer, end - buffer, flags);
      98        if (ret < 0)
      99          {
     100            printf ("error: getrandom (%zu, 0x%x): %m\n", length, flags);
     101            errors = true;
     102            return false;
     103          }
     104        buffer += ret;
     105      }
     106  
     107    return true;
     108  }
     109  
     110  static void
     111  test_flags (unsigned int flags)
     112  {
     113    /* Test various lengths, but only for !GRND_RANDOM, to conserve
     114       entropy.  */
     115    {
     116      enum { max_length = 300 };
     117      char buffer[max_length + 4];
     118      if (flags & GRND_RANDOM)
     119        test_length (buffer, 0, flags);
     120      else
     121        {
     122          for (int length = 0; length <= 9; ++length)
     123            test_length (buffer, length, flags);
     124          test_length (buffer, 16, flags);
     125          test_length (buffer, max_length, flags);
     126        }
     127    }
     128  
     129    /* Test that getrandom returns different data.  */
     130    if (!(flags & GRND_NONBLOCK))
     131      {
     132        char buffer1[8];
     133        memset (buffer1, 0, sizeof (buffer1));
     134  
     135        char buffer2[8];
     136        memset (buffer2, 0, sizeof (buffer2));
     137  
     138        if (getrandom_full (buffer1, sizeof (buffer1), flags)
     139            && getrandom_full (buffer2, sizeof (buffer2), flags))
     140          {
     141            /* The probability that these two 8-byte buffers are equal
     142               is very small (assuming that two subsequent calls to
     143               getrandom result are independent, uniformly distributed
     144               random variables).  */
     145            if (memcmp (buffer1, buffer2, sizeof (buffer1)) == 0)
     146              {
     147                printf ("error: getrandom returns constant value\n");
     148                errors = true;
     149              }
     150          }
     151      }
     152  }
     153  
     154  static void
     155  test_getentropy (void)
     156  {
     157    char buf[16];
     158    memset (buf, '@', sizeof (buf));
     159    if (getentropy (buf, 0) != 0)
     160      {
     161        printf ("error: getentropy zero length: %m\n");
     162        errors = true;
     163        return;
     164      }
     165    for (size_t i = 0; i < sizeof (buf); ++i)
     166      if (buf[i] != '@')
     167        {
     168          printf ("error: getentropy modified zero-length buffer\n");
     169          errors = true;
     170          return;
     171        }
     172  
     173    if (getentropy (buf, sizeof (buf)) != 0)
     174      {
     175        printf ("error: getentropy buf: %m\n");
     176        errors = true;
     177        return;
     178      }
     179  
     180    char buf2[256];
     181    _Static_assert (sizeof (buf) < sizeof (buf2), "buf and buf2 compatible");
     182    memset (buf2, '@', sizeof (buf2));
     183    if (getentropy (buf2, sizeof (buf)) != 0)
     184      {
     185        printf ("error: getentropy buf2: %m\n");
     186        errors = true;
     187        return;
     188      }
     189  
     190    /* The probability that these two buffers are equal is very
     191       small. */
     192    if (memcmp (buf, buf2, sizeof (buf)) == 0)
     193      {
     194        printf ("error: getentropy appears to return constant bytes\n");
     195        errors = true;
     196        return;
     197      }
     198  
     199    for (size_t i = sizeof (buf); i < sizeof (buf2); ++i)
     200      if (buf2[i] != '@')
     201        {
     202          printf ("error: getentropy wrote beyond the end of the buffer\n");
     203          errors = true;
     204          return;
     205        }
     206  
     207    char buf3[257];
     208    if (getentropy (buf3, sizeof (buf3)) == 0)
     209      {
     210        printf ("error: getentropy successful for 257 byte buffer\n");
     211        errors = true;
     212        return;
     213      }
     214    if (errno != EIO)
     215      {
     216        printf ("error: getentropy wrong error for 257 byte buffer: %m\n");
     217        errors = true;
     218        return;
     219      }
     220  }
     221  
     222  static int
     223  do_test (void)
     224  {
     225    /* Check if getrandom is not supported by this system.  */
     226    if (getrandom (NULL, 0, 0) == -1 && errno == ENOSYS)
     227      return 77;
     228  
     229    for (int use_random = 0; use_random < 2; ++use_random)
     230      for (int use_nonblock = 0; use_nonblock < 2; ++use_nonblock)
     231        {
     232          unsigned int flags = 0;
     233          if (use_random)
     234            flags |= GRND_RANDOM;
     235          if (use_nonblock)
     236            flags |= GRND_NONBLOCK;
     237          test_flags (flags);
     238        }
     239  
     240    test_getentropy ();
     241  
     242    return errors;
     243  }
     244  
     245  #include <support/test-driver.c>