(root)/
glibc-2.38/
stdlib/
tst-arc4random-fork.c
       1  /* Test that subprocesses generate distinct streams of randomness.
       2     Copyright (C) 2022-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  /* Collect random data from subprocesses and check that all the
      20     results are unique.  */
      21  
      22  #include <array_length.h>
      23  #include <stdlib.h>
      24  #include <stdio.h>
      25  #include <string.h>
      26  #include <support/check.h>
      27  #include <support/support.h>
      28  #include <support/xthread.h>
      29  #include <support/xunistd.h>
      30  #include <unistd.h>
      31  
      32  /* Perform multiple runs.  The subsequent runs start with an
      33     already-initialized random number generator.  */
      34  enum { runs = 10 };
      35  
      36  /* Total number of spawned processes on each run.  */
      37  enum { subprocesses = 49 };
      38  
      39  /* The total number of processes.  */
      40  enum { processes = subprocesses + 1 };
      41  
      42  /* Number of bytes of randomness to generate per process.  Large
      43     enough to make false positive duplicates extremely unlikely.  */
      44  enum { random_size = 16 };
      45  
      46  /* Generated bytes of randomness.  */
      47  struct result
      48  {
      49    unsigned char bytes[random_size];
      50  };
      51  
      52  /* Shared across all processes.  */
      53  static struct shared_data
      54  {
      55    pthread_barrier_t barrier;
      56    struct result results[runs][processes];
      57  } *shared_data;
      58  
      59  static void
      60  generate_arc4random (unsigned char *bytes)
      61  {
      62    for (int i = 0; i < random_size / sizeof (uint32_t); i++)
      63      {
      64        uint32_t x = arc4random ();
      65        memcpy (&bytes[4 * i], &x, sizeof x);
      66      }
      67  }
      68  
      69  static void
      70  generate_arc4random_buf (unsigned char *bytes)
      71  {
      72    arc4random_buf (bytes, random_size);
      73  }
      74  
      75  static void
      76  generate_arc4random_uniform (unsigned char *bytes)
      77  {
      78    for (int i = 0; i < random_size; i++)
      79      bytes[i] = arc4random_uniform (256);
      80  }
      81  
      82  /* Invoked to collect data from a subprocess.  */
      83  static void
      84  subprocess (int run, int process_index, void (*func)(unsigned char *))
      85  {
      86    xpthread_barrier_wait (&shared_data->barrier);
      87    func (shared_data->results[run][process_index].bytes);
      88  }
      89  
      90  /* Used to sort the results.  */
      91  struct index
      92  {
      93    int run;
      94    int process_index;
      95  };
      96  
      97  /* Used to sort an array of struct index values.  */
      98  static int
      99  index_compare (const void *left1, const void *right1)
     100  {
     101    const struct index *left = left1;
     102    const struct index *right = right1;
     103  
     104    return memcmp (shared_data->results[left->run][left->process_index].bytes,
     105                   shared_data->results[right->run][right->process_index].bytes,
     106                   random_size);
     107  }
     108  
     109  static int
     110  do_test_func (void (*func)(unsigned char *bytes))
     111  {
     112    /* Collect random data.  */
     113    for (int run = 0; run < runs; ++run)
     114      {
     115        pid_t pids[subprocesses];
     116        for (int process_index = 0; process_index < subprocesses;
     117             ++process_index)
     118          {
     119            pids[process_index] = xfork ();
     120            if (pids[process_index] == 0)
     121              {
     122                subprocess (run, process_index, func);
     123                _exit (0);
     124              }
     125          }
     126  
     127        /* Trigger all subprocesses.  Also add data from the parent
     128           process.  */
     129        subprocess (run, subprocesses, func);
     130  
     131        for (int process_index = 0; process_index < subprocesses;
     132             ++process_index)
     133          {
     134            int status;
     135            xwaitpid (pids[process_index], &status, 0);
     136            if (status != 0)
     137              FAIL_EXIT1 ("subprocess index %d (PID %d) exit status %d\n",
     138                          process_index, (int) pids[process_index], status);
     139          }
     140      }
     141  
     142    /* Check for duplicates.  */
     143    struct index indexes[runs * processes];
     144    for (int run = 0; run < runs; ++run)
     145      for (int process_index = 0; process_index < processes; ++process_index)
     146        indexes[run * processes + process_index]
     147          = (struct index) { .run = run, .process_index = process_index };
     148    qsort (indexes, array_length (indexes), sizeof (indexes[0]), index_compare);
     149    for (size_t i = 1; i < array_length (indexes); ++i)
     150      {
     151        if (index_compare (indexes + i - 1, indexes + i) == 0)
     152          {
     153            support_record_failure ();
     154            unsigned char *bytes
     155              = shared_data->results[indexes[i].run]
     156                  [indexes[i].process_index].bytes;
     157            char *quoted = support_quote_blob (bytes, random_size);
     158            printf ("error: duplicate randomness data: \"%s\"\n"
     159                    "  run %d, subprocess %d\n"
     160                    "  run %d, subprocess %d\n",
     161                    quoted, indexes[i - 1].run, indexes[i - 1].process_index,
     162                    indexes[i].run, indexes[i].process_index);
     163            free (quoted);
     164          }
     165      }
     166  
     167    return 0;
     168  }
     169  
     170  static int
     171  do_test (void)
     172  {
     173    shared_data = support_shared_allocate (sizeof (*shared_data));
     174    {
     175      pthread_barrierattr_t attr;
     176      xpthread_barrierattr_init (&attr);
     177      xpthread_barrierattr_setpshared (&attr, PTHREAD_PROCESS_SHARED);
     178      xpthread_barrier_init (&shared_data->barrier, &attr, processes);
     179      xpthread_barrierattr_destroy (&attr);
     180    }
     181  
     182    do_test_func (generate_arc4random);
     183    do_test_func (generate_arc4random_buf);
     184    do_test_func (generate_arc4random_uniform);
     185  
     186    xpthread_barrier_destroy (&shared_data->barrier);
     187    support_shared_free (shared_data);
     188    shared_data = NULL;
     189  
     190    return 0;
     191  }
     192  
     193  #define TIMEOUT 40
     194  #include <support/test-driver.c>