xref: /openbsd-src/regress/lib/libc/arc4random-fork/arc4random-fork.c (revision e5157e49389faebcb42b7237d55fbf096d9c2523)
1 /*
2  * Copyright (c) 2014 Google Inc.
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <sys/mman.h>
18 #include <sys/wait.h>
19 #include <assert.h>
20 #include <err.h>
21 #include <errno.h>
22 #include <signal.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #define CHECK(x) assert(x)
28 #define CHECK_EQ(a, b) assert((a) == (b))
29 #define CHECK_NE(a, b) assert((a) != (b))
30 #define CHECK_GE(a, b) assert((a) >= (b))
31 #define CHECK_LE(a, b) assert((a) <= (b))
32 
33 /* Test arc4random_buf(3) instead of arc4random(3). */
34 static int flagbuf;
35 
36 /* Initialize arc4random(3) before forking. */
37 static int flagprefork;
38 
39 enum {
40 	N = 4096
41 };
42 
43 typedef struct {
44 	uint32_t x[N];
45 } Buf;
46 
47 static int
48 isfullbuf(const Buf *buf)
49 {
50 	size_t i;
51 	for (i = 0; i < N; i++)
52 		if (buf->x[i])
53 			return (1);
54 	return (0);
55 }
56 
57 static void
58 fillbuf(Buf *buf)
59 {
60 	if (flagbuf) {
61 		arc4random_buf(buf->x, sizeof(buf->x));
62 	} else {
63 		size_t i;
64 		for (i = 0; i < N; i++)
65 			buf->x[i] = arc4random();
66 	}
67 }
68 
69 static void
70 usage()
71 {
72 	errx(1, "usage: arc4random-fork [-bp]");
73 }
74 
75 static pid_t
76 safewaitpid(pid_t pid, int *status, int options)
77 {
78 	pid_t ret;
79 	do {
80 		ret = waitpid(pid, status, options);
81 	} while (ret == -1 && errno == EINTR);
82 	return (ret);
83 }
84 
85 int
86 main(int argc, char *argv[])
87 {
88 	int opt, status;
89 	Buf *bufparent, *bufchildone, *bufchildtwo;
90 	pid_t pidone, pidtwo;
91 	size_t i, countone = 0, counttwo = 0, countkids = 0;
92 
93 	/* Ensure SIGCHLD isn't set to SIG_IGN. */
94 	const struct sigaction sa = {
95 		.sa_handler = SIG_DFL,
96 	};
97 	CHECK_EQ(0, sigaction(SIGCHLD, &sa, NULL));
98 
99 	while ((opt = getopt(argc, argv, "bp")) != -1) {
100 		switch (opt) {
101 		case 'b':
102 			flagbuf = 1;
103 			break;
104 		case 'p':
105 			flagprefork = 1;
106 			break;
107 		default:
108 			usage();
109 		}
110 	}
111 
112 	if (flagprefork)
113 		arc4random();
114 
115 	bufparent = mmap(NULL, sizeof(Buf), PROT_READ|PROT_WRITE,
116 	    MAP_ANON|MAP_PRIVATE, -1, 0);
117 	CHECK_NE(MAP_FAILED, bufparent);
118 
119 	bufchildone = mmap(NULL, sizeof(Buf), PROT_READ|PROT_WRITE,
120 	    MAP_ANON|MAP_SHARED, -1, 0);
121 	CHECK_NE(MAP_FAILED, bufchildone);
122 
123 	bufchildtwo = mmap(NULL, sizeof(Buf), PROT_READ|PROT_WRITE,
124 	    MAP_ANON|MAP_SHARED, -1, 0);
125 	CHECK_NE(MAP_FAILED, bufchildtwo);
126 
127 	pidone = fork();
128 	CHECK_GE(pidone, 0);
129 	if (pidone == 0) {
130 		fillbuf(bufchildone);
131 		_exit(0);
132 	}
133 
134 	pidtwo = fork();
135 	CHECK_GE(pidtwo, 0);
136 	if (pidtwo == 0) {
137 		fillbuf(bufchildtwo);
138 		_exit(0);
139 	}
140 
141 	fillbuf(bufparent);
142 
143 	CHECK_EQ(pidone, safewaitpid(pidone, &status, 0));
144 	CHECK(WIFEXITED(status));
145 	CHECK_EQ(0, WEXITSTATUS(status));
146 
147 	CHECK_EQ(pidtwo, safewaitpid(pidtwo, &status, 0));
148 	CHECK(WIFEXITED(status));
149 	CHECK_EQ(0, WEXITSTATUS(status));
150 
151 	CHECK(isfullbuf(bufchildone));
152 	CHECK(isfullbuf(bufchildtwo));
153 
154 	for (i = 0; i < N; i++) {
155 		countone += bufparent->x[i] == bufchildone->x[i];
156 		counttwo += bufparent->x[i] == bufchildtwo->x[i];
157 		countkids += bufchildone->x[i] == bufchildtwo->x[i];
158 	}
159 
160 	/*
161 	 * These checks are inherently probabilistic and theoretically risk
162 	 * flaking, but there's less than a 1 in 2^40 chance of more than
163 	 * one pairwise match between two vectors of 4096 32-bit integers.
164 	 */
165 	CHECK_LE(countone, 1);
166 	CHECK_LE(counttwo, 1);
167 	CHECK_LE(countkids, 1);
168 
169 	return (0);
170 }
171