xref: /freebsd/contrib/unbound/compat/getentropy_osx.c (revision ff8258499cd4a5a2a522c985cd7592a7904d973f)
1*ff825849SDag-Erling Smørgrav /*	$OpenBSD: getentropy_osx.c,v 1.3 2014/07/12 14:48:00 deraadt Exp $	*/
2*ff825849SDag-Erling Smørgrav 
3*ff825849SDag-Erling Smørgrav /*
4*ff825849SDag-Erling Smørgrav  * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org>
5*ff825849SDag-Erling Smørgrav  * Copyright (c) 2014 Bob Beck <beck@obtuse.com>
6*ff825849SDag-Erling Smørgrav  *
7*ff825849SDag-Erling Smørgrav  * Permission to use, copy, modify, and distribute this software for any
8*ff825849SDag-Erling Smørgrav  * purpose with or without fee is hereby granted, provided that the above
9*ff825849SDag-Erling Smørgrav  * copyright notice and this permission notice appear in all copies.
10*ff825849SDag-Erling Smørgrav  *
11*ff825849SDag-Erling Smørgrav  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12*ff825849SDag-Erling Smørgrav  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13*ff825849SDag-Erling Smørgrav  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14*ff825849SDag-Erling Smørgrav  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15*ff825849SDag-Erling Smørgrav  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16*ff825849SDag-Erling Smørgrav  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17*ff825849SDag-Erling Smørgrav  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18*ff825849SDag-Erling Smørgrav  */
19*ff825849SDag-Erling Smørgrav #include "config.h"
20*ff825849SDag-Erling Smørgrav 
21*ff825849SDag-Erling Smørgrav #include <sys/types.h>
22*ff825849SDag-Erling Smørgrav #include <sys/param.h>
23*ff825849SDag-Erling Smørgrav #include <sys/ioctl.h>
24*ff825849SDag-Erling Smørgrav #include <sys/resource.h>
25*ff825849SDag-Erling Smørgrav #include <sys/syscall.h>
26*ff825849SDag-Erling Smørgrav #include <sys/sysctl.h>
27*ff825849SDag-Erling Smørgrav #include <sys/statvfs.h>
28*ff825849SDag-Erling Smørgrav #include <sys/socket.h>
29*ff825849SDag-Erling Smørgrav #include <sys/mount.h>
30*ff825849SDag-Erling Smørgrav #include <sys/mman.h>
31*ff825849SDag-Erling Smørgrav #include <sys/stat.h>
32*ff825849SDag-Erling Smørgrav #include <sys/time.h>
33*ff825849SDag-Erling Smørgrav #include <stdlib.h>
34*ff825849SDag-Erling Smørgrav #include <stdint.h>
35*ff825849SDag-Erling Smørgrav #include <stdio.h>
36*ff825849SDag-Erling Smørgrav #include <termios.h>
37*ff825849SDag-Erling Smørgrav #include <fcntl.h>
38*ff825849SDag-Erling Smørgrav #include <signal.h>
39*ff825849SDag-Erling Smørgrav #include <string.h>
40*ff825849SDag-Erling Smørgrav #include <errno.h>
41*ff825849SDag-Erling Smørgrav #include <unistd.h>
42*ff825849SDag-Erling Smørgrav #include <time.h>
43*ff825849SDag-Erling Smørgrav #include <mach/mach_time.h>
44*ff825849SDag-Erling Smørgrav #include <mach/mach_host.h>
45*ff825849SDag-Erling Smørgrav #include <mach/host_info.h>
46*ff825849SDag-Erling Smørgrav #include <sys/socketvar.h>
47*ff825849SDag-Erling Smørgrav #include <sys/vmmeter.h>
48*ff825849SDag-Erling Smørgrav #include <netinet/in.h>
49*ff825849SDag-Erling Smørgrav #include <netinet/tcp.h>
50*ff825849SDag-Erling Smørgrav #include <netinet/udp.h>
51*ff825849SDag-Erling Smørgrav #include <netinet/ip_var.h>
52*ff825849SDag-Erling Smørgrav #include <netinet/tcp_var.h>
53*ff825849SDag-Erling Smørgrav #include <netinet/udp_var.h>
54*ff825849SDag-Erling Smørgrav #include <CommonCrypto/CommonDigest.h>
55*ff825849SDag-Erling Smørgrav #define SHA512_Update(a, b, c)	(CC_SHA512_Update((a), (b), (c)))
56*ff825849SDag-Erling Smørgrav #define SHA512_Init(xxx) (CC_SHA512_Init((xxx)))
57*ff825849SDag-Erling Smørgrav #define SHA512_Final(xxx, yyy) (CC_SHA512_Final((xxx), (yyy)))
58*ff825849SDag-Erling Smørgrav #define SHA512_CTX CC_SHA512_CTX
59*ff825849SDag-Erling Smørgrav #define SHA512_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH
60*ff825849SDag-Erling Smørgrav 
61*ff825849SDag-Erling Smørgrav #define REPEAT 5
62*ff825849SDag-Erling Smørgrav #define min(a, b) (((a) < (b)) ? (a) : (b))
63*ff825849SDag-Erling Smørgrav 
64*ff825849SDag-Erling Smørgrav #define HX(a, b) \
65*ff825849SDag-Erling Smørgrav 	do { \
66*ff825849SDag-Erling Smørgrav 		if ((a)) \
67*ff825849SDag-Erling Smørgrav 			HD(errno); \
68*ff825849SDag-Erling Smørgrav 		else \
69*ff825849SDag-Erling Smørgrav 			HD(b); \
70*ff825849SDag-Erling Smørgrav 	} while (0)
71*ff825849SDag-Erling Smørgrav 
72*ff825849SDag-Erling Smørgrav #define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
73*ff825849SDag-Erling Smørgrav #define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
74*ff825849SDag-Erling Smørgrav #define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
75*ff825849SDag-Erling Smørgrav 
76*ff825849SDag-Erling Smørgrav int	getentropy(void *buf, size_t len);
77*ff825849SDag-Erling Smørgrav 
78*ff825849SDag-Erling Smørgrav #ifdef CAN_REFERENCE_MAIN
79*ff825849SDag-Erling Smørgrav extern int main(int, char *argv[]);
80*ff825849SDag-Erling Smørgrav #endif
81*ff825849SDag-Erling Smørgrav static int gotdata(char *buf, size_t len);
82*ff825849SDag-Erling Smørgrav static int getentropy_urandom(void *buf, size_t len);
83*ff825849SDag-Erling Smørgrav static int getentropy_fallback(void *buf, size_t len);
84*ff825849SDag-Erling Smørgrav 
85*ff825849SDag-Erling Smørgrav int
86*ff825849SDag-Erling Smørgrav getentropy(void *buf, size_t len)
87*ff825849SDag-Erling Smørgrav {
88*ff825849SDag-Erling Smørgrav 	int ret = -1;
89*ff825849SDag-Erling Smørgrav 
90*ff825849SDag-Erling Smørgrav 	if (len > 256) {
91*ff825849SDag-Erling Smørgrav 		errno = EIO;
92*ff825849SDag-Erling Smørgrav 		return -1;
93*ff825849SDag-Erling Smørgrav 	}
94*ff825849SDag-Erling Smørgrav 
95*ff825849SDag-Erling Smørgrav 	/*
96*ff825849SDag-Erling Smørgrav 	 * Try to get entropy with /dev/urandom
97*ff825849SDag-Erling Smørgrav 	 *
98*ff825849SDag-Erling Smørgrav 	 * This can fail if the process is inside a chroot or if file
99*ff825849SDag-Erling Smørgrav 	 * descriptors are exhausted.
100*ff825849SDag-Erling Smørgrav 	 */
101*ff825849SDag-Erling Smørgrav 	ret = getentropy_urandom(buf, len);
102*ff825849SDag-Erling Smørgrav 	if (ret != -1)
103*ff825849SDag-Erling Smørgrav 		return (ret);
104*ff825849SDag-Erling Smørgrav 
105*ff825849SDag-Erling Smørgrav 	/*
106*ff825849SDag-Erling Smørgrav 	 * Entropy collection via /dev/urandom and sysctl have failed.
107*ff825849SDag-Erling Smørgrav 	 *
108*ff825849SDag-Erling Smørgrav 	 * No other API exists for collecting entropy, and we have
109*ff825849SDag-Erling Smørgrav 	 * no failsafe way to get it on OSX that is not sensitive
110*ff825849SDag-Erling Smørgrav 	 * to resource exhaustion.
111*ff825849SDag-Erling Smørgrav 	 *
112*ff825849SDag-Erling Smørgrav 	 * We have very few options:
113*ff825849SDag-Erling Smørgrav 	 *     - Even syslog_r is unsafe to call at this low level, so
114*ff825849SDag-Erling Smørgrav 	 *	 there is no way to alert the user or program.
115*ff825849SDag-Erling Smørgrav 	 *     - Cannot call abort() because some systems have unsafe
116*ff825849SDag-Erling Smørgrav 	 *	 corefiles.
117*ff825849SDag-Erling Smørgrav 	 *     - Could raise(SIGKILL) resulting in silent program termination.
118*ff825849SDag-Erling Smørgrav 	 *     - Return EIO, to hint that arc4random's stir function
119*ff825849SDag-Erling Smørgrav 	 *       should raise(SIGKILL)
120*ff825849SDag-Erling Smørgrav 	 *     - Do the best under the circumstances....
121*ff825849SDag-Erling Smørgrav 	 *
122*ff825849SDag-Erling Smørgrav 	 * This code path exists to bring light to the issue that OSX
123*ff825849SDag-Erling Smørgrav 	 * does not provide a failsafe API for entropy collection.
124*ff825849SDag-Erling Smørgrav 	 *
125*ff825849SDag-Erling Smørgrav 	 * We hope this demonstrates that OSX should consider
126*ff825849SDag-Erling Smørgrav 	 * providing a new failsafe API which works in a chroot or
127*ff825849SDag-Erling Smørgrav 	 * when file descriptors are exhausted.
128*ff825849SDag-Erling Smørgrav 	 */
129*ff825849SDag-Erling Smørgrav #undef FAIL_INSTEAD_OF_TRYING_FALLBACK
130*ff825849SDag-Erling Smørgrav #ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
131*ff825849SDag-Erling Smørgrav 	raise(SIGKILL);
132*ff825849SDag-Erling Smørgrav #endif
133*ff825849SDag-Erling Smørgrav 	ret = getentropy_fallback(buf, len);
134*ff825849SDag-Erling Smørgrav 	if (ret != -1)
135*ff825849SDag-Erling Smørgrav 		return (ret);
136*ff825849SDag-Erling Smørgrav 
137*ff825849SDag-Erling Smørgrav 	errno = EIO;
138*ff825849SDag-Erling Smørgrav 	return (ret);
139*ff825849SDag-Erling Smørgrav }
140*ff825849SDag-Erling Smørgrav 
141*ff825849SDag-Erling Smørgrav /*
142*ff825849SDag-Erling Smørgrav  * Basic sanity checking; wish we could do better.
143*ff825849SDag-Erling Smørgrav  */
144*ff825849SDag-Erling Smørgrav static int
145*ff825849SDag-Erling Smørgrav gotdata(char *buf, size_t len)
146*ff825849SDag-Erling Smørgrav {
147*ff825849SDag-Erling Smørgrav 	char	any_set = 0;
148*ff825849SDag-Erling Smørgrav 	size_t	i;
149*ff825849SDag-Erling Smørgrav 
150*ff825849SDag-Erling Smørgrav 	for (i = 0; i < len; ++i)
151*ff825849SDag-Erling Smørgrav 		any_set |= buf[i];
152*ff825849SDag-Erling Smørgrav 	if (any_set == 0)
153*ff825849SDag-Erling Smørgrav 		return -1;
154*ff825849SDag-Erling Smørgrav 	return 0;
155*ff825849SDag-Erling Smørgrav }
156*ff825849SDag-Erling Smørgrav 
157*ff825849SDag-Erling Smørgrav static int
158*ff825849SDag-Erling Smørgrav getentropy_urandom(void *buf, size_t len)
159*ff825849SDag-Erling Smørgrav {
160*ff825849SDag-Erling Smørgrav 	struct stat st;
161*ff825849SDag-Erling Smørgrav 	size_t i;
162*ff825849SDag-Erling Smørgrav 	int fd, flags;
163*ff825849SDag-Erling Smørgrav 	int save_errno = errno;
164*ff825849SDag-Erling Smørgrav 
165*ff825849SDag-Erling Smørgrav start:
166*ff825849SDag-Erling Smørgrav 
167*ff825849SDag-Erling Smørgrav 	flags = O_RDONLY;
168*ff825849SDag-Erling Smørgrav #ifdef O_NOFOLLOW
169*ff825849SDag-Erling Smørgrav 	flags |= O_NOFOLLOW;
170*ff825849SDag-Erling Smørgrav #endif
171*ff825849SDag-Erling Smørgrav #ifdef O_CLOEXEC
172*ff825849SDag-Erling Smørgrav 	flags |= O_CLOEXEC;
173*ff825849SDag-Erling Smørgrav #endif
174*ff825849SDag-Erling Smørgrav 	fd = open("/dev/urandom", flags, 0);
175*ff825849SDag-Erling Smørgrav 	if (fd == -1) {
176*ff825849SDag-Erling Smørgrav 		if (errno == EINTR)
177*ff825849SDag-Erling Smørgrav 			goto start;
178*ff825849SDag-Erling Smørgrav 		goto nodevrandom;
179*ff825849SDag-Erling Smørgrav 	}
180*ff825849SDag-Erling Smørgrav #ifndef O_CLOEXEC
181*ff825849SDag-Erling Smørgrav 	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
182*ff825849SDag-Erling Smørgrav #endif
183*ff825849SDag-Erling Smørgrav 
184*ff825849SDag-Erling Smørgrav 	/* Lightly verify that the device node looks sane */
185*ff825849SDag-Erling Smørgrav 	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
186*ff825849SDag-Erling Smørgrav 		close(fd);
187*ff825849SDag-Erling Smørgrav 		goto nodevrandom;
188*ff825849SDag-Erling Smørgrav 	}
189*ff825849SDag-Erling Smørgrav 	for (i = 0; i < len; ) {
190*ff825849SDag-Erling Smørgrav 		size_t wanted = len - i;
191*ff825849SDag-Erling Smørgrav 		ssize_t ret = read(fd, (char*)buf + i, wanted);
192*ff825849SDag-Erling Smørgrav 
193*ff825849SDag-Erling Smørgrav 		if (ret == -1) {
194*ff825849SDag-Erling Smørgrav 			if (errno == EAGAIN || errno == EINTR)
195*ff825849SDag-Erling Smørgrav 				continue;
196*ff825849SDag-Erling Smørgrav 			close(fd);
197*ff825849SDag-Erling Smørgrav 			goto nodevrandom;
198*ff825849SDag-Erling Smørgrav 		}
199*ff825849SDag-Erling Smørgrav 		i += ret;
200*ff825849SDag-Erling Smørgrav 	}
201*ff825849SDag-Erling Smørgrav 	close(fd);
202*ff825849SDag-Erling Smørgrav 	if (gotdata(buf, len) == 0) {
203*ff825849SDag-Erling Smørgrav 		errno = save_errno;
204*ff825849SDag-Erling Smørgrav 		return 0;		/* satisfied */
205*ff825849SDag-Erling Smørgrav 	}
206*ff825849SDag-Erling Smørgrav nodevrandom:
207*ff825849SDag-Erling Smørgrav 	errno = EIO;
208*ff825849SDag-Erling Smørgrav 	return -1;
209*ff825849SDag-Erling Smørgrav }
210*ff825849SDag-Erling Smørgrav 
211*ff825849SDag-Erling Smørgrav static int tcpmib[] = { CTL_NET, AF_INET, IPPROTO_TCP, TCPCTL_STATS };
212*ff825849SDag-Erling Smørgrav static int udpmib[] = { CTL_NET, AF_INET, IPPROTO_UDP, UDPCTL_STATS };
213*ff825849SDag-Erling Smørgrav static int ipmib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_STATS };
214*ff825849SDag-Erling Smørgrav static int kmib[] = { CTL_KERN, KERN_USRSTACK };
215*ff825849SDag-Erling Smørgrav static int hwmib[] = { CTL_HW, HW_USERMEM };
216*ff825849SDag-Erling Smørgrav 
217*ff825849SDag-Erling Smørgrav static int
218*ff825849SDag-Erling Smørgrav getentropy_fallback(void *buf, size_t len)
219*ff825849SDag-Erling Smørgrav {
220*ff825849SDag-Erling Smørgrav 	uint8_t results[SHA512_DIGEST_LENGTH];
221*ff825849SDag-Erling Smørgrav 	int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
222*ff825849SDag-Erling Smørgrav 	static int cnt;
223*ff825849SDag-Erling Smørgrav 	struct timespec ts;
224*ff825849SDag-Erling Smørgrav 	struct timeval tv;
225*ff825849SDag-Erling Smørgrav 	struct rusage ru;
226*ff825849SDag-Erling Smørgrav 	sigset_t sigset;
227*ff825849SDag-Erling Smørgrav 	struct stat st;
228*ff825849SDag-Erling Smørgrav 	SHA512_CTX ctx;
229*ff825849SDag-Erling Smørgrav 	static pid_t lastpid;
230*ff825849SDag-Erling Smørgrav 	pid_t pid;
231*ff825849SDag-Erling Smørgrav 	size_t i, ii, m;
232*ff825849SDag-Erling Smørgrav 	char *p;
233*ff825849SDag-Erling Smørgrav 	struct tcpstat tcpstat;
234*ff825849SDag-Erling Smørgrav 	struct udpstat udpstat;
235*ff825849SDag-Erling Smørgrav 	struct ipstat ipstat;
236*ff825849SDag-Erling Smørgrav 	u_int64_t mach_time;
237*ff825849SDag-Erling Smørgrav 	unsigned int idata;
238*ff825849SDag-Erling Smørgrav 	void *addr;
239*ff825849SDag-Erling Smørgrav 
240*ff825849SDag-Erling Smørgrav 	pid = getpid();
241*ff825849SDag-Erling Smørgrav 	if (lastpid == pid) {
242*ff825849SDag-Erling Smørgrav 		faster = 1;
243*ff825849SDag-Erling Smørgrav 		repeat = 2;
244*ff825849SDag-Erling Smørgrav 	} else {
245*ff825849SDag-Erling Smørgrav 		faster = 0;
246*ff825849SDag-Erling Smørgrav 		lastpid = pid;
247*ff825849SDag-Erling Smørgrav 		repeat = REPEAT;
248*ff825849SDag-Erling Smørgrav 	}
249*ff825849SDag-Erling Smørgrav 	for (i = 0; i < len; ) {
250*ff825849SDag-Erling Smørgrav 		int j;
251*ff825849SDag-Erling Smørgrav 		SHA512_Init(&ctx);
252*ff825849SDag-Erling Smørgrav 		for (j = 0; j < repeat; j++) {
253*ff825849SDag-Erling Smørgrav 			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
254*ff825849SDag-Erling Smørgrav 			if (e != -1) {
255*ff825849SDag-Erling Smørgrav 				cnt += (int)tv.tv_sec;
256*ff825849SDag-Erling Smørgrav 				cnt += (int)tv.tv_usec;
257*ff825849SDag-Erling Smørgrav 			}
258*ff825849SDag-Erling Smørgrav 
259*ff825849SDag-Erling Smørgrav 			mach_time = mach_absolute_time();
260*ff825849SDag-Erling Smørgrav 			HD(mach_time);
261*ff825849SDag-Erling Smørgrav 
262*ff825849SDag-Erling Smørgrav 			ii = sizeof(addr);
263*ff825849SDag-Erling Smørgrav 			HX(sysctl(kmib, sizeof(kmib) / sizeof(kmib[0]),
264*ff825849SDag-Erling Smørgrav 			    &addr, &ii, NULL, 0) == -1, addr);
265*ff825849SDag-Erling Smørgrav 
266*ff825849SDag-Erling Smørgrav 			ii = sizeof(idata);
267*ff825849SDag-Erling Smørgrav 			HX(sysctl(hwmib, sizeof(hwmib) / sizeof(hwmib[0]),
268*ff825849SDag-Erling Smørgrav 			    &idata, &ii, NULL, 0) == -1, idata);
269*ff825849SDag-Erling Smørgrav 
270*ff825849SDag-Erling Smørgrav 			ii = sizeof(tcpstat);
271*ff825849SDag-Erling Smørgrav 			HX(sysctl(tcpmib, sizeof(tcpmib) / sizeof(tcpmib[0]),
272*ff825849SDag-Erling Smørgrav 			    &tcpstat, &ii, NULL, 0) == -1, tcpstat);
273*ff825849SDag-Erling Smørgrav 
274*ff825849SDag-Erling Smørgrav 			ii = sizeof(udpstat);
275*ff825849SDag-Erling Smørgrav 			HX(sysctl(udpmib, sizeof(udpmib) / sizeof(udpmib[0]),
276*ff825849SDag-Erling Smørgrav 			    &udpstat, &ii, NULL, 0) == -1, udpstat);
277*ff825849SDag-Erling Smørgrav 
278*ff825849SDag-Erling Smørgrav 			ii = sizeof(ipstat);
279*ff825849SDag-Erling Smørgrav 			HX(sysctl(ipmib, sizeof(ipmib) / sizeof(ipmib[0]),
280*ff825849SDag-Erling Smørgrav 			    &ipstat, &ii, NULL, 0) == -1, ipstat);
281*ff825849SDag-Erling Smørgrav 
282*ff825849SDag-Erling Smørgrav 			HX((pid = getpid()) == -1, pid);
283*ff825849SDag-Erling Smørgrav 			HX((pid = getsid(pid)) == -1, pid);
284*ff825849SDag-Erling Smørgrav 			HX((pid = getppid()) == -1, pid);
285*ff825849SDag-Erling Smørgrav 			HX((pid = getpgid(0)) == -1, pid);
286*ff825849SDag-Erling Smørgrav 			HX((e = getpriority(0, 0)) == -1, e);
287*ff825849SDag-Erling Smørgrav 
288*ff825849SDag-Erling Smørgrav 			if (!faster) {
289*ff825849SDag-Erling Smørgrav 				ts.tv_sec = 0;
290*ff825849SDag-Erling Smørgrav 				ts.tv_nsec = 1;
291*ff825849SDag-Erling Smørgrav 				(void) nanosleep(&ts, NULL);
292*ff825849SDag-Erling Smørgrav 			}
293*ff825849SDag-Erling Smørgrav 
294*ff825849SDag-Erling Smørgrav 			HX(sigpending(&sigset) == -1, sigset);
295*ff825849SDag-Erling Smørgrav 			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
296*ff825849SDag-Erling Smørgrav 			    sigset);
297*ff825849SDag-Erling Smørgrav 
298*ff825849SDag-Erling Smørgrav #ifdef CAN_REFERENCE_MAIN
299*ff825849SDag-Erling Smørgrav 			HF(main);		/* an addr in program */
300*ff825849SDag-Erling Smørgrav #endif
301*ff825849SDag-Erling Smørgrav 			HF(getentropy);	/* an addr in this library */
302*ff825849SDag-Erling Smørgrav 			HF(printf);		/* an addr in libc */
303*ff825849SDag-Erling Smørgrav 			p = (char *)&p;
304*ff825849SDag-Erling Smørgrav 			HD(p);		/* an addr on stack */
305*ff825849SDag-Erling Smørgrav 			p = (char *)&errno;
306*ff825849SDag-Erling Smørgrav 			HD(p);		/* the addr of errno */
307*ff825849SDag-Erling Smørgrav 
308*ff825849SDag-Erling Smørgrav 			if (i == 0) {
309*ff825849SDag-Erling Smørgrav 				struct sockaddr_storage ss;
310*ff825849SDag-Erling Smørgrav 				struct statvfs stvfs;
311*ff825849SDag-Erling Smørgrav 				struct termios tios;
312*ff825849SDag-Erling Smørgrav 				struct statfs stfs;
313*ff825849SDag-Erling Smørgrav 				socklen_t ssl;
314*ff825849SDag-Erling Smørgrav 				off_t off;
315*ff825849SDag-Erling Smørgrav 
316*ff825849SDag-Erling Smørgrav 				/*
317*ff825849SDag-Erling Smørgrav 				 * Prime-sized mappings encourage fragmentation;
318*ff825849SDag-Erling Smørgrav 				 * thus exposing some address entropy.
319*ff825849SDag-Erling Smørgrav 				 */
320*ff825849SDag-Erling Smørgrav 				struct mm {
321*ff825849SDag-Erling Smørgrav 					size_t	npg;
322*ff825849SDag-Erling Smørgrav 					void	*p;
323*ff825849SDag-Erling Smørgrav 				} mm[] =	 {
324*ff825849SDag-Erling Smørgrav 					{ 17, MAP_FAILED }, { 3, MAP_FAILED },
325*ff825849SDag-Erling Smørgrav 					{ 11, MAP_FAILED }, { 2, MAP_FAILED },
326*ff825849SDag-Erling Smørgrav 					{ 5, MAP_FAILED }, { 3, MAP_FAILED },
327*ff825849SDag-Erling Smørgrav 					{ 7, MAP_FAILED }, { 1, MAP_FAILED },
328*ff825849SDag-Erling Smørgrav 					{ 57, MAP_FAILED }, { 3, MAP_FAILED },
329*ff825849SDag-Erling Smørgrav 					{ 131, MAP_FAILED }, { 1, MAP_FAILED },
330*ff825849SDag-Erling Smørgrav 				};
331*ff825849SDag-Erling Smørgrav 
332*ff825849SDag-Erling Smørgrav 				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
333*ff825849SDag-Erling Smørgrav 					HX(mm[m].p = mmap(NULL,
334*ff825849SDag-Erling Smørgrav 					    mm[m].npg * pgs,
335*ff825849SDag-Erling Smørgrav 					    PROT_READ|PROT_WRITE,
336*ff825849SDag-Erling Smørgrav 					    MAP_PRIVATE|MAP_ANON, -1,
337*ff825849SDag-Erling Smørgrav 					    (off_t)0), mm[m].p);
338*ff825849SDag-Erling Smørgrav 					if (mm[m].p != MAP_FAILED) {
339*ff825849SDag-Erling Smørgrav 						size_t mo;
340*ff825849SDag-Erling Smørgrav 
341*ff825849SDag-Erling Smørgrav 						/* Touch some memory... */
342*ff825849SDag-Erling Smørgrav 						p = mm[m].p;
343*ff825849SDag-Erling Smørgrav 						mo = cnt %
344*ff825849SDag-Erling Smørgrav 						    (mm[m].npg * pgs - 1);
345*ff825849SDag-Erling Smørgrav 						p[mo] = 1;
346*ff825849SDag-Erling Smørgrav 						cnt += (int)((long)(mm[m].p)
347*ff825849SDag-Erling Smørgrav 						    / pgs);
348*ff825849SDag-Erling Smørgrav 					}
349*ff825849SDag-Erling Smørgrav 
350*ff825849SDag-Erling Smørgrav 					/* Check cnts and times... */
351*ff825849SDag-Erling Smørgrav 					mach_time = mach_absolute_time();
352*ff825849SDag-Erling Smørgrav 					HD(mach_time);
353*ff825849SDag-Erling Smørgrav 					cnt += (int)mach_time;
354*ff825849SDag-Erling Smørgrav 
355*ff825849SDag-Erling Smørgrav 					HX((e = getrusage(RUSAGE_SELF,
356*ff825849SDag-Erling Smørgrav 					    &ru)) == -1, ru);
357*ff825849SDag-Erling Smørgrav 					if (e != -1) {
358*ff825849SDag-Erling Smørgrav 						cnt += (int)ru.ru_utime.tv_sec;
359*ff825849SDag-Erling Smørgrav 						cnt += (int)ru.ru_utime.tv_usec;
360*ff825849SDag-Erling Smørgrav 					}
361*ff825849SDag-Erling Smørgrav 				}
362*ff825849SDag-Erling Smørgrav 
363*ff825849SDag-Erling Smørgrav 				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
364*ff825849SDag-Erling Smørgrav 					if (mm[m].p != MAP_FAILED)
365*ff825849SDag-Erling Smørgrav 						munmap(mm[m].p, mm[m].npg * pgs);
366*ff825849SDag-Erling Smørgrav 					mm[m].p = MAP_FAILED;
367*ff825849SDag-Erling Smørgrav 				}
368*ff825849SDag-Erling Smørgrav 
369*ff825849SDag-Erling Smørgrav 				HX(stat(".", &st) == -1, st);
370*ff825849SDag-Erling Smørgrav 				HX(statvfs(".", &stvfs) == -1, stvfs);
371*ff825849SDag-Erling Smørgrav 				HX(statfs(".", &stfs) == -1, stfs);
372*ff825849SDag-Erling Smørgrav 
373*ff825849SDag-Erling Smørgrav 				HX(stat("/", &st) == -1, st);
374*ff825849SDag-Erling Smørgrav 				HX(statvfs("/", &stvfs) == -1, stvfs);
375*ff825849SDag-Erling Smørgrav 				HX(statfs("/", &stfs) == -1, stfs);
376*ff825849SDag-Erling Smørgrav 
377*ff825849SDag-Erling Smørgrav 				HX((e = fstat(0, &st)) == -1, st);
378*ff825849SDag-Erling Smørgrav 				if (e == -1) {
379*ff825849SDag-Erling Smørgrav 					if (S_ISREG(st.st_mode) ||
380*ff825849SDag-Erling Smørgrav 					    S_ISFIFO(st.st_mode) ||
381*ff825849SDag-Erling Smørgrav 					    S_ISSOCK(st.st_mode)) {
382*ff825849SDag-Erling Smørgrav 						HX(fstatvfs(0, &stvfs) == -1,
383*ff825849SDag-Erling Smørgrav 						    stvfs);
384*ff825849SDag-Erling Smørgrav 						HX(fstatfs(0, &stfs) == -1,
385*ff825849SDag-Erling Smørgrav 						    stfs);
386*ff825849SDag-Erling Smørgrav 						HX((off = lseek(0, (off_t)0,
387*ff825849SDag-Erling Smørgrav 						    SEEK_CUR)) < 0, off);
388*ff825849SDag-Erling Smørgrav 					}
389*ff825849SDag-Erling Smørgrav 					if (S_ISCHR(st.st_mode)) {
390*ff825849SDag-Erling Smørgrav 						HX(tcgetattr(0, &tios) == -1,
391*ff825849SDag-Erling Smørgrav 						    tios);
392*ff825849SDag-Erling Smørgrav 					} else if (S_ISSOCK(st.st_mode)) {
393*ff825849SDag-Erling Smørgrav 						memset(&ss, 0, sizeof ss);
394*ff825849SDag-Erling Smørgrav 						ssl = sizeof(ss);
395*ff825849SDag-Erling Smørgrav 						HX(getpeername(0,
396*ff825849SDag-Erling Smørgrav 						    (void *)&ss, &ssl) == -1,
397*ff825849SDag-Erling Smørgrav 						    ss);
398*ff825849SDag-Erling Smørgrav 					}
399*ff825849SDag-Erling Smørgrav 				}
400*ff825849SDag-Erling Smørgrav 
401*ff825849SDag-Erling Smørgrav 				HX((e = getrusage(RUSAGE_CHILDREN,
402*ff825849SDag-Erling Smørgrav 				    &ru)) == -1, ru);
403*ff825849SDag-Erling Smørgrav 				if (e != -1) {
404*ff825849SDag-Erling Smørgrav 					cnt += (int)ru.ru_utime.tv_sec;
405*ff825849SDag-Erling Smørgrav 					cnt += (int)ru.ru_utime.tv_usec;
406*ff825849SDag-Erling Smørgrav 				}
407*ff825849SDag-Erling Smørgrav 			} else {
408*ff825849SDag-Erling Smørgrav 				/* Subsequent hashes absorb previous result */
409*ff825849SDag-Erling Smørgrav 				HD(results);
410*ff825849SDag-Erling Smørgrav 			}
411*ff825849SDag-Erling Smørgrav 
412*ff825849SDag-Erling Smørgrav 			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
413*ff825849SDag-Erling Smørgrav 			if (e != -1) {
414*ff825849SDag-Erling Smørgrav 				cnt += (int)tv.tv_sec;
415*ff825849SDag-Erling Smørgrav 				cnt += (int)tv.tv_usec;
416*ff825849SDag-Erling Smørgrav 			}
417*ff825849SDag-Erling Smørgrav 
418*ff825849SDag-Erling Smørgrav 			HD(cnt);
419*ff825849SDag-Erling Smørgrav 		}
420*ff825849SDag-Erling Smørgrav 
421*ff825849SDag-Erling Smørgrav 		SHA512_Final(results, &ctx);
422*ff825849SDag-Erling Smørgrav 		memcpy((char*)buf + i, results, min(sizeof(results), len - i));
423*ff825849SDag-Erling Smørgrav 		i += min(sizeof(results), len - i);
424*ff825849SDag-Erling Smørgrav 	}
425*ff825849SDag-Erling Smørgrav 	memset(results, 0, sizeof results);
426*ff825849SDag-Erling Smørgrav 	if (gotdata(buf, len) == 0) {
427*ff825849SDag-Erling Smørgrav 		errno = save_errno;
428*ff825849SDag-Erling Smørgrav 		return 0;		/* satisfied */
429*ff825849SDag-Erling Smørgrav 	}
430*ff825849SDag-Erling Smørgrav 	errno = EIO;
431*ff825849SDag-Erling Smørgrav 	return -1;
432*ff825849SDag-Erling Smørgrav }
433