xref: /netbsd-src/tests/lib/libc/sys/t_getrandom.c (revision a5ca3916c3205ae0d8d7e8f162a894d0e48199f7)
1 /*	$NetBSD: t_getrandom.c,v 1.5 2023/08/03 03:18:12 rin Exp $	*/
2 
3 /*-
4  * Copyright (c) 2020 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Taylor R. Campbell.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: t_getrandom.c,v 1.5 2023/08/03 03:18:12 rin Exp $");
34 
35 #include <sys/param.h>
36 
37 #include <sys/random.h>
38 
39 #include <atf-c.h>
40 #include <errno.h>
41 #include <signal.h>
42 #include <stdio.h>
43 #include <unistd.h>
44 
45 static uint8_t buf[65536];
46 static uint8_t zero24[24];
47 
48 static void
alarm_handler(int signo)49 alarm_handler(int signo)
50 {
51 
52 	fprintf(stderr, "timeout\n");
53 }
54 
55 static void
install_alarm_handler(void)56 install_alarm_handler(void)
57 {
58 	struct sigaction sa;
59 
60 	memset(&sa, 0, sizeof sa);
61 	sa.sa_handler = alarm_handler;
62 	sigfillset(&sa.sa_mask);
63 	sa.sa_flags = 0;	/* no SA_RESTART */
64 
65 	ATF_CHECK_MSG(sigaction(SIGALRM, &sa, NULL) != -1,
66 	    "sigaction(SIGALRM): %s", strerror(errno));
67 }
68 
69 /*
70  * Probability of spurious failure is 1/2^192 for each of the memcmps.
71  * As long as there are fewer than 2^64 of them, the probability of
72  * spurious failure is at most 1/2^128, which is low enough that we
73  * don't care about it.
74  */
75 
76 ATF_TC(getrandom_default);
ATF_TC_HEAD(getrandom_default,tc)77 ATF_TC_HEAD(getrandom_default, tc)
78 {
79 	atf_tc_set_md_var(tc, "descr", "getrandom(..., 0)");
80 	atf_tc_set_md_var(tc, "timeout", "2");
81 }
ATF_TC_BODY(getrandom_default,tc)82 ATF_TC_BODY(getrandom_default, tc)
83 {
84 	ssize_t n;
85 
86 	/* default */
87 	install_alarm_handler();
88 	alarm(1);
89 	memset(buf, 0, sizeof buf);
90 	n = getrandom(buf, sizeof buf, 0);
91 	if (n == -1) {
92 		ATF_CHECK_EQ(errno, EINTR);
93 	} else {
94 		ATF_CHECK(n >= (ssize_t)MIN(256, sizeof buf));
95 		ATF_CHECK((size_t)n <= sizeof buf);
96 		ATF_CHECK(memcmp(buf, zero24, 24) != 0);
97 		ATF_CHECK(memcmp(buf + n - 24, zero24, 24) != 0);
98 	}
99 	alarm(0);
100 }
101 
102 ATF_TC(getrandom_nonblock);
ATF_TC_HEAD(getrandom_nonblock,tc)103 ATF_TC_HEAD(getrandom_nonblock, tc)
104 {
105 	atf_tc_set_md_var(tc, "descr", "getrandom(..., GRND_NONBLOCK)");
106 }
ATF_TC_BODY(getrandom_nonblock,tc)107 ATF_TC_BODY(getrandom_nonblock, tc)
108 {
109 	ssize_t n;
110 
111 	/* default, nonblocking */
112 	memset(buf, 0, sizeof buf);
113 	n = getrandom(buf, sizeof buf, GRND_NONBLOCK);
114 	if (n == -1) {
115 		ATF_CHECK_EQ(errno, EAGAIN);
116 	} else {
117 		ATF_CHECK(n >= (ssize_t)MIN(256, sizeof buf));
118 		ATF_CHECK((size_t)n <= sizeof buf);
119 		ATF_CHECK(memcmp(buf, zero24, 24) != 0);
120 		ATF_CHECK(memcmp(buf + n - 24, zero24, 24) != 0);
121 	}
122 }
123 
124 ATF_TC(getrandom_insecure);
ATF_TC_HEAD(getrandom_insecure,tc)125 ATF_TC_HEAD(getrandom_insecure, tc)
126 {
127 	atf_tc_set_md_var(tc, "descr", "getrandom(..., GRND_INSECURE)");
128 }
ATF_TC_BODY(getrandom_insecure,tc)129 ATF_TC_BODY(getrandom_insecure, tc)
130 {
131 	ssize_t n;
132 
133 	/* insecure */
134 	memset(buf, 0, sizeof buf);
135 	n = getrandom(buf, sizeof buf, GRND_INSECURE);
136 	ATF_CHECK(n != -1);
137 	ATF_CHECK(n >= (ssize_t)MIN(256, sizeof buf));
138 	ATF_CHECK((size_t)n <= sizeof buf);
139 	ATF_CHECK(memcmp(buf, zero24, 24) != 0);
140 	ATF_CHECK(memcmp(buf + n - 24, zero24, 24) != 0);
141 }
142 
143 ATF_TC(getrandom_insecure_nonblock);
ATF_TC_HEAD(getrandom_insecure_nonblock,tc)144 ATF_TC_HEAD(getrandom_insecure_nonblock, tc)
145 {
146 	atf_tc_set_md_var(tc, "descr",
147 	    "getrandom(..., GRND_INSECURE|GRND_NONBLOCK)");
148 }
ATF_TC_BODY(getrandom_insecure_nonblock,tc)149 ATF_TC_BODY(getrandom_insecure_nonblock, tc)
150 {
151 	ssize_t n;
152 
153 	/* insecure, nonblocking -- same as mere insecure */
154 	memset(buf, 0, sizeof buf);
155 	n = getrandom(buf, sizeof buf, GRND_INSECURE|GRND_NONBLOCK);
156 	ATF_CHECK(n != -1);
157 	ATF_CHECK(n >= (ssize_t)MIN(256, sizeof buf));
158 	ATF_CHECK((size_t)n <= sizeof buf);
159 	ATF_CHECK(memcmp(buf, zero24, 24) != 0);
160 	ATF_CHECK(memcmp(buf + n - 24, zero24, 24) != 0);
161 }
162 
163 ATF_TC(getrandom_random);
ATF_TC_HEAD(getrandom_random,tc)164 ATF_TC_HEAD(getrandom_random, tc)
165 {
166 	atf_tc_set_md_var(tc, "descr", "getrandom(..., GRND_RANDOM)");
167 	atf_tc_set_md_var(tc, "timeout", "2");
168 }
ATF_TC_BODY(getrandom_random,tc)169 ATF_TC_BODY(getrandom_random, tc)
170 {
171 	ssize_t n;
172 
173 	/* `random' (hokey) */
174 	install_alarm_handler();
175 	alarm(1);
176 	memset(buf, 0, sizeof buf);
177 	n = getrandom(buf, sizeof buf, GRND_RANDOM);
178 	if (n == -1) {
179 		ATF_CHECK_EQ(errno, EINTR);
180 	} else {
181 		ATF_CHECK(n != 0);
182 		ATF_CHECK((size_t)n <= sizeof buf);
183 		if ((size_t)n >= 24) {
184 			ATF_CHECK(memcmp(buf, zero24, 24) != 0);
185 			ATF_CHECK(memcmp(buf + n - 24, zero24, 24) != 0);
186 		}
187 	}
188 	alarm(0);
189 }
190 
191 ATF_TC(getrandom_random_nonblock);
ATF_TC_HEAD(getrandom_random_nonblock,tc)192 ATF_TC_HEAD(getrandom_random_nonblock, tc)
193 {
194 	atf_tc_set_md_var(tc, "descr",
195 	    "getrandom(..., GRND_RANDOM|GRND_NONBLOCK)");
196 }
ATF_TC_BODY(getrandom_random_nonblock,tc)197 ATF_TC_BODY(getrandom_random_nonblock, tc)
198 {
199 	ssize_t n;
200 
201 	/* `random' (hokey), nonblocking */
202 	memset(buf, 0, sizeof buf);
203 	n = getrandom(buf, sizeof buf, GRND_RANDOM|GRND_NONBLOCK);
204 	if (n == -1) {
205 		ATF_CHECK_EQ(errno, EAGAIN);
206 	} else {
207 		ATF_CHECK(n != 0);
208 		ATF_CHECK((size_t)n <= sizeof buf);
209 		if ((size_t)n >= 24) {
210 			ATF_CHECK(memcmp(buf, zero24, 24) != 0);
211 			ATF_CHECK(memcmp(buf + n - 24, zero24, 24) != 0);
212 		}
213 	}
214 }
215 
216 ATF_TC(getrandom_random_insecure);
ATF_TC_HEAD(getrandom_random_insecure,tc)217 ATF_TC_HEAD(getrandom_random_insecure, tc)
218 {
219 	atf_tc_set_md_var(tc, "descr",
220 	    "getrandom(..., GRND_RANDOM|GRND_INSECURE)");
221 }
ATF_TC_BODY(getrandom_random_insecure,tc)222 ATF_TC_BODY(getrandom_random_insecure, tc)
223 {
224 	ssize_t n;
225 
226 	/* random and insecure -- nonsensical */
227 	n = getrandom(buf, sizeof buf, GRND_RANDOM|GRND_INSECURE);
228 	ATF_CHECK_EQ(n, -1);
229 	ATF_CHECK_EQ(errno, EINVAL);
230 }
231 
232 ATF_TC(getrandom_random_insecure_nonblock);
ATF_TC_HEAD(getrandom_random_insecure_nonblock,tc)233 ATF_TC_HEAD(getrandom_random_insecure_nonblock, tc)
234 {
235 	atf_tc_set_md_var(tc, "descr",
236 	    "getrandom(..., GRND_RANDOM|GRND_INSECURE|GRND_NONBLOCK)");
237 }
ATF_TC_BODY(getrandom_random_insecure_nonblock,tc)238 ATF_TC_BODY(getrandom_random_insecure_nonblock, tc)
239 {
240 	ssize_t n;
241 
242 	/* random and insecure, nonblocking -- nonsensical */
243 	n = getrandom(buf, sizeof buf,
244 	    GRND_RANDOM|GRND_INSECURE|GRND_NONBLOCK);
245 	ATF_CHECK_EQ(n, -1);
246 	ATF_CHECK_EQ(errno, EINVAL);
247 }
248 
249 ATF_TC(getrandom_invalid);
ATF_TC_HEAD(getrandom_invalid,tc)250 ATF_TC_HEAD(getrandom_invalid, tc)
251 {
252 	atf_tc_set_md_var(tc, "descr", "getrandom(..., <invalid>)");
253 }
ATF_TC_BODY(getrandom_invalid,tc)254 ATF_TC_BODY(getrandom_invalid, tc)
255 {
256 	ssize_t n;
257 
258 	/* invalid flags */
259 	__CTASSERT(~(GRND_RANDOM|GRND_INSECURE|GRND_NONBLOCK));
260 	n = getrandom(buf, sizeof buf,
261 	    ~(GRND_RANDOM|GRND_INSECURE|GRND_NONBLOCK));
262 	ATF_CHECK_EQ(n, -1);
263 	ATF_CHECK_EQ(errno, EINVAL);
264 }
265 
266 ATF_TC(getrandom_fault);
ATF_TC_HEAD(getrandom_fault,tc)267 ATF_TC_HEAD(getrandom_fault, tc)
268 {
269 	atf_tc_set_md_var(tc, "descr", "getrandom(NULL, ...)");
270 }
ATF_TC_BODY(getrandom_fault,tc)271 ATF_TC_BODY(getrandom_fault, tc)
272 {
273 	ssize_t n;
274 
275 	/* unmapped */
276 	n = getrandom(NULL, sizeof buf, GRND_INSECURE|GRND_NONBLOCK);
277 	ATF_CHECK_EQ(n, -1);
278 	ATF_CHECK_EQ(errno, EFAULT);
279 }
280 
ATF_TP_ADD_TCS(tp)281 ATF_TP_ADD_TCS(tp)
282 {
283 
284 	ATF_TP_ADD_TC(tp, getrandom_default);
285 	ATF_TP_ADD_TC(tp, getrandom_nonblock);
286 	ATF_TP_ADD_TC(tp, getrandom_insecure);
287 	ATF_TP_ADD_TC(tp, getrandom_insecure_nonblock);
288 	ATF_TP_ADD_TC(tp, getrandom_random);
289 	ATF_TP_ADD_TC(tp, getrandom_random_nonblock);
290 	ATF_TP_ADD_TC(tp, getrandom_random_insecure);
291 	ATF_TP_ADD_TC(tp, getrandom_random_insecure_nonblock);
292 	ATF_TP_ADD_TC(tp, getrandom_invalid);
293 	ATF_TP_ADD_TC(tp, getrandom_fault);
294 
295 	return atf_no_error();
296 }
297