xref: /freebsd/contrib/unbound/compat/getentropy_solaris.c (revision ff8258499cd4a5a2a522c985cd7592a7904d973f)
1*ff825849SDag-Erling Smørgrav /*	$OpenBSD: getentropy_solaris.c,v 1.3 2014/07/12 14:46:31 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/statvfs.h>
27*ff825849SDag-Erling Smørgrav #include <sys/socket.h>
28*ff825849SDag-Erling Smørgrav #include <sys/mount.h>
29*ff825849SDag-Erling Smørgrav #include <sys/mman.h>
30*ff825849SDag-Erling Smørgrav #include <sys/stat.h>
31*ff825849SDag-Erling Smørgrav #include <sys/time.h>
32*ff825849SDag-Erling Smørgrav #include <stdlib.h>
33*ff825849SDag-Erling Smørgrav #include <stdint.h>
34*ff825849SDag-Erling Smørgrav #include <stdio.h>
35*ff825849SDag-Erling Smørgrav #include <termios.h>
36*ff825849SDag-Erling Smørgrav #include <fcntl.h>
37*ff825849SDag-Erling Smørgrav #include <signal.h>
38*ff825849SDag-Erling Smørgrav #include <string.h>
39*ff825849SDag-Erling Smørgrav #include <errno.h>
40*ff825849SDag-Erling Smørgrav #include <unistd.h>
41*ff825849SDag-Erling Smørgrav #include <time.h>
42*ff825849SDag-Erling Smørgrav #include <sys/sha2.h>
43*ff825849SDag-Erling Smørgrav #define SHA512_Init SHA512Init
44*ff825849SDag-Erling Smørgrav #define SHA512_Update SHA512Update
45*ff825849SDag-Erling Smørgrav #define SHA512_Final SHA512Final
46*ff825849SDag-Erling Smørgrav 
47*ff825849SDag-Erling Smørgrav #include <sys/vfs.h>
48*ff825849SDag-Erling Smørgrav #include <sys/statfs.h>
49*ff825849SDag-Erling Smørgrav #include <sys/loadavg.h>
50*ff825849SDag-Erling Smørgrav 
51*ff825849SDag-Erling Smørgrav #define REPEAT 5
52*ff825849SDag-Erling Smørgrav #define min(a, b) (((a) < (b)) ? (a) : (b))
53*ff825849SDag-Erling Smørgrav 
54*ff825849SDag-Erling Smørgrav #define HX(a, b) \
55*ff825849SDag-Erling Smørgrav 	do { \
56*ff825849SDag-Erling Smørgrav 		if ((a)) \
57*ff825849SDag-Erling Smørgrav 			HD(errno); \
58*ff825849SDag-Erling Smørgrav 		else \
59*ff825849SDag-Erling Smørgrav 			HD(b); \
60*ff825849SDag-Erling Smørgrav 	} while (0)
61*ff825849SDag-Erling Smørgrav 
62*ff825849SDag-Erling Smørgrav #define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
63*ff825849SDag-Erling Smørgrav #define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
64*ff825849SDag-Erling Smørgrav #define HF(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
65*ff825849SDag-Erling Smørgrav 
66*ff825849SDag-Erling Smørgrav int	getentropy(void *buf, size_t len);
67*ff825849SDag-Erling Smørgrav 
68*ff825849SDag-Erling Smørgrav #ifdef CAN_REFERENCE_MAIN
69*ff825849SDag-Erling Smørgrav extern int main(int, char *argv[]);
70*ff825849SDag-Erling Smørgrav #endif
71*ff825849SDag-Erling Smørgrav static int gotdata(char *buf, size_t len);
72*ff825849SDag-Erling Smørgrav static int getentropy_urandom(void *buf, size_t len, const char *path,
73*ff825849SDag-Erling Smørgrav     int devfscheck);
74*ff825849SDag-Erling Smørgrav static int getentropy_fallback(void *buf, size_t len);
75*ff825849SDag-Erling Smørgrav 
76*ff825849SDag-Erling Smørgrav int
77*ff825849SDag-Erling Smørgrav getentropy(void *buf, size_t len)
78*ff825849SDag-Erling Smørgrav {
79*ff825849SDag-Erling Smørgrav 	int ret = -1;
80*ff825849SDag-Erling Smørgrav 
81*ff825849SDag-Erling Smørgrav 	if (len > 256) {
82*ff825849SDag-Erling Smørgrav 		errno = EIO;
83*ff825849SDag-Erling Smørgrav 		return -1;
84*ff825849SDag-Erling Smørgrav 	}
85*ff825849SDag-Erling Smørgrav 
86*ff825849SDag-Erling Smørgrav 	/*
87*ff825849SDag-Erling Smørgrav 	 * Try to get entropy with /dev/urandom
88*ff825849SDag-Erling Smørgrav 	 *
89*ff825849SDag-Erling Smørgrav 	 * Solaris provides /dev/urandom as a symbolic link to
90*ff825849SDag-Erling Smørgrav 	 * /devices/pseudo/random@0:urandom which is provided by
91*ff825849SDag-Erling Smørgrav 	 * a devfs filesystem.  Best practice is to use O_NOFOLLOW,
92*ff825849SDag-Erling Smørgrav 	 * so we must try the unpublished name directly.
93*ff825849SDag-Erling Smørgrav 	 *
94*ff825849SDag-Erling Smørgrav 	 * This can fail if the process is inside a chroot which lacks
95*ff825849SDag-Erling Smørgrav 	 * the devfs mount, or if file descriptors are exhausted.
96*ff825849SDag-Erling Smørgrav 	 */
97*ff825849SDag-Erling Smørgrav 	ret = getentropy_urandom(buf, len,
98*ff825849SDag-Erling Smørgrav 	    "/devices/pseudo/random@0:urandom", 1);
99*ff825849SDag-Erling Smørgrav 	if (ret != -1)
100*ff825849SDag-Erling Smørgrav 		return (ret);
101*ff825849SDag-Erling Smørgrav 
102*ff825849SDag-Erling Smørgrav 	/*
103*ff825849SDag-Erling Smørgrav 	 * Unfortunately, chroot spaces on Solaris are sometimes setup
104*ff825849SDag-Erling Smørgrav 	 * with direct device node of the well-known /dev/urandom name
105*ff825849SDag-Erling Smørgrav 	 * (perhaps to avoid dragging all of devfs into the space).
106*ff825849SDag-Erling Smørgrav 	 *
107*ff825849SDag-Erling Smørgrav 	 * This can fail if the process is inside a chroot or if file
108*ff825849SDag-Erling Smørgrav 	 * descriptors are exhausted.
109*ff825849SDag-Erling Smørgrav 	 */
110*ff825849SDag-Erling Smørgrav 	ret = getentropy_urandom(buf, len, "/dev/urandom", 0);
111*ff825849SDag-Erling Smørgrav 	if (ret != -1)
112*ff825849SDag-Erling Smørgrav 		return (ret);
113*ff825849SDag-Erling Smørgrav 
114*ff825849SDag-Erling Smørgrav 	/*
115*ff825849SDag-Erling Smørgrav 	 * Entropy collection via /dev/urandom has failed.
116*ff825849SDag-Erling Smørgrav 	 *
117*ff825849SDag-Erling Smørgrav 	 * No other API exists for collecting entropy, and we have
118*ff825849SDag-Erling Smørgrav 	 * no failsafe way to get it on Solaris that is not sensitive
119*ff825849SDag-Erling Smørgrav 	 * to resource exhaustion.
120*ff825849SDag-Erling Smørgrav 	 *
121*ff825849SDag-Erling Smørgrav 	 * We have very few options:
122*ff825849SDag-Erling Smørgrav 	 *     - Even syslog_r is unsafe to call at this low level, so
123*ff825849SDag-Erling Smørgrav 	 *	 there is no way to alert the user or program.
124*ff825849SDag-Erling Smørgrav 	 *     - Cannot call abort() because some systems have unsafe
125*ff825849SDag-Erling Smørgrav 	 *	 corefiles.
126*ff825849SDag-Erling Smørgrav 	 *     - Could raise(SIGKILL) resulting in silent program termination.
127*ff825849SDag-Erling Smørgrav 	 *     - Return EIO, to hint that arc4random's stir function
128*ff825849SDag-Erling Smørgrav 	 *       should raise(SIGKILL)
129*ff825849SDag-Erling Smørgrav 	 *     - Do the best under the circumstances....
130*ff825849SDag-Erling Smørgrav 	 *
131*ff825849SDag-Erling Smørgrav 	 * This code path exists to bring light to the issue that Solaris
132*ff825849SDag-Erling Smørgrav 	 * does not provide a failsafe API for entropy collection.
133*ff825849SDag-Erling Smørgrav 	 *
134*ff825849SDag-Erling Smørgrav 	 * We hope this demonstrates that Solaris should consider
135*ff825849SDag-Erling Smørgrav 	 * providing a new failsafe API which works in a chroot or
136*ff825849SDag-Erling Smørgrav 	 * when file descriptors are exhausted.
137*ff825849SDag-Erling Smørgrav 	 */
138*ff825849SDag-Erling Smørgrav #undef FAIL_INSTEAD_OF_TRYING_FALLBACK
139*ff825849SDag-Erling Smørgrav #ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
140*ff825849SDag-Erling Smørgrav 	raise(SIGKILL);
141*ff825849SDag-Erling Smørgrav #endif
142*ff825849SDag-Erling Smørgrav 	ret = getentropy_fallback(buf, len);
143*ff825849SDag-Erling Smørgrav 	if (ret != -1)
144*ff825849SDag-Erling Smørgrav 		return (ret);
145*ff825849SDag-Erling Smørgrav 
146*ff825849SDag-Erling Smørgrav 	errno = EIO;
147*ff825849SDag-Erling Smørgrav 	return (ret);
148*ff825849SDag-Erling Smørgrav }
149*ff825849SDag-Erling Smørgrav 
150*ff825849SDag-Erling Smørgrav /*
151*ff825849SDag-Erling Smørgrav  * Basic sanity checking; wish we could do better.
152*ff825849SDag-Erling Smørgrav  */
153*ff825849SDag-Erling Smørgrav static int
154*ff825849SDag-Erling Smørgrav gotdata(char *buf, size_t len)
155*ff825849SDag-Erling Smørgrav {
156*ff825849SDag-Erling Smørgrav 	char	any_set = 0;
157*ff825849SDag-Erling Smørgrav 	size_t	i;
158*ff825849SDag-Erling Smørgrav 
159*ff825849SDag-Erling Smørgrav 	for (i = 0; i < len; ++i)
160*ff825849SDag-Erling Smørgrav 		any_set |= buf[i];
161*ff825849SDag-Erling Smørgrav 	if (any_set == 0)
162*ff825849SDag-Erling Smørgrav 		return -1;
163*ff825849SDag-Erling Smørgrav 	return 0;
164*ff825849SDag-Erling Smørgrav }
165*ff825849SDag-Erling Smørgrav 
166*ff825849SDag-Erling Smørgrav static int
167*ff825849SDag-Erling Smørgrav getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck)
168*ff825849SDag-Erling Smørgrav {
169*ff825849SDag-Erling Smørgrav 	struct stat st;
170*ff825849SDag-Erling Smørgrav 	size_t i;
171*ff825849SDag-Erling Smørgrav 	int fd, flags;
172*ff825849SDag-Erling Smørgrav 	int save_errno = errno;
173*ff825849SDag-Erling Smørgrav 
174*ff825849SDag-Erling Smørgrav start:
175*ff825849SDag-Erling Smørgrav 
176*ff825849SDag-Erling Smørgrav 	flags = O_RDONLY;
177*ff825849SDag-Erling Smørgrav #ifdef O_NOFOLLOW
178*ff825849SDag-Erling Smørgrav 	flags |= O_NOFOLLOW;
179*ff825849SDag-Erling Smørgrav #endif
180*ff825849SDag-Erling Smørgrav #ifdef O_CLOEXEC
181*ff825849SDag-Erling Smørgrav 	flags |= O_CLOEXEC;
182*ff825849SDag-Erling Smørgrav #endif
183*ff825849SDag-Erling Smørgrav 	fd = open(path, flags, 0);
184*ff825849SDag-Erling Smørgrav 	if (fd == -1) {
185*ff825849SDag-Erling Smørgrav 		if (errno == EINTR)
186*ff825849SDag-Erling Smørgrav 			goto start;
187*ff825849SDag-Erling Smørgrav 		goto nodevrandom;
188*ff825849SDag-Erling Smørgrav 	}
189*ff825849SDag-Erling Smørgrav #ifndef O_CLOEXEC
190*ff825849SDag-Erling Smørgrav 	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
191*ff825849SDag-Erling Smørgrav #endif
192*ff825849SDag-Erling Smørgrav 
193*ff825849SDag-Erling Smørgrav 	/* Lightly verify that the device node looks sane */
194*ff825849SDag-Erling Smørgrav 	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode) ||
195*ff825849SDag-Erling Smørgrav 	    (devfscheck && (strcmp(st.st_fstype, "devfs") != 0))) {
196*ff825849SDag-Erling Smørgrav 		close(fd);
197*ff825849SDag-Erling Smørgrav 		goto nodevrandom;
198*ff825849SDag-Erling Smørgrav 	}
199*ff825849SDag-Erling Smørgrav 	for (i = 0; i < len; ) {
200*ff825849SDag-Erling Smørgrav 		size_t wanted = len - i;
201*ff825849SDag-Erling Smørgrav 		ssize_t ret = read(fd, (char*)buf + i, wanted);
202*ff825849SDag-Erling Smørgrav 
203*ff825849SDag-Erling Smørgrav 		if (ret == -1) {
204*ff825849SDag-Erling Smørgrav 			if (errno == EAGAIN || errno == EINTR)
205*ff825849SDag-Erling Smørgrav 				continue;
206*ff825849SDag-Erling Smørgrav 			close(fd);
207*ff825849SDag-Erling Smørgrav 			goto nodevrandom;
208*ff825849SDag-Erling Smørgrav 		}
209*ff825849SDag-Erling Smørgrav 		i += ret;
210*ff825849SDag-Erling Smørgrav 	}
211*ff825849SDag-Erling Smørgrav 	close(fd);
212*ff825849SDag-Erling Smørgrav 	if (gotdata(buf, len) == 0) {
213*ff825849SDag-Erling Smørgrav 		errno = save_errno;
214*ff825849SDag-Erling Smørgrav 		return 0;		/* satisfied */
215*ff825849SDag-Erling Smørgrav 	}
216*ff825849SDag-Erling Smørgrav nodevrandom:
217*ff825849SDag-Erling Smørgrav 	errno = EIO;
218*ff825849SDag-Erling Smørgrav 	return -1;
219*ff825849SDag-Erling Smørgrav }
220*ff825849SDag-Erling Smørgrav 
221*ff825849SDag-Erling Smørgrav static const int cl[] = {
222*ff825849SDag-Erling Smørgrav 	CLOCK_REALTIME,
223*ff825849SDag-Erling Smørgrav #ifdef CLOCK_MONOTONIC
224*ff825849SDag-Erling Smørgrav 	CLOCK_MONOTONIC,
225*ff825849SDag-Erling Smørgrav #endif
226*ff825849SDag-Erling Smørgrav #ifdef CLOCK_MONOTONIC_RAW
227*ff825849SDag-Erling Smørgrav 	CLOCK_MONOTONIC_RAW,
228*ff825849SDag-Erling Smørgrav #endif
229*ff825849SDag-Erling Smørgrav #ifdef CLOCK_TAI
230*ff825849SDag-Erling Smørgrav 	CLOCK_TAI,
231*ff825849SDag-Erling Smørgrav #endif
232*ff825849SDag-Erling Smørgrav #ifdef CLOCK_VIRTUAL
233*ff825849SDag-Erling Smørgrav 	CLOCK_VIRTUAL,
234*ff825849SDag-Erling Smørgrav #endif
235*ff825849SDag-Erling Smørgrav #ifdef CLOCK_UPTIME
236*ff825849SDag-Erling Smørgrav 	CLOCK_UPTIME,
237*ff825849SDag-Erling Smørgrav #endif
238*ff825849SDag-Erling Smørgrav #ifdef CLOCK_PROCESS_CPUTIME_ID
239*ff825849SDag-Erling Smørgrav 	CLOCK_PROCESS_CPUTIME_ID,
240*ff825849SDag-Erling Smørgrav #endif
241*ff825849SDag-Erling Smørgrav #ifdef CLOCK_THREAD_CPUTIME_ID
242*ff825849SDag-Erling Smørgrav 	CLOCK_THREAD_CPUTIME_ID,
243*ff825849SDag-Erling Smørgrav #endif
244*ff825849SDag-Erling Smørgrav };
245*ff825849SDag-Erling Smørgrav 
246*ff825849SDag-Erling Smørgrav static int
247*ff825849SDag-Erling Smørgrav getentropy_fallback(void *buf, size_t len)
248*ff825849SDag-Erling Smørgrav {
249*ff825849SDag-Erling Smørgrav 	uint8_t results[SHA512_DIGEST_LENGTH];
250*ff825849SDag-Erling Smørgrav 	int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
251*ff825849SDag-Erling Smørgrav 	static int cnt;
252*ff825849SDag-Erling Smørgrav 	struct timespec ts;
253*ff825849SDag-Erling Smørgrav 	struct timeval tv;
254*ff825849SDag-Erling Smørgrav 	double loadavg[3];
255*ff825849SDag-Erling Smørgrav 	struct rusage ru;
256*ff825849SDag-Erling Smørgrav 	sigset_t sigset;
257*ff825849SDag-Erling Smørgrav 	struct stat st;
258*ff825849SDag-Erling Smørgrav 	SHA512_CTX ctx;
259*ff825849SDag-Erling Smørgrav 	static pid_t lastpid;
260*ff825849SDag-Erling Smørgrav 	pid_t pid;
261*ff825849SDag-Erling Smørgrav 	size_t i, ii, m;
262*ff825849SDag-Erling Smørgrav 	char *p;
263*ff825849SDag-Erling Smørgrav 
264*ff825849SDag-Erling Smørgrav 	pid = getpid();
265*ff825849SDag-Erling Smørgrav 	if (lastpid == pid) {
266*ff825849SDag-Erling Smørgrav 		faster = 1;
267*ff825849SDag-Erling Smørgrav 		repeat = 2;
268*ff825849SDag-Erling Smørgrav 	} else {
269*ff825849SDag-Erling Smørgrav 		faster = 0;
270*ff825849SDag-Erling Smørgrav 		lastpid = pid;
271*ff825849SDag-Erling Smørgrav 		repeat = REPEAT;
272*ff825849SDag-Erling Smørgrav 	}
273*ff825849SDag-Erling Smørgrav 	for (i = 0; i < len; ) {
274*ff825849SDag-Erling Smørgrav 		int j;
275*ff825849SDag-Erling Smørgrav 		SHA512_Init(&ctx);
276*ff825849SDag-Erling Smørgrav 		for (j = 0; j < repeat; j++) {
277*ff825849SDag-Erling Smørgrav 			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
278*ff825849SDag-Erling Smørgrav 			if (e != -1) {
279*ff825849SDag-Erling Smørgrav 				cnt += (int)tv.tv_sec;
280*ff825849SDag-Erling Smørgrav 				cnt += (int)tv.tv_usec;
281*ff825849SDag-Erling Smørgrav 			}
282*ff825849SDag-Erling Smørgrav 
283*ff825849SDag-Erling Smørgrav 			for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
284*ff825849SDag-Erling Smørgrav 				HX(clock_gettime(cl[ii], &ts) == -1, ts);
285*ff825849SDag-Erling Smørgrav 
286*ff825849SDag-Erling Smørgrav 			HX((pid = getpid()) == -1, pid);
287*ff825849SDag-Erling Smørgrav 			HX((pid = getsid(pid)) == -1, pid);
288*ff825849SDag-Erling Smørgrav 			HX((pid = getppid()) == -1, pid);
289*ff825849SDag-Erling Smørgrav 			HX((pid = getpgid(0)) == -1, pid);
290*ff825849SDag-Erling Smørgrav 			HX((e = getpriority(0, 0)) == -1, e);
291*ff825849SDag-Erling Smørgrav 			HX((getloadavg(loadavg, 3) == -1), loadavg);
292*ff825849SDag-Erling Smørgrav 
293*ff825849SDag-Erling Smørgrav 			if (!faster) {
294*ff825849SDag-Erling Smørgrav 				ts.tv_sec = 0;
295*ff825849SDag-Erling Smørgrav 				ts.tv_nsec = 1;
296*ff825849SDag-Erling Smørgrav 				(void) nanosleep(&ts, NULL);
297*ff825849SDag-Erling Smørgrav 			}
298*ff825849SDag-Erling Smørgrav 
299*ff825849SDag-Erling Smørgrav 			HX(sigpending(&sigset) == -1, sigset);
300*ff825849SDag-Erling Smørgrav 			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
301*ff825849SDag-Erling Smørgrav 			    sigset);
302*ff825849SDag-Erling Smørgrav 
303*ff825849SDag-Erling Smørgrav #ifdef CAN_REFERENCE_MAIN
304*ff825849SDag-Erling Smørgrav 			HF(main);		/* an addr in program */
305*ff825849SDag-Erling Smørgrav #endif
306*ff825849SDag-Erling Smørgrav 			HF(getentropy);	/* an addr in this library */
307*ff825849SDag-Erling Smørgrav 			HF(printf);		/* an addr in libc */
308*ff825849SDag-Erling Smørgrav 			p = (char *)&p;
309*ff825849SDag-Erling Smørgrav 			HD(p);		/* an addr on stack */
310*ff825849SDag-Erling Smørgrav 			p = (char *)&errno;
311*ff825849SDag-Erling Smørgrav 			HD(p);		/* the addr of errno */
312*ff825849SDag-Erling Smørgrav 
313*ff825849SDag-Erling Smørgrav 			if (i == 0) {
314*ff825849SDag-Erling Smørgrav 				struct sockaddr_storage ss;
315*ff825849SDag-Erling Smørgrav 				struct statvfs stvfs;
316*ff825849SDag-Erling Smørgrav 				struct termios tios;
317*ff825849SDag-Erling Smørgrav 				socklen_t ssl;
318*ff825849SDag-Erling Smørgrav 				off_t off;
319*ff825849SDag-Erling Smørgrav 
320*ff825849SDag-Erling Smørgrav 				/*
321*ff825849SDag-Erling Smørgrav 				 * Prime-sized mappings encourage fragmentation;
322*ff825849SDag-Erling Smørgrav 				 * thus exposing some address entropy.
323*ff825849SDag-Erling Smørgrav 				 */
324*ff825849SDag-Erling Smørgrav 				struct mm {
325*ff825849SDag-Erling Smørgrav 					size_t	npg;
326*ff825849SDag-Erling Smørgrav 					void	*p;
327*ff825849SDag-Erling Smørgrav 				} mm[] =	 {
328*ff825849SDag-Erling Smørgrav 					{ 17, MAP_FAILED }, { 3, MAP_FAILED },
329*ff825849SDag-Erling Smørgrav 					{ 11, MAP_FAILED }, { 2, MAP_FAILED },
330*ff825849SDag-Erling Smørgrav 					{ 5, MAP_FAILED }, { 3, MAP_FAILED },
331*ff825849SDag-Erling Smørgrav 					{ 7, MAP_FAILED }, { 1, MAP_FAILED },
332*ff825849SDag-Erling Smørgrav 					{ 57, MAP_FAILED }, { 3, MAP_FAILED },
333*ff825849SDag-Erling Smørgrav 					{ 131, MAP_FAILED }, { 1, MAP_FAILED },
334*ff825849SDag-Erling Smørgrav 				};
335*ff825849SDag-Erling Smørgrav 
336*ff825849SDag-Erling Smørgrav 				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
337*ff825849SDag-Erling Smørgrav 					HX(mm[m].p = mmap(NULL,
338*ff825849SDag-Erling Smørgrav 					    mm[m].npg * pgs,
339*ff825849SDag-Erling Smørgrav 					    PROT_READ|PROT_WRITE,
340*ff825849SDag-Erling Smørgrav 					    MAP_PRIVATE|MAP_ANON, -1,
341*ff825849SDag-Erling Smørgrav 					    (off_t)0), mm[m].p);
342*ff825849SDag-Erling Smørgrav 					if (mm[m].p != MAP_FAILED) {
343*ff825849SDag-Erling Smørgrav 						size_t mo;
344*ff825849SDag-Erling Smørgrav 
345*ff825849SDag-Erling Smørgrav 						/* Touch some memory... */
346*ff825849SDag-Erling Smørgrav 						p = mm[m].p;
347*ff825849SDag-Erling Smørgrav 						mo = cnt %
348*ff825849SDag-Erling Smørgrav 						    (mm[m].npg * pgs - 1);
349*ff825849SDag-Erling Smørgrav 						p[mo] = 1;
350*ff825849SDag-Erling Smørgrav 						cnt += (int)((long)(mm[m].p)
351*ff825849SDag-Erling Smørgrav 						    / pgs);
352*ff825849SDag-Erling Smørgrav 					}
353*ff825849SDag-Erling Smørgrav 
354*ff825849SDag-Erling Smørgrav 					/* Check cnts and times... */
355*ff825849SDag-Erling Smørgrav 					for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]);
356*ff825849SDag-Erling Smørgrav 					    ii++) {
357*ff825849SDag-Erling Smørgrav 						HX((e = clock_gettime(cl[ii],
358*ff825849SDag-Erling Smørgrav 						    &ts)) == -1, ts);
359*ff825849SDag-Erling Smørgrav 						if (e != -1)
360*ff825849SDag-Erling Smørgrav 							cnt += (int)ts.tv_nsec;
361*ff825849SDag-Erling Smørgrav 					}
362*ff825849SDag-Erling Smørgrav 
363*ff825849SDag-Erling Smørgrav 					HX((e = getrusage(RUSAGE_SELF,
364*ff825849SDag-Erling Smørgrav 					    &ru)) == -1, ru);
365*ff825849SDag-Erling Smørgrav 					if (e != -1) {
366*ff825849SDag-Erling Smørgrav 						cnt += (int)ru.ru_utime.tv_sec;
367*ff825849SDag-Erling Smørgrav 						cnt += (int)ru.ru_utime.tv_usec;
368*ff825849SDag-Erling Smørgrav 					}
369*ff825849SDag-Erling Smørgrav 				}
370*ff825849SDag-Erling Smørgrav 
371*ff825849SDag-Erling Smørgrav 				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
372*ff825849SDag-Erling Smørgrav 					if (mm[m].p != MAP_FAILED)
373*ff825849SDag-Erling Smørgrav 						munmap(mm[m].p, mm[m].npg * pgs);
374*ff825849SDag-Erling Smørgrav 					mm[m].p = MAP_FAILED;
375*ff825849SDag-Erling Smørgrav 				}
376*ff825849SDag-Erling Smørgrav 
377*ff825849SDag-Erling Smørgrav 				HX(stat(".", &st) == -1, st);
378*ff825849SDag-Erling Smørgrav 				HX(statvfs(".", &stvfs) == -1, stvfs);
379*ff825849SDag-Erling Smørgrav 
380*ff825849SDag-Erling Smørgrav 				HX(stat("/", &st) == -1, st);
381*ff825849SDag-Erling Smørgrav 				HX(statvfs("/", &stvfs) == -1, stvfs);
382*ff825849SDag-Erling Smørgrav 
383*ff825849SDag-Erling Smørgrav 				HX((e = fstat(0, &st)) == -1, st);
384*ff825849SDag-Erling Smørgrav 				if (e == -1) {
385*ff825849SDag-Erling Smørgrav 					if (S_ISREG(st.st_mode) ||
386*ff825849SDag-Erling Smørgrav 					    S_ISFIFO(st.st_mode) ||
387*ff825849SDag-Erling Smørgrav 					    S_ISSOCK(st.st_mode)) {
388*ff825849SDag-Erling Smørgrav 						HX(fstatvfs(0, &stvfs) == -1,
389*ff825849SDag-Erling Smørgrav 						    stvfs);
390*ff825849SDag-Erling Smørgrav 						HX((off = lseek(0, (off_t)0,
391*ff825849SDag-Erling Smørgrav 						    SEEK_CUR)) < 0, off);
392*ff825849SDag-Erling Smørgrav 					}
393*ff825849SDag-Erling Smørgrav 					if (S_ISCHR(st.st_mode)) {
394*ff825849SDag-Erling Smørgrav 						HX(tcgetattr(0, &tios) == -1,
395*ff825849SDag-Erling Smørgrav 						    tios);
396*ff825849SDag-Erling Smørgrav 					} else if (S_ISSOCK(st.st_mode)) {
397*ff825849SDag-Erling Smørgrav 						memset(&ss, 0, sizeof ss);
398*ff825849SDag-Erling Smørgrav 						ssl = sizeof(ss);
399*ff825849SDag-Erling Smørgrav 						HX(getpeername(0,
400*ff825849SDag-Erling Smørgrav 						    (void *)&ss, &ssl) == -1,
401*ff825849SDag-Erling Smørgrav 						    ss);
402*ff825849SDag-Erling Smørgrav 					}
403*ff825849SDag-Erling Smørgrav 				}
404*ff825849SDag-Erling Smørgrav 
405*ff825849SDag-Erling Smørgrav 				HX((e = getrusage(RUSAGE_CHILDREN,
406*ff825849SDag-Erling Smørgrav 				    &ru)) == -1, ru);
407*ff825849SDag-Erling Smørgrav 				if (e != -1) {
408*ff825849SDag-Erling Smørgrav 					cnt += (int)ru.ru_utime.tv_sec;
409*ff825849SDag-Erling Smørgrav 					cnt += (int)ru.ru_utime.tv_usec;
410*ff825849SDag-Erling Smørgrav 				}
411*ff825849SDag-Erling Smørgrav 			} else {
412*ff825849SDag-Erling Smørgrav 				/* Subsequent hashes absorb previous result */
413*ff825849SDag-Erling Smørgrav 				HD(results);
414*ff825849SDag-Erling Smørgrav 			}
415*ff825849SDag-Erling Smørgrav 
416*ff825849SDag-Erling Smørgrav 			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
417*ff825849SDag-Erling Smørgrav 			if (e != -1) {
418*ff825849SDag-Erling Smørgrav 				cnt += (int)tv.tv_sec;
419*ff825849SDag-Erling Smørgrav 				cnt += (int)tv.tv_usec;
420*ff825849SDag-Erling Smørgrav 			}
421*ff825849SDag-Erling Smørgrav 
422*ff825849SDag-Erling Smørgrav 			HD(cnt);
423*ff825849SDag-Erling Smørgrav 		}
424*ff825849SDag-Erling Smørgrav 		SHA512_Final(results, &ctx);
425*ff825849SDag-Erling Smørgrav 		memcpy((char*)buf + i, results, min(sizeof(results), len - i));
426*ff825849SDag-Erling Smørgrav 		i += min(sizeof(results), len - i);
427*ff825849SDag-Erling Smørgrav 	}
428*ff825849SDag-Erling Smørgrav 	memset(results, 0, sizeof results);
429*ff825849SDag-Erling Smørgrav 	if (gotdata(buf, len) == 0) {
430*ff825849SDag-Erling Smørgrav 		errno = save_errno;
431*ff825849SDag-Erling Smørgrav 		return 0;		/* satisfied */
432*ff825849SDag-Erling Smørgrav 	}
433*ff825849SDag-Erling Smørgrav 	errno = EIO;
434*ff825849SDag-Erling Smørgrav 	return -1;
435*ff825849SDag-Erling Smørgrav }
436