Blame stdlib/tst-getrandom.c

Packit Service 82fcde
/* Tests for the getentropy, getrandom functions.
Packit Service 82fcde
   Copyright (C) 2016-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <stdbool.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <sys/random.h>
Packit Service 82fcde
Packit Service 82fcde
/* Set to true if any errors are encountered.  */
Packit Service 82fcde
static bool errors;
Packit Service 82fcde
Packit Service 82fcde
/* Test getrandom with a single buffer length.  NB: The passed-in
Packit Service 82fcde
   buffer must have room for four extra bytes after the specified
Packit Service 82fcde
   length, which are used to test that getrandom leaves those bytes
Packit Service 82fcde
   unchanged.  */
Packit Service 82fcde
static void
Packit Service 82fcde
test_length (char *buffer, size_t length, unsigned int flags)
Packit Service 82fcde
{
Packit Service 82fcde
  memset (buffer, 0, length);
Packit Service 82fcde
  strcpy (buffer + length, "123");
Packit Service 82fcde
  ssize_t ret = getrandom (buffer, length, flags);
Packit Service 82fcde
  if (ret < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* EAGAIN is an expected error with GRND_RANDOM and
Packit Service 82fcde
         GRND_NONBLOCK.  */
Packit Service 82fcde
      if ((flags & GRND_RANDOM)
Packit Service 82fcde
          && (flags & GRND_NONBLOCK)
Packit Service 82fcde
          && errno == EAGAIN)
Packit Service 82fcde
        return;
Packit Service 82fcde
      printf ("error: getrandom (%zu, 0x%x): %m\n", length, flags);
Packit Service 82fcde
      errors = true;
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
 if (ret != length)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (flags & GRND_RANDOM)
Packit Service 82fcde
        {
Packit Service 82fcde
          if (ret == 0 || ret > length)
Packit Service 82fcde
            {
Packit Service 82fcde
              printf ("error: getrandom (%zu, 0x%x) returned %zd\n",
Packit Service 82fcde
                      length, flags, ret);
Packit Service 82fcde
              errors = true;
Packit Service 82fcde
            }
Packit Service 82fcde
        }
Packit Service 82fcde
      else
Packit Service 82fcde
        {
Packit Service 82fcde
          printf ("error: getrandom (%zu, 0x%x) returned %zd\n",
Packit Service 82fcde
                  length, flags, ret);
Packit Service 82fcde
          errors = true;
Packit Service 82fcde
        }
Packit Service 82fcde
    }
Packit Service 82fcde
  if (length >= 7)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* One spurious test failure in 2**56 is sufficiently
Packit Service 82fcde
         unlikely.  */
Packit Service 82fcde
      int non_null = 0;
Packit Service 82fcde
      for (int i = 0; i < length; ++i)
Packit Service 82fcde
        non_null += buffer[i] != 0;
Packit Service 82fcde
      if (non_null == 0)
Packit Service 82fcde
        {
Packit Service 82fcde
          printf ("error: getrandom (%zu, 0x%x) returned all-zero bytes\n",
Packit Service 82fcde
                  length, flags);
Packit Service 82fcde
          errors = true;
Packit Service 82fcde
        }
Packit Service 82fcde
    }
Packit Service 82fcde
  if (memcmp (buffer + length, "123", 4) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("error: getrandom (%zu, 0x%x) wrote spurious bytes\n",
Packit Service 82fcde
              length, flags);
Packit Service 82fcde
      errors = true;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Call getrandom repeatedly to fill the buffer.  */
Packit Service 82fcde
static bool
Packit Service 82fcde
getrandom_full (char *buffer, size_t length, unsigned int flags)
Packit Service 82fcde
{
Packit Service 82fcde
  char *end = buffer + length;
Packit Service 82fcde
  while (buffer < end)
Packit Service 82fcde
    {
Packit Service 82fcde
      ssize_t ret = getrandom (buffer, end - buffer, flags);
Packit Service 82fcde
      if (ret < 0)
Packit Service 82fcde
        {
Packit Service 82fcde
          printf ("error: getrandom (%zu, 0x%x): %m\n", length, flags);
Packit Service 82fcde
          errors = true;
Packit Service 82fcde
          return false;
Packit Service 82fcde
        }
Packit Service 82fcde
      buffer += ret;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return true;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
test_flags (unsigned int flags)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Test various lengths, but only for !GRND_RANDOM, to conserve
Packit Service 82fcde
     entropy.  */
Packit Service 82fcde
  {
Packit Service 82fcde
    enum { max_length = 300 };
Packit Service 82fcde
    char buffer[max_length + 4];
Packit Service 82fcde
    if (flags & GRND_RANDOM)
Packit Service 82fcde
      test_length (buffer, 0, flags);
Packit Service 82fcde
    else
Packit Service 82fcde
      {
Packit Service 82fcde
        for (int length = 0; length <= 9; ++length)
Packit Service 82fcde
          test_length (buffer, length, flags);
Packit Service 82fcde
        test_length (buffer, 16, flags);
Packit Service 82fcde
        test_length (buffer, max_length, flags);
Packit Service 82fcde
      }
Packit Service 82fcde
  }
Packit Service 82fcde
Packit Service 82fcde
  /* Test that getrandom returns different data.  */
Packit Service 82fcde
  if (!(flags & GRND_NONBLOCK))
Packit Service 82fcde
    {
Packit Service 82fcde
      char buffer1[8];
Packit Service 82fcde
      memset (buffer1, 0, sizeof (buffer1));
Packit Service 82fcde
Packit Service 82fcde
      char buffer2[8];
Packit Service 82fcde
      memset (buffer2, 0, sizeof (buffer2));
Packit Service 82fcde
Packit Service 82fcde
      if (getrandom_full (buffer1, sizeof (buffer1), flags)
Packit Service 82fcde
          && getrandom_full (buffer2, sizeof (buffer2), flags))
Packit Service 82fcde
        {
Packit Service 82fcde
          /* The probability that these two 8-byte buffers are equal
Packit Service 82fcde
             is very small (assuming that two subsequent calls to
Packit Service 82fcde
             getrandom result are independent, uniformly distributed
Packit Service 82fcde
             random variables).  */
Packit Service 82fcde
          if (memcmp (buffer1, buffer2, sizeof (buffer1)) == 0)
Packit Service 82fcde
            {
Packit Service 82fcde
              printf ("error: getrandom returns constant value\n");
Packit Service 82fcde
              errors = true;
Packit Service 82fcde
            }
Packit Service 82fcde
        }
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
test_getentropy (void)
Packit Service 82fcde
{
Packit Service 82fcde
  char buf[16];
Packit Service 82fcde
  memset (buf, '@', sizeof (buf));
Packit Service 82fcde
  if (getentropy (buf, 0) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("error: getentropy zero length: %m\n");
Packit Service 82fcde
      errors = true;
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
  for (size_t i = 0; i < sizeof (buf); ++i)
Packit Service 82fcde
    if (buf[i] != '@')
Packit Service 82fcde
      {
Packit Service 82fcde
        printf ("error: getentropy modified zero-length buffer\n");
Packit Service 82fcde
        errors = true;
Packit Service 82fcde
        return;
Packit Service 82fcde
      }
Packit Service 82fcde
Packit Service 82fcde
  if (getentropy (buf, sizeof (buf)) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("error: getentropy buf: %m\n");
Packit Service 82fcde
      errors = true;
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  char buf2[256];
Packit Service 82fcde
  _Static_assert (sizeof (buf) < sizeof (buf2), "buf and buf2 compatible");
Packit Service 82fcde
  memset (buf2, '@', sizeof (buf2));
Packit Service 82fcde
  if (getentropy (buf2, sizeof (buf)) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("error: getentropy buf2: %m\n");
Packit Service 82fcde
      errors = true;
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* The probability that these two buffers are equal is very
Packit Service 82fcde
     small. */
Packit Service 82fcde
  if (memcmp (buf, buf2, sizeof (buf) == 0))
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("error: getentropy appears to return constant bytes\n");
Packit Service 82fcde
      errors = true;
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  for (size_t i = sizeof (buf); i < sizeof (buf2); ++i)
Packit Service 82fcde
    if (buf2[i] != '@')
Packit Service 82fcde
      {
Packit Service 82fcde
        printf ("error: getentropy wrote beyond the end of the buffer\n");
Packit Service 82fcde
        errors = true;
Packit Service 82fcde
        return;
Packit Service 82fcde
      }
Packit Service 82fcde
Packit Service 82fcde
  char buf3[257];
Packit Service 82fcde
  if (getentropy (buf3, sizeof (buf3)) == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("error: getentropy successful for 257 byte buffer\n");
Packit Service 82fcde
      errors = true;
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (errno != EIO)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("error: getentropy wrong error for 257 byte buffer: %m\n");
Packit Service 82fcde
      errors = true;
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
do_test (void)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Check if getrandom is not supported by this system.  */
Packit Service 82fcde
  if (getrandom (NULL, 0, 0) == -1 && errno == ENOSYS)
Packit Service 82fcde
    return 77;
Packit Service 82fcde
Packit Service 82fcde
  for (int use_random = 0; use_random < 2; ++use_random)
Packit Service 82fcde
    for (int use_nonblock = 0; use_nonblock < 2; ++use_nonblock)
Packit Service 82fcde
      {
Packit Service 82fcde
        unsigned int flags = 0;
Packit Service 82fcde
        if (use_random)
Packit Service 82fcde
          flags |= GRND_RANDOM;
Packit Service 82fcde
        if (use_nonblock)
Packit Service 82fcde
          flags |= GRND_NONBLOCK;
Packit Service 82fcde
        test_flags (flags);
Packit Service 82fcde
      }
Packit Service 82fcde
Packit Service 82fcde
  test_getentropy ();
Packit Service 82fcde
Packit Service 82fcde
  return errors;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#include <support/test-driver.c>