]>
Commit | Line | Data |
---|---|---|
92dcaa3e | 1 | /* Tests for the getentropy, getrandom functions. |
581c785b | 2 | Copyright (C) 2016-2022 Free Software Foundation, Inc. |
92dcaa3e FW |
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 | |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
92dcaa3e FW |
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> |