xref: /netbsd-src/tests/lib/libc/gen/t_arc4random.c (revision 0d283a3a7ed9024e9a0b490e3ba1950a6e625f25)
1*0d283a3aSriastradh /*	$NetBSD: t_arc4random.c,v 1.1 2024/08/27 13:43:02 riastradh Exp $	*/
2*0d283a3aSriastradh 
3*0d283a3aSriastradh /*-
4*0d283a3aSriastradh  * Copyright (c) 2024 The NetBSD Foundation, Inc.
5*0d283a3aSriastradh  * All rights reserved.
6*0d283a3aSriastradh  *
7*0d283a3aSriastradh  * Redistribution and use in source and binary forms, with or without
8*0d283a3aSriastradh  * modification, are permitted provided that the following conditions
9*0d283a3aSriastradh  * are met:
10*0d283a3aSriastradh  * 1. Redistributions of source code must retain the above copyright
11*0d283a3aSriastradh  *    notice, this list of conditions and the following disclaimer.
12*0d283a3aSriastradh  * 2. Redistributions in binary form must reproduce the above copyright
13*0d283a3aSriastradh  *    notice, this list of conditions and the following disclaimer in the
14*0d283a3aSriastradh  *    documentation and/or other materials provided with the distribution.
15*0d283a3aSriastradh  *
16*0d283a3aSriastradh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17*0d283a3aSriastradh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18*0d283a3aSriastradh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19*0d283a3aSriastradh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20*0d283a3aSriastradh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*0d283a3aSriastradh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*0d283a3aSriastradh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*0d283a3aSriastradh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*0d283a3aSriastradh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*0d283a3aSriastradh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*0d283a3aSriastradh  * POSSIBILITY OF SUCH DAMAGE.
27*0d283a3aSriastradh  */
28*0d283a3aSriastradh 
29*0d283a3aSriastradh #define	_REENTRANT
30*0d283a3aSriastradh 
31*0d283a3aSriastradh #include <sys/cdefs.h>
32*0d283a3aSriastradh __RCSID("$NetBSD: t_arc4random.c,v 1.1 2024/08/27 13:43:02 riastradh Exp $");
33*0d283a3aSriastradh 
34*0d283a3aSriastradh #include <sys/resource.h>
35*0d283a3aSriastradh #include <sys/sysctl.h>
36*0d283a3aSriastradh #include <sys/wait.h>
37*0d283a3aSriastradh 
38*0d283a3aSriastradh #include <atf-c.h>
39*0d283a3aSriastradh #include <stdio.h>
40*0d283a3aSriastradh #include <string.h>
41*0d283a3aSriastradh #include <unistd.h>
42*0d283a3aSriastradh 
43*0d283a3aSriastradh #include "arc4random.h"
44*0d283a3aSriastradh #include "reentrant.h"
45*0d283a3aSriastradh #include "h_macros.h"
46*0d283a3aSriastradh 
47*0d283a3aSriastradh /*
48*0d283a3aSriastradh  * iszero(buf, len)
49*0d283a3aSriastradh  *
50*0d283a3aSriastradh  *	True if len bytes at buf are all zero, false if any one of them
51*0d283a3aSriastradh  *	is nonzero.
52*0d283a3aSriastradh  */
53*0d283a3aSriastradh static bool
54*0d283a3aSriastradh iszero(const void *buf, size_t len)
55*0d283a3aSriastradh {
56*0d283a3aSriastradh 	const unsigned char *p = buf;
57*0d283a3aSriastradh 	size_t i;
58*0d283a3aSriastradh 
59*0d283a3aSriastradh 	for (i = 0; i < len; i++) {
60*0d283a3aSriastradh 		if (p[i] != 0)
61*0d283a3aSriastradh 			return false;
62*0d283a3aSriastradh 	}
63*0d283a3aSriastradh 	return true;
64*0d283a3aSriastradh }
65*0d283a3aSriastradh 
66*0d283a3aSriastradh /*
67*0d283a3aSriastradh  * arc4random_prng()
68*0d283a3aSriastradh  *
69*0d283a3aSriastradh  *	Get a pointer to the current arc4random state, without updating
70*0d283a3aSriastradh  *	any of the state, not even lazy initialization.
71*0d283a3aSriastradh  */
72*0d283a3aSriastradh static struct arc4random_prng *
73*0d283a3aSriastradh arc4random_prng(void)
74*0d283a3aSriastradh {
75*0d283a3aSriastradh 	struct arc4random_prng *prng = NULL;
76*0d283a3aSriastradh 
77*0d283a3aSriastradh 	/*
78*0d283a3aSriastradh 	 * If arc4random has been initialized and there is a thread key
79*0d283a3aSriastradh 	 * (i.e., libc was built with _REENTRANT), get the thread-local
80*0d283a3aSriastradh 	 * arc4random state if there is one.
81*0d283a3aSriastradh 	 */
82*0d283a3aSriastradh 	if (arc4random_global.initialized)
83*0d283a3aSriastradh 		prng = thr_getspecific(arc4random_global.thread_key);
84*0d283a3aSriastradh 
85*0d283a3aSriastradh 	/*
86*0d283a3aSriastradh 	 * If we couldn't get the thread-local state, get the global
87*0d283a3aSriastradh 	 * state instead.
88*0d283a3aSriastradh 	 */
89*0d283a3aSriastradh 	if (prng == NULL)
90*0d283a3aSriastradh 		prng = &arc4random_global.prng;
91*0d283a3aSriastradh 
92*0d283a3aSriastradh 	return prng;
93*0d283a3aSriastradh }
94*0d283a3aSriastradh 
95*0d283a3aSriastradh /*
96*0d283a3aSriastradh  * arc4random_global_buf(buf, len)
97*0d283a3aSriastradh  *
98*0d283a3aSriastradh  *	Same as arc4random_buf, but force use of the global state.
99*0d283a3aSriastradh  *	Must happen before any other use of arc4random.
100*0d283a3aSriastradh  */
101*0d283a3aSriastradh static void
102*0d283a3aSriastradh arc4random_global_buf(void *buf, size_t len)
103*0d283a3aSriastradh {
104*0d283a3aSriastradh 	struct rlimit rlim, orlim;
105*0d283a3aSriastradh 	struct arc4random_prng *prng;
106*0d283a3aSriastradh 
107*0d283a3aSriastradh 	/*
108*0d283a3aSriastradh 	 * Save the address space limit.
109*0d283a3aSriastradh 	 */
110*0d283a3aSriastradh 	RL(getrlimit(RLIMIT_AS, &orlim));
111*0d283a3aSriastradh 	memcpy(&rlim, &orlim, sizeof(rlim));
112*0d283a3aSriastradh 
113*0d283a3aSriastradh 	/*
114*0d283a3aSriastradh 	 * Get a sample while the address space limit is zero.  This
115*0d283a3aSriastradh 	 * should try, and fail, to allocate a thread-local arc4random
116*0d283a3aSriastradh 	 * state with mmap(2).
117*0d283a3aSriastradh 	 */
118*0d283a3aSriastradh 	rlim.rlim_cur = 0;
119*0d283a3aSriastradh 	RL(setrlimit(RLIMIT_AS, &rlim));
120*0d283a3aSriastradh 	arc4random_buf(buf, len);
121*0d283a3aSriastradh 	RL(setrlimit(RLIMIT_AS, &orlim));
122*0d283a3aSriastradh 
123*0d283a3aSriastradh 	/*
124*0d283a3aSriastradh 	 * Restore the address space limit.
125*0d283a3aSriastradh 	 */
126*0d283a3aSriastradh 	RL(setrlimit(RLIMIT_AS, &orlim));
127*0d283a3aSriastradh 
128*0d283a3aSriastradh 	/*
129*0d283a3aSriastradh 	 * Verify the PRNG is the global one, not the thread-local one,
130*0d283a3aSriastradh 	 * and that it was initialized.
131*0d283a3aSriastradh 	 */
132*0d283a3aSriastradh 	prng = arc4random_prng();
133*0d283a3aSriastradh 	ATF_CHECK_EQ(prng, &arc4random_global.prng);
134*0d283a3aSriastradh 	ATF_CHECK(!iszero(&prng->arc4_prng, sizeof(prng->arc4_prng)));
135*0d283a3aSriastradh 	ATF_CHECK(prng->arc4_epoch != 0);
136*0d283a3aSriastradh }
137*0d283a3aSriastradh 
138*0d283a3aSriastradh /*
139*0d283a3aSriastradh  * arc4random_global_thread(cookie)
140*0d283a3aSriastradh  *
141*0d283a3aSriastradh  *	Start routine for a thread that just grabs an output from the
142*0d283a3aSriastradh  *	global state.
143*0d283a3aSriastradh  */
144*0d283a3aSriastradh static void *
145*0d283a3aSriastradh arc4random_global_thread(void *cookie)
146*0d283a3aSriastradh {
147*0d283a3aSriastradh 	unsigned char buf[32];
148*0d283a3aSriastradh 
149*0d283a3aSriastradh 	arc4random_global_buf(buf, sizeof(buf));
150*0d283a3aSriastradh 
151*0d283a3aSriastradh 	return NULL;
152*0d283a3aSriastradh }
153*0d283a3aSriastradh 
154*0d283a3aSriastradh ATF_TC(addrandom);
155*0d283a3aSriastradh ATF_TC_HEAD(addrandom, tc)
156*0d283a3aSriastradh {
157*0d283a3aSriastradh 	atf_tc_set_md_var(tc, "descr",
158*0d283a3aSriastradh 	    "Test arc4random_addrandom updates the state");
159*0d283a3aSriastradh }
160*0d283a3aSriastradh ATF_TC_BODY(addrandom, tc)
161*0d283a3aSriastradh {
162*0d283a3aSriastradh 	unsigned char buf[32], zero32[32] = {0};
163*0d283a3aSriastradh 	struct arc4random_prng *prng, copy;
164*0d283a3aSriastradh 
165*0d283a3aSriastradh 	/*
166*0d283a3aSriastradh 	 * Get a sample to start things off.
167*0d283a3aSriastradh 	 */
168*0d283a3aSriastradh 	arc4random_buf(buf, sizeof(buf));
169*0d283a3aSriastradh 	ATF_CHECK(!iszero(buf, sizeof(buf)));	/* Pr[fail] = 1/2^256 */
170*0d283a3aSriastradh 
171*0d283a3aSriastradh 	/*
172*0d283a3aSriastradh 	 * By this point, the global state must be initialized -- if
173*0d283a3aSriastradh 	 * not, the process should have aborted.
174*0d283a3aSriastradh 	 */
175*0d283a3aSriastradh 	ATF_CHECK(arc4random_global.initialized);
176*0d283a3aSriastradh 
177*0d283a3aSriastradh 	/*
178*0d283a3aSriastradh 	 * Get the PRNG, global or local.  By this point, the PRNG
179*0d283a3aSriastradh 	 * state should be nonzero (with overwhelmingly high
180*0d283a3aSriastradh 	 * probability) and the epoch should also be nonzero.
181*0d283a3aSriastradh 	 */
182*0d283a3aSriastradh 	prng = arc4random_prng();
183*0d283a3aSriastradh 	ATF_CHECK(!iszero(&prng->arc4_prng, sizeof(prng->arc4_prng)));
184*0d283a3aSriastradh 	ATF_CHECK(prng->arc4_epoch != 0);
185*0d283a3aSriastradh 
186*0d283a3aSriastradh 	/*
187*0d283a3aSriastradh 	 * Save a copy and update the state with arc4random_addrandom.
188*0d283a3aSriastradh 	 */
189*0d283a3aSriastradh 	copy = *prng;
190*0d283a3aSriastradh 	arc4random_addrandom(zero32, sizeof(zero32));
191*0d283a3aSriastradh 
192*0d283a3aSriastradh 	/*
193*0d283a3aSriastradh 	 * The state should have changed.  (The epoch may or may not.)
194*0d283a3aSriastradh 	 */
195*0d283a3aSriastradh 	ATF_CHECK(memcmp(&prng->arc4_prng, &copy.arc4_prng,
196*0d283a3aSriastradh 		sizeof(copy.arc4_prng)) != 0);
197*0d283a3aSriastradh 
198*0d283a3aSriastradh 	/*
199*0d283a3aSriastradh 	 * Save a copy and update the state with arc4random_stir.
200*0d283a3aSriastradh 	 */
201*0d283a3aSriastradh 	copy = *prng;
202*0d283a3aSriastradh 	arc4random_stir();
203*0d283a3aSriastradh 
204*0d283a3aSriastradh 	/*
205*0d283a3aSriastradh 	 * The state should have changed.  (The epoch may or may not.)
206*0d283a3aSriastradh 	 */
207*0d283a3aSriastradh 	ATF_CHECK(memcmp(&prng->arc4_prng, &copy.arc4_prng,
208*0d283a3aSriastradh 		sizeof(copy.arc4_prng)) != 0);
209*0d283a3aSriastradh }
210*0d283a3aSriastradh 
211*0d283a3aSriastradh ATF_TC(consolidate);
212*0d283a3aSriastradh ATF_TC_HEAD(consolidate, tc)
213*0d283a3aSriastradh {
214*0d283a3aSriastradh 	atf_tc_set_md_var(tc, "descr",
215*0d283a3aSriastradh 	    "Test consolidating entropy resets the epoch");
216*0d283a3aSriastradh }
217*0d283a3aSriastradh ATF_TC_BODY(consolidate, tc)
218*0d283a3aSriastradh {
219*0d283a3aSriastradh 	unsigned char buf[32];
220*0d283a3aSriastradh 	struct arc4random_prng *local, *global = &arc4random_global.prng;
221*0d283a3aSriastradh 	unsigned localepoch, globalepoch;
222*0d283a3aSriastradh 	const int consolidate = 1;
223*0d283a3aSriastradh 	pthread_t thread;
224*0d283a3aSriastradh 
225*0d283a3aSriastradh 	/*
226*0d283a3aSriastradh 	 * Get a sample from the global state to make sure the global
227*0d283a3aSriastradh 	 * state is initialized.  Remember the epoch.
228*0d283a3aSriastradh 	 */
229*0d283a3aSriastradh 	arc4random_global_buf(buf, sizeof(buf));
230*0d283a3aSriastradh 	ATF_CHECK(!iszero(buf, sizeof(buf)));	/* Pr[fail] = 1/2^256 */
231*0d283a3aSriastradh 	ATF_CHECK(!iszero(&global->arc4_prng, sizeof(global->arc4_prng)));
232*0d283a3aSriastradh 	ATF_CHECK((globalepoch = global->arc4_epoch) != 0);
233*0d283a3aSriastradh 
234*0d283a3aSriastradh 	/*
235*0d283a3aSriastradh 	 * Get a sample from the local state too to make sure the local
236*0d283a3aSriastradh 	 * state is initialized.  Remember the epoch.
237*0d283a3aSriastradh 	 */
238*0d283a3aSriastradh 	arc4random_buf(buf, sizeof(buf));
239*0d283a3aSriastradh 	ATF_CHECK(!iszero(buf, sizeof(buf)));	/* Pr[fail] = 1/2^256 */
240*0d283a3aSriastradh 	local = arc4random_prng();
241*0d283a3aSriastradh 	ATF_CHECK(!iszero(&local->arc4_prng, sizeof(local->arc4_prng)));
242*0d283a3aSriastradh 	ATF_CHECK((localepoch = local->arc4_epoch) != 0);
243*0d283a3aSriastradh 
244*0d283a3aSriastradh 	/*
245*0d283a3aSriastradh 	 * Trigger entropy consolidation.
246*0d283a3aSriastradh 	 */
247*0d283a3aSriastradh 	RL(sysctlbyname("kern.entropy.consolidate", /*oldp*/NULL, /*oldlen*/0,
248*0d283a3aSriastradh 		&consolidate, sizeof(consolidate)));
249*0d283a3aSriastradh 
250*0d283a3aSriastradh 	/*
251*0d283a3aSriastradh 	 * Verify the epoch cache isn't changed yet until we ask for
252*0d283a3aSriastradh 	 * more data.
253*0d283a3aSriastradh 	 */
254*0d283a3aSriastradh 	ATF_CHECK_EQ_MSG(globalepoch, global->arc4_epoch,
255*0d283a3aSriastradh 	    "global epoch was %u, now %u", globalepoch, global->arc4_epoch);
256*0d283a3aSriastradh 	ATF_CHECK_EQ_MSG(localepoch, local->arc4_epoch,
257*0d283a3aSriastradh 	    "local epoch was %u, now %u", localepoch, local->arc4_epoch);
258*0d283a3aSriastradh 
259*0d283a3aSriastradh 	/*
260*0d283a3aSriastradh 	 * Request new output and verify the local epoch cache has
261*0d283a3aSriastradh 	 * changed.
262*0d283a3aSriastradh 	 */
263*0d283a3aSriastradh 	arc4random_buf(buf, sizeof(buf));
264*0d283a3aSriastradh 	ATF_CHECK(!iszero(buf, sizeof(buf)));	/* Pr[fail] = 1/2^256 */
265*0d283a3aSriastradh 	ATF_CHECK_MSG(localepoch != local->arc4_epoch,
266*0d283a3aSriastradh 	    "local epoch unchanged from %u", localepoch);
267*0d283a3aSriastradh 
268*0d283a3aSriastradh 	/*
269*0d283a3aSriastradh 	 * Create a new thread to grab output from the global state,
270*0d283a3aSriastradh 	 * wait for it to complete, and verify the global epoch cache
271*0d283a3aSriastradh 	 * has changed.  (Now that we have already used the local state
272*0d283a3aSriastradh 	 * in this thread, we can't use the global state any more.)
273*0d283a3aSriastradh 	 */
274*0d283a3aSriastradh 	RZ(pthread_create(&thread, NULL, &arc4random_global_thread, NULL));
275*0d283a3aSriastradh 	RZ(pthread_join(thread, NULL));
276*0d283a3aSriastradh 	ATF_CHECK_MSG(globalepoch != global->arc4_epoch,
277*0d283a3aSriastradh 	    "global epoch unchanged from %u", globalepoch);
278*0d283a3aSriastradh }
279*0d283a3aSriastradh 
280*0d283a3aSriastradh ATF_TC(fork);
281*0d283a3aSriastradh ATF_TC_HEAD(fork, tc)
282*0d283a3aSriastradh {
283*0d283a3aSriastradh 	atf_tc_set_md_var(tc, "descr",
284*0d283a3aSriastradh 	    "Test fork zeros the state and gets independent state");
285*0d283a3aSriastradh }
286*0d283a3aSriastradh ATF_TC_BODY(fork, tc)
287*0d283a3aSriastradh {
288*0d283a3aSriastradh 	unsigned char buf[32];
289*0d283a3aSriastradh 	struct arc4random_prng *local, *global = &arc4random_global.prng;
290*0d283a3aSriastradh 	struct arc4random_prng childstate;
291*0d283a3aSriastradh 	int fd[2];
292*0d283a3aSriastradh 	pid_t child, pid;
293*0d283a3aSriastradh 	ssize_t nread;
294*0d283a3aSriastradh 	int status;
295*0d283a3aSriastradh 
296*0d283a3aSriastradh 	/*
297*0d283a3aSriastradh 	 * Get a sample from the global state to make sure the global
298*0d283a3aSriastradh 	 * state is initialized.
299*0d283a3aSriastradh 	 */
300*0d283a3aSriastradh 	arc4random_global_buf(buf, sizeof(buf));
301*0d283a3aSriastradh 	ATF_CHECK(!iszero(buf, sizeof(buf)));	/* Pr[fail] = 1/2^256 */
302*0d283a3aSriastradh 	ATF_CHECK(!iszero(&global->arc4_prng, sizeof(global->arc4_prng)));
303*0d283a3aSriastradh 	ATF_CHECK(global->arc4_epoch != 0);
304*0d283a3aSriastradh 
305*0d283a3aSriastradh 	/*
306*0d283a3aSriastradh 	 * Get a sample from the local state too to make sure the local
307*0d283a3aSriastradh 	 * state is initialized.
308*0d283a3aSriastradh 	 */
309*0d283a3aSriastradh 	arc4random_buf(buf, sizeof(buf));
310*0d283a3aSriastradh 	ATF_CHECK(!iszero(buf, sizeof(buf)));	/* Pr[fail] = 1/2^256 */
311*0d283a3aSriastradh 	local = arc4random_prng();
312*0d283a3aSriastradh 	ATF_CHECK(!iszero(&local->arc4_prng, sizeof(local->arc4_prng)));
313*0d283a3aSriastradh 	ATF_CHECK(local->arc4_epoch != 0);
314*0d283a3aSriastradh 
315*0d283a3aSriastradh 	/*
316*0d283a3aSriastradh 	 * Create a pipe to transfer the state from child to parent.
317*0d283a3aSriastradh 	 */
318*0d283a3aSriastradh 	RL(pipe(fd));
319*0d283a3aSriastradh 
320*0d283a3aSriastradh 	/*
321*0d283a3aSriastradh 	 * Fork a child.
322*0d283a3aSriastradh 	 */
323*0d283a3aSriastradh 	RL(child = fork());
324*0d283a3aSriastradh 	if (child == 0) {
325*0d283a3aSriastradh 		status = 0;
326*0d283a3aSriastradh 
327*0d283a3aSriastradh 		/*
328*0d283a3aSriastradh 		 * Verify the states have been zero'd on fork.
329*0d283a3aSriastradh 		 */
330*0d283a3aSriastradh 		if (!iszero(local, sizeof(*local))) {
331*0d283a3aSriastradh 			fprintf(stderr, "failed to zero local state\n");
332*0d283a3aSriastradh 			status = 1;
333*0d283a3aSriastradh 		}
334*0d283a3aSriastradh 		if (!iszero(global, sizeof(*global))) {
335*0d283a3aSriastradh 			fprintf(stderr, "failed to zero global state\n");
336*0d283a3aSriastradh 			status = 1;
337*0d283a3aSriastradh 		}
338*0d283a3aSriastradh 
339*0d283a3aSriastradh 		/*
340*0d283a3aSriastradh 		 * Verify we generate nonzero output.
341*0d283a3aSriastradh 		 */
342*0d283a3aSriastradh 		arc4random_buf(buf, sizeof(buf));
343*0d283a3aSriastradh 		if (iszero(buf, sizeof(buf))) {
344*0d283a3aSriastradh 			fprintf(stderr, "failed to generate nonzero output\n");
345*0d283a3aSriastradh 			status = 1;
346*0d283a3aSriastradh 		}
347*0d283a3aSriastradh 
348*0d283a3aSriastradh 		/*
349*0d283a3aSriastradh 		 * Share the state to compare with parent.
350*0d283a3aSriastradh 		 */
351*0d283a3aSriastradh 		if ((size_t)write(fd[1], local, sizeof(*local)) !=
352*0d283a3aSriastradh 		    sizeof(*local)) {
353*0d283a3aSriastradh 			fprintf(stderr, "failed to share local state\n");
354*0d283a3aSriastradh 			status = 1;
355*0d283a3aSriastradh 		}
356*0d283a3aSriastradh 		_exit(status);
357*0d283a3aSriastradh 	}
358*0d283a3aSriastradh 
359*0d283a3aSriastradh 	/*
360*0d283a3aSriastradh 	 * Verify the global state has been zeroed as expected.  (This
361*0d283a3aSriastradh 	 * way it is never available to the child, even shortly after
362*0d283a3aSriastradh 	 * the fork syscall returns before the atfork handler is
363*0d283a3aSriastradh 	 * called.)
364*0d283a3aSriastradh 	 */
365*0d283a3aSriastradh 	ATF_CHECK(iszero(global, sizeof(*global)));
366*0d283a3aSriastradh 
367*0d283a3aSriastradh 	/*
368*0d283a3aSriastradh 	 * Read the state from the child.
369*0d283a3aSriastradh 	 */
370*0d283a3aSriastradh 	RL(nread = read(fd[0], &childstate, sizeof(childstate)));
371*0d283a3aSriastradh 	ATF_CHECK_EQ_MSG(nread, sizeof(childstate),
372*0d283a3aSriastradh 	    "nread=%zu sizeof(childstate)=%zu", nread, sizeof(childstate));
373*0d283a3aSriastradh 
374*0d283a3aSriastradh 	/*
375*0d283a3aSriastradh 	 * Verify the child state is distinct.  (The global state has
376*0d283a3aSriastradh 	 * been zero'd so it's OK it if coincides.)  Check again after
377*0d283a3aSriastradh 	 * we grab another output.
378*0d283a3aSriastradh 	 */
379*0d283a3aSriastradh 	ATF_CHECK(memcmp(local, &childstate, sizeof(*local)) != 0);
380*0d283a3aSriastradh 	arc4random_buf(buf, sizeof(buf));
381*0d283a3aSriastradh 	ATF_CHECK(!iszero(buf, sizeof(buf)));	/* Pr[fail] = 1/2^256 */
382*0d283a3aSriastradh 	ATF_CHECK(memcmp(local, &childstate, sizeof(*local)) != 0);
383*0d283a3aSriastradh 
384*0d283a3aSriastradh 	/*
385*0d283a3aSriastradh 	 * Wait for the child to complete and verify it passed.
386*0d283a3aSriastradh 	 */
387*0d283a3aSriastradh 	RL(pid = waitpid(child, &status, 0));
388*0d283a3aSriastradh 	ATF_CHECK_EQ_MSG(status, 0, "child exited with nonzero status=%d",
389*0d283a3aSriastradh 	    status);
390*0d283a3aSriastradh }
391*0d283a3aSriastradh 
392*0d283a3aSriastradh ATF_TC(global);
393*0d283a3aSriastradh ATF_TC_HEAD(global, tc)
394*0d283a3aSriastradh {
395*0d283a3aSriastradh 	atf_tc_set_md_var(tc, "descr",
396*0d283a3aSriastradh 	    "Test the global state is used when address space limit is hit");
397*0d283a3aSriastradh }
398*0d283a3aSriastradh ATF_TC_BODY(global, tc)
399*0d283a3aSriastradh {
400*0d283a3aSriastradh 	unsigned char buf[32], buf1[32];
401*0d283a3aSriastradh 
402*0d283a3aSriastradh 	/*
403*0d283a3aSriastradh 	 * Get a sample from the global state (and verify it was using
404*0d283a3aSriastradh 	 * the global state).
405*0d283a3aSriastradh 	 */
406*0d283a3aSriastradh 	arc4random_global_buf(buf, sizeof(buf));
407*0d283a3aSriastradh 
408*0d283a3aSriastradh 	/*
409*0d283a3aSriastradh 	 * Verify we got a sample.
410*0d283a3aSriastradh 	 */
411*0d283a3aSriastradh 	ATF_CHECK(!iszero(buf, sizeof(buf)));	/* Pr[fail] = 1/2^256 */
412*0d283a3aSriastradh 
413*0d283a3aSriastradh 	/*
414*0d283a3aSriastradh 	 * Get a sample from whatever state and make sure it wasn't
415*0d283a3aSriastradh 	 * repeated, which happens only with probability 1/2^256.
416*0d283a3aSriastradh 	 */
417*0d283a3aSriastradh 	arc4random_buf(buf1, sizeof(buf1));
418*0d283a3aSriastradh 	ATF_CHECK(!iszero(buf1, sizeof(buf1)));	/* Pr[fail] = 1/2^256 */
419*0d283a3aSriastradh 	ATF_CHECK(memcmp(buf, buf1, sizeof(buf)) != 0);
420*0d283a3aSriastradh }
421*0d283a3aSriastradh 
422*0d283a3aSriastradh ATF_TC(local);
423*0d283a3aSriastradh ATF_TC_HEAD(local, tc)
424*0d283a3aSriastradh {
425*0d283a3aSriastradh 	atf_tc_set_md_var(tc, "descr",
426*0d283a3aSriastradh 	    "Test arc4random uses thread-local state");
427*0d283a3aSriastradh 	/* XXX skip if libc was built without _REENTRANT */
428*0d283a3aSriastradh }
429*0d283a3aSriastradh ATF_TC_BODY(local, tc)
430*0d283a3aSriastradh {
431*0d283a3aSriastradh 	unsigned char buf[32], buf1[32];
432*0d283a3aSriastradh 	struct arc4random_prng *prng;
433*0d283a3aSriastradh 
434*0d283a3aSriastradh 	/*
435*0d283a3aSriastradh 	 * Get a sample to start things off.
436*0d283a3aSriastradh 	 */
437*0d283a3aSriastradh 	arc4random_buf(buf, sizeof(buf));
438*0d283a3aSriastradh 	ATF_CHECK(!iszero(buf, sizeof(buf)));	/* Pr[fail] = 1/2^256 */
439*0d283a3aSriastradh 
440*0d283a3aSriastradh 	/*
441*0d283a3aSriastradh 	 * Verify the arc4random state is _not_ the global state.
442*0d283a3aSriastradh 	 */
443*0d283a3aSriastradh 	prng = arc4random_prng();
444*0d283a3aSriastradh 	ATF_CHECK(prng != &arc4random_global.prng);
445*0d283a3aSriastradh 	ATF_CHECK(!iszero(&prng->arc4_prng, sizeof(prng->arc4_prng)));
446*0d283a3aSriastradh 	ATF_CHECK(prng->arc4_epoch != 0);
447*0d283a3aSriastradh 
448*0d283a3aSriastradh 	/*
449*0d283a3aSriastradh 	 * Get another sample and make sure it wasn't repeated, which
450*0d283a3aSriastradh 	 * happens only with probability 1/2^256.
451*0d283a3aSriastradh 	 */
452*0d283a3aSriastradh 	arc4random_buf(buf1, sizeof(buf1));
453*0d283a3aSriastradh 	ATF_CHECK(!iszero(buf1, sizeof(buf1)));	/* Pr[fail] = 1/2^256 */
454*0d283a3aSriastradh 	ATF_CHECK(memcmp(buf, buf1, sizeof(buf)) != 0);
455*0d283a3aSriastradh }
456*0d283a3aSriastradh 
457*0d283a3aSriastradh ATF_TP_ADD_TCS(tp)
458*0d283a3aSriastradh {
459*0d283a3aSriastradh 
460*0d283a3aSriastradh 	ATF_TP_ADD_TC(tp, addrandom);
461*0d283a3aSriastradh 	ATF_TP_ADD_TC(tp, consolidate);
462*0d283a3aSriastradh 	ATF_TP_ADD_TC(tp, fork);
463*0d283a3aSriastradh 	ATF_TP_ADD_TC(tp, global);
464*0d283a3aSriastradh 	ATF_TP_ADD_TC(tp, local);
465*0d283a3aSriastradh 
466*0d283a3aSriastradh 	return atf_no_error();
467*0d283a3aSriastradh }
468