]> git.ipfire.org Git - thirdparty/glibc.git/blob - stdlib/tst-arc4random-fork.c
Regenerate libc.pot
[thirdparty/glibc.git] / 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>