13f15e290Smatthew /*
23f15e290Smatthew  * Copyright (c) 2014 Google Inc.
33f15e290Smatthew  *
43f15e290Smatthew  * Permission to use, copy, modify, and distribute this software for any
53f15e290Smatthew  * purpose with or without fee is hereby granted, provided that the above
63f15e290Smatthew  * copyright notice and this permission notice appear in all copies.
73f15e290Smatthew  *
83f15e290Smatthew  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
93f15e290Smatthew  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
103f15e290Smatthew  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
113f15e290Smatthew  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
123f15e290Smatthew  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
133f15e290Smatthew  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
143f15e290Smatthew  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
153f15e290Smatthew  */
163f15e290Smatthew 
173f15e290Smatthew #include <sys/mman.h>
183f15e290Smatthew #include <sys/wait.h>
193f15e290Smatthew #include <assert.h>
203f15e290Smatthew #include <err.h>
216f639c86Sbcook #include <errno.h>
225a11c7edSmatthew #include <signal.h>
233f15e290Smatthew #include <stdlib.h>
243f15e290Smatthew #include <string.h>
253f15e290Smatthew #include <unistd.h>
26*7df9a849Smiod #include <stdint.h>
273f15e290Smatthew 
283f15e290Smatthew #define CHECK(x) assert(x)
293f15e290Smatthew #define CHECK_EQ(a, b) assert((a) == (b))
303f15e290Smatthew #define CHECK_NE(a, b) assert((a) != (b))
313f15e290Smatthew #define CHECK_GE(a, b) assert((a) >= (b))
323f15e290Smatthew #define CHECK_LE(a, b) assert((a) <= (b))
333f15e290Smatthew 
343f15e290Smatthew /* Test arc4random_buf(3) instead of arc4random(3). */
353f15e290Smatthew static int flagbuf;
363f15e290Smatthew 
373f15e290Smatthew /* Initialize arc4random(3) before forking. */
383f15e290Smatthew static int flagprefork;
393f15e290Smatthew 
403f15e290Smatthew enum {
413f15e290Smatthew 	N = 4096
423f15e290Smatthew };
433f15e290Smatthew 
443f15e290Smatthew typedef struct {
453f15e290Smatthew 	uint32_t x[N];
463f15e290Smatthew } Buf;
473f15e290Smatthew 
483f15e290Smatthew static int
isfullbuf(const Buf * buf)493f15e290Smatthew isfullbuf(const Buf *buf)
503f15e290Smatthew {
513f15e290Smatthew 	size_t i;
523f15e290Smatthew 	for (i = 0; i < N; i++)
533f15e290Smatthew 		if (buf->x[i])
543f15e290Smatthew 			return (1);
553f15e290Smatthew 	return (0);
563f15e290Smatthew }
573f15e290Smatthew 
583f15e290Smatthew static void
fillbuf(Buf * buf)593f15e290Smatthew fillbuf(Buf *buf)
603f15e290Smatthew {
613f15e290Smatthew 	if (flagbuf) {
623f15e290Smatthew 		arc4random_buf(buf->x, sizeof(buf->x));
633f15e290Smatthew 	} else {
643f15e290Smatthew 		size_t i;
653f15e290Smatthew 		for (i = 0; i < N; i++)
663f15e290Smatthew 			buf->x[i] = arc4random();
673f15e290Smatthew 	}
683f15e290Smatthew }
693f15e290Smatthew 
703f15e290Smatthew static void
usage()713f15e290Smatthew usage()
723f15e290Smatthew {
738c18f9d1Sbcook 	errx(1, "usage: arc4random-fork [-bp]");
743f15e290Smatthew }
753f15e290Smatthew 
766f639c86Sbcook static pid_t
safewaitpid(pid_t pid,int * status,int options)775a11c7edSmatthew safewaitpid(pid_t pid, int *status, int options)
786f639c86Sbcook {
796f639c86Sbcook 	pid_t ret;
806f639c86Sbcook 	do {
815a11c7edSmatthew 		ret = waitpid(pid, status, options);
826f639c86Sbcook 	} while (ret == -1 && errno == EINTR);
835a11c7edSmatthew 	return (ret);
846f639c86Sbcook }
856f639c86Sbcook 
863f15e290Smatthew int
main(int argc,char * argv[])873f15e290Smatthew main(int argc, char *argv[])
883f15e290Smatthew {
893f15e290Smatthew 	int opt, status;
903f15e290Smatthew 	Buf *bufparent, *bufchildone, *bufchildtwo;
913f15e290Smatthew 	pid_t pidone, pidtwo;
923f15e290Smatthew 	size_t i, countone = 0, counttwo = 0, countkids = 0;
933f15e290Smatthew 
945a11c7edSmatthew 	/* Ensure SIGCHLD isn't set to SIG_IGN. */
955a11c7edSmatthew 	const struct sigaction sa = {
965a11c7edSmatthew 		.sa_handler = SIG_DFL,
975a11c7edSmatthew 	};
985a11c7edSmatthew 	CHECK_EQ(0, sigaction(SIGCHLD, &sa, NULL));
995a11c7edSmatthew 
1003f15e290Smatthew 	while ((opt = getopt(argc, argv, "bp")) != -1) {
1013f15e290Smatthew 		switch (opt) {
1023f15e290Smatthew 		case 'b':
1033f15e290Smatthew 			flagbuf = 1;
1043f15e290Smatthew 			break;
1053f15e290Smatthew 		case 'p':
1063f15e290Smatthew 			flagprefork = 1;
1073f15e290Smatthew 			break;
1083f15e290Smatthew 		default:
1093f15e290Smatthew 			usage();
1103f15e290Smatthew 		}
1113f15e290Smatthew 	}
1123f15e290Smatthew 
1133f15e290Smatthew 	if (flagprefork)
1143f15e290Smatthew 		arc4random();
1153f15e290Smatthew 
1163f15e290Smatthew 	bufparent = mmap(NULL, sizeof(Buf), PROT_READ|PROT_WRITE,
1173f15e290Smatthew 	    MAP_ANON|MAP_PRIVATE, -1, 0);
1183f15e290Smatthew 	CHECK_NE(MAP_FAILED, bufparent);
1193f15e290Smatthew 
1203f15e290Smatthew 	bufchildone = mmap(NULL, sizeof(Buf), PROT_READ|PROT_WRITE,
1213f15e290Smatthew 	    MAP_ANON|MAP_SHARED, -1, 0);
1223f15e290Smatthew 	CHECK_NE(MAP_FAILED, bufchildone);
1233f15e290Smatthew 
1243f15e290Smatthew 	bufchildtwo = mmap(NULL, sizeof(Buf), PROT_READ|PROT_WRITE,
1253f15e290Smatthew 	    MAP_ANON|MAP_SHARED, -1, 0);
1263f15e290Smatthew 	CHECK_NE(MAP_FAILED, bufchildtwo);
1273f15e290Smatthew 
1283f15e290Smatthew 	pidone = fork();
1293f15e290Smatthew 	CHECK_GE(pidone, 0);
1303f15e290Smatthew 	if (pidone == 0) {
1313f15e290Smatthew 		fillbuf(bufchildone);
1323f15e290Smatthew 		_exit(0);
1333f15e290Smatthew 	}
1343f15e290Smatthew 
1353f15e290Smatthew 	pidtwo = fork();
1363f15e290Smatthew 	CHECK_GE(pidtwo, 0);
1373f15e290Smatthew 	if (pidtwo == 0) {
1383f15e290Smatthew 		fillbuf(bufchildtwo);
1393f15e290Smatthew 		_exit(0);
1403f15e290Smatthew 	}
1413f15e290Smatthew 
1423f15e290Smatthew 	fillbuf(bufparent);
1433f15e290Smatthew 
1445a11c7edSmatthew 	CHECK_EQ(pidone, safewaitpid(pidone, &status, 0));
1453f15e290Smatthew 	CHECK(WIFEXITED(status));
1463f15e290Smatthew 	CHECK_EQ(0, WEXITSTATUS(status));
1473f15e290Smatthew 
1485a11c7edSmatthew 	CHECK_EQ(pidtwo, safewaitpid(pidtwo, &status, 0));
1493f15e290Smatthew 	CHECK(WIFEXITED(status));
1503f15e290Smatthew 	CHECK_EQ(0, WEXITSTATUS(status));
1513f15e290Smatthew 
1523f15e290Smatthew 	CHECK(isfullbuf(bufchildone));
1533f15e290Smatthew 	CHECK(isfullbuf(bufchildtwo));
1543f15e290Smatthew 
1553f15e290Smatthew 	for (i = 0; i < N; i++) {
1563f15e290Smatthew 		countone += bufparent->x[i] == bufchildone->x[i];
1573f15e290Smatthew 		counttwo += bufparent->x[i] == bufchildtwo->x[i];
1583f15e290Smatthew 		countkids += bufchildone->x[i] == bufchildtwo->x[i];
1593f15e290Smatthew 	}
1603f15e290Smatthew 
1613f15e290Smatthew 	/*
1623f15e290Smatthew 	 * These checks are inherently probabilistic and theoretically risk
1633f15e290Smatthew 	 * flaking, but there's less than a 1 in 2^40 chance of more than
1643f15e290Smatthew 	 * one pairwise match between two vectors of 4096 32-bit integers.
1653f15e290Smatthew 	 */
1663f15e290Smatthew 	CHECK_LE(countone, 1);
1673f15e290Smatthew 	CHECK_LE(counttwo, 1);
1683f15e290Smatthew 	CHECK_LE(countkids, 1);
1693f15e290Smatthew 
1703f15e290Smatthew 	return (0);
1713f15e290Smatthew }
172