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
45static uint8_t buf[65536];
46static uint8_t zero24[24];
47
48static void
49alarm_handler(int signo)
50{
51
52	fprintf(stderr, "timeout\n");
53}
54
55static void
56install_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
76ATF_TC(getrandom_default);
77ATF_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}
82ATF_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
102ATF_TC(getrandom_nonblock);
103ATF_TC_HEAD(getrandom_nonblock, tc)
104{
105	atf_tc_set_md_var(tc, "descr", "getrandom(..., GRND_NONBLOCK)");
106}
107ATF_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
124ATF_TC(getrandom_insecure);
125ATF_TC_HEAD(getrandom_insecure, tc)
126{
127	atf_tc_set_md_var(tc, "descr", "getrandom(..., GRND_INSECURE)");
128}
129ATF_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
143ATF_TC(getrandom_insecure_nonblock);
144ATF_TC_HEAD(getrandom_insecure_nonblock, tc)
145{
146	atf_tc_set_md_var(tc, "descr",
147	    "getrandom(..., GRND_INSECURE|GRND_NONBLOCK)");
148}
149ATF_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
163ATF_TC(getrandom_random);
164ATF_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}
169ATF_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
191ATF_TC(getrandom_random_nonblock);
192ATF_TC_HEAD(getrandom_random_nonblock, tc)
193{
194	atf_tc_set_md_var(tc, "descr",
195	    "getrandom(..., GRND_RANDOM|GRND_NONBLOCK)");
196}
197ATF_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
216ATF_TC(getrandom_random_insecure);
217ATF_TC_HEAD(getrandom_random_insecure, tc)
218{
219	atf_tc_set_md_var(tc, "descr",
220	    "getrandom(..., GRND_RANDOM|GRND_INSECURE)");
221}
222ATF_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
232ATF_TC(getrandom_random_insecure_nonblock);
233ATF_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}
238ATF_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
249ATF_TC(getrandom_invalid);
250ATF_TC_HEAD(getrandom_invalid, tc)
251{
252	atf_tc_set_md_var(tc, "descr", "getrandom(..., <invalid>)");
253}
254ATF_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
266ATF_TC(getrandom_fault);
267ATF_TC_HEAD(getrandom_fault, tc)
268{
269	atf_tc_set_md_var(tc, "descr", "getrandom(NULL, ...)");
270}
271ATF_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
281ATF_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