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, ©.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, ©.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