xref: /openbsd-src/lib/libcrypto/arc4random/getentropy_linux.c (revision 93d8086caff7b81d3dd4a95f598adac1497d1a02)
1*93d8086cSbeck /*	$OpenBSD: getentropy_linux.c,v 1.4 2014/06/20 20:27:22 beck Exp $	*/
28286e41bSbeck 
38286e41bSbeck /*
48286e41bSbeck  * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org>
58286e41bSbeck  * Copyright (c) 2014 Bob Beck <beck@obtuse.com>
68286e41bSbeck  *
78286e41bSbeck  * Permission to use, copy, modify, and distribute this software for any
88286e41bSbeck  * purpose with or without fee is hereby granted, provided that the above
98286e41bSbeck  * copyright notice and this permission notice appear in all copies.
108286e41bSbeck  *
118286e41bSbeck  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
128286e41bSbeck  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
138286e41bSbeck  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
148286e41bSbeck  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
158286e41bSbeck  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
168286e41bSbeck  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
178286e41bSbeck  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
188286e41bSbeck  */
198286e41bSbeck 
208286e41bSbeck #define	_POSIX_C_SOURCE 199309L
218286e41bSbeck #define	_GNU_SOURCE     1
228286e41bSbeck #include <sys/types.h>
238286e41bSbeck #include <sys/param.h>
248286e41bSbeck #include <sys/ioctl.h>
258286e41bSbeck #include <sys/resource.h>
268286e41bSbeck #include <sys/syscall.h>
278286e41bSbeck #include <sys/sysctl.h>
288286e41bSbeck #include <sys/statvfs.h>
298286e41bSbeck #include <sys/socket.h>
308286e41bSbeck #include <sys/mount.h>
318286e41bSbeck #include <sys/mman.h>
328286e41bSbeck #include <sys/stat.h>
338286e41bSbeck #include <sys/time.h>
348286e41bSbeck #include <stdlib.h>
358286e41bSbeck #include <stdint.h>
368286e41bSbeck #include <stdio.h>
378286e41bSbeck #include <termios.h>
388286e41bSbeck #include <fcntl.h>
398286e41bSbeck #include <signal.h>
408286e41bSbeck #include <string.h>
418286e41bSbeck #include <errno.h>
428286e41bSbeck #include <unistd.h>
438286e41bSbeck #include <time.h>
448286e41bSbeck #include <openssl/sha.h>
458286e41bSbeck 
468286e41bSbeck #include <linux/random.h>
478286e41bSbeck #include <sys/vfs.h>
488286e41bSbeck 
498286e41bSbeck #define REPEAT 5
508286e41bSbeck #define min(a, b) (((a) < (b)) ? (a) : (b))
518286e41bSbeck 
528286e41bSbeck #define HASHX(a, b) \
538286e41bSbeck 	do { \
548286e41bSbeck 		if ((a)) \
558286e41bSbeck 			HASHD(errno); \
568286e41bSbeck 		else \
578286e41bSbeck 			HASHD(b); \
588286e41bSbeck 	} while (0)
598286e41bSbeck 
608286e41bSbeck #define HASHD(xxx)	(SHA512_Update(&ctx, (char *)&(xxx), sizeof (xxx)))
618286e41bSbeck 
628286e41bSbeck int	getentropy(void *buf, size_t len);
638286e41bSbeck 
648286e41bSbeck static int gotdata(char *buf, size_t len);
6595438510Sotto static int getentropy_urandom(void *buf, size_t len);
6695438510Sotto static int getentropy_sysctl(void *buf, size_t len);
6795438510Sotto static int getentropy_fallback(void *buf, size_t len);
6895438510Sotto 
6995438510Sotto int
7095438510Sotto getentropy(void *buf, size_t len)
7195438510Sotto {
7295438510Sotto 	int ret = -1;
7395438510Sotto 
7495438510Sotto 	if (len > 256) {
7595438510Sotto 		errno = EIO;
7695438510Sotto 		return -1;
7795438510Sotto 	}
7895438510Sotto 
7995438510Sotto 	/*
8095438510Sotto 	 * Try to get entropy with /dev/urandom
8195438510Sotto 	 *
8295438510Sotto 	 * This can fail if the process is inside a chroot or if file
8395438510Sotto 	 * descriptors are exhausted.
8495438510Sotto 	 */
8595438510Sotto 	ret = getentropy_urandom(buf, len);
8695438510Sotto 	if (ret != -1)
8795438510Sotto 		return (ret);
8895438510Sotto 
8995438510Sotto #ifdef RANDOM_UUID
9095438510Sotto 	/*
91*93d8086cSbeck 	 * Try to use sysctl CTL_KERN, KERN_RANDOM, RANDOM_UUID.
92*93d8086cSbeck 	 * sysctl is a failsafe API, so it guarantees a result.  This
93*93d8086cSbeck 	 * should work inside a chroot, or when file descriptors are
94*93d8086cSbeck 	 * exhuasted.
9595438510Sotto 	 *
96*93d8086cSbeck 	 * However this can fail if the Linux kernel removes support
97*93d8086cSbeck 	 * for sysctl.  Starting in 2007, there have been efforts to
98*93d8086cSbeck 	 * deprecate the sysctl API/ABI, and push callers towards use
99*93d8086cSbeck 	 * of the chroot-unavailable fd-using /proc mechanism --
100*93d8086cSbeck 	 * essentially the same problems as /dev/urandom.
10195438510Sotto 	 *
10295438510Sotto 	 * Numerous setbacks have been encountered in their deprecation
10395438510Sotto 	 * schedule, so as of June 2014 the kernel ABI still exists. The
10495438510Sotto 	 * sysctl() stub in libc is missing on some systems.  There are
10595438510Sotto 	 * also reports that some kernels spew messages to the console.
10695438510Sotto 	 */
10795438510Sotto 	ret = getentropy_sysctl(buf, len);
10895438510Sotto 	if (ret != -1)
10995438510Sotto 		return (ret);
11095438510Sotto #endif /* RANDOM_UUID */
11195438510Sotto 
11295438510Sotto 	/*
11395438510Sotto 	 * Entropy collection via /dev/urandom and sysctl have failed.
11495438510Sotto 	 *
11595438510Sotto 	 * No other API exists for collecting entropy.  See the large
11695438510Sotto 	 * comment block above.
11795438510Sotto 	 *
11895438510Sotto 	 * We have very few options:
11995438510Sotto 	 *     - Even syslog_r is unsafe to call at this low level, so
12095438510Sotto 	 *	 there is no way to alert the user or program.
121*93d8086cSbeck 	 *     - Cannot call abort() because some systems have unsafe
122*93d8086cSbeck 	 *	 corefiles.
12395438510Sotto 	 *     - Could raise(SIGKILL) resulting in silent program termination.
12495438510Sotto 	 *     - Return EIO, to hint that arc4random's stir function
12595438510Sotto 	 *       should raise(SIGKILL)
12695438510Sotto 	 *     - Do the best under the circumstances....
12795438510Sotto 	 *
12895438510Sotto 	 * This code path exists to bring light to the issue that Linux
12995438510Sotto 	 * does not provide a failsafe API for entropy collection.
13095438510Sotto 	 *
13195438510Sotto 	 * We hope this demonstrates that Linux should either retain their
13295438510Sotto 	 * sysctl ABI, or consider providing a new failsafe API which
13395438510Sotto 	 * works in a chroot or when file descriptors are exhausted.
13495438510Sotto 	 */
13595438510Sotto #undef FAIL_HARD_WHEN_LINUX_DEPRECATES_SYSCTL
13695438510Sotto #ifdef FAIL_HARD_WHEN_LINUX_DEPRECATES_SYSCTL
13795438510Sotto 	raise(SIGKILL);
13895438510Sotto #endif
13995438510Sotto 	ret = getentropy_fallback(buf, len);
14095438510Sotto 	if (ret != -1)
14195438510Sotto 		return (ret);
14295438510Sotto 
14395438510Sotto 	errno = EIO;
14495438510Sotto 	return (ret);
14595438510Sotto }
1468286e41bSbeck 
1478286e41bSbeck /*
1488286e41bSbeck  * XXX Should be replaced with a proper entropy measure.
1498286e41bSbeck  */
1508286e41bSbeck static int
1518286e41bSbeck gotdata(char *buf, size_t len)
1528286e41bSbeck {
1538286e41bSbeck 	char	any_set = 0;
1548286e41bSbeck 	size_t	i;
1558286e41bSbeck 
1568286e41bSbeck 	for (i = 0; i < len; ++i)
1578286e41bSbeck 		any_set |= buf[i];
1588286e41bSbeck 	if (any_set == 0)
1598286e41bSbeck 		return -1;
1608286e41bSbeck 	return 0;
1618286e41bSbeck }
1628286e41bSbeck 
1638286e41bSbeck static int
1648286e41bSbeck getentropy_urandom(void *buf, size_t len)
1658286e41bSbeck {
1668286e41bSbeck 	struct stat st;
1678286e41bSbeck 	size_t i;
1688286e41bSbeck 	int fd, cnt;
1698286e41bSbeck 	int save_errno = errno;
1708286e41bSbeck 
1718286e41bSbeck start:
1728286e41bSbeck #ifdef O_CLOEXEC
1738286e41bSbeck 	fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC, 0);
1748286e41bSbeck 	if (fd == -1) {
1758286e41bSbeck 		if (errno == EINTR)
1768286e41bSbeck 			goto start;
1778286e41bSbeck 		goto nodevrandom;
1788286e41bSbeck 	}
1798286e41bSbeck #else
1808286e41bSbeck 	fd = open("/dev/urandom", O_RDONLY, 0);
1818286e41bSbeck 	if (fd == -1) {
1828286e41bSbeck 		if (errno == EINTR)
1838286e41bSbeck 			goto start;
1848286e41bSbeck 		goto nodevrandom;
1858286e41bSbeck 	}
1868286e41bSbeck 	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
1878286e41bSbeck #endif
1888286e41bSbeck 
1898286e41bSbeck 	/* Lightly verify that the device node looks sane */
1908286e41bSbeck 	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
1918286e41bSbeck 		close(fd);
1928286e41bSbeck 		goto nodevrandom;
1938286e41bSbeck 	}
1948286e41bSbeck 	if (ioctl(fd, RNDGETENTCNT, &cnt) == -1) {
1958286e41bSbeck 		close(fd);
1968286e41bSbeck 		goto nodevrandom;
1978286e41bSbeck 	}
1988286e41bSbeck 	for (i = 0; i < len; ) {
1998286e41bSbeck 		size_t wanted = len - i;
2008286e41bSbeck 		ssize_t ret = read(fd, buf + i, wanted);
2018286e41bSbeck 
2028286e41bSbeck 		if (ret == -1) {
2038286e41bSbeck 			if (errno == EAGAIN || errno == EINTR)
2048286e41bSbeck 				continue;
2058286e41bSbeck 			close(fd);
2068286e41bSbeck 			goto nodevrandom;
2078286e41bSbeck 		}
2088286e41bSbeck 		i += ret;
2098286e41bSbeck 	}
2108286e41bSbeck 	close(fd);
2118286e41bSbeck 	if (gotdata(buf, len) == 0) {
2128286e41bSbeck 		errno = save_errno;
2138286e41bSbeck 		return 0;		/* satisfied */
2148286e41bSbeck 	}
2158286e41bSbeck nodevrandom:
2168286e41bSbeck 	errno = EIO;
2178286e41bSbeck 	return -1;
2188286e41bSbeck }
2198286e41bSbeck 
2208286e41bSbeck #ifdef RANDOM_UUID
2218286e41bSbeck static int
2228286e41bSbeck getentropy_sysctl(void *buf, size_t len)
2238286e41bSbeck {
2248286e41bSbeck 	static const int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
2258286e41bSbeck 	size_t i, chunk;
2268286e41bSbeck 	int save_errno = errno;
2278286e41bSbeck 
2288286e41bSbeck 	for (i = 0; i < len; ) {
2298286e41bSbeck 		chunk = min(len - i, 16);
2308286e41bSbeck 
2318286e41bSbeck 		/* SYS__sysctl because some systems already removed sysctl() */
2328286e41bSbeck 		struct __sysctl_args args = {
2338286e41bSbeck 			.name = mib,
2348286e41bSbeck 			.nlen = 3,
2358286e41bSbeck 			.oldval = &buf[i],
2368286e41bSbeck 			.oldlenp = &chunk,
2378286e41bSbeck 		};
2388286e41bSbeck 		if (syscall(SYS__sysctl, &args) != 0)
2398286e41bSbeck 			goto sysctlfailed;
2408286e41bSbeck 		i += chunk;
2418286e41bSbeck 	}
2428286e41bSbeck 	if (gotdata(buf, len) == 0) {
2438286e41bSbeck 		errno = save_errno;
2448286e41bSbeck 		return (0);			/* satisfied */
2458286e41bSbeck 	}
2468286e41bSbeck sysctlfailed:
2478286e41bSbeck 	errno = EIO;
2488286e41bSbeck 	return -1;
2498286e41bSbeck }
2508286e41bSbeck #endif /* RANDOM_UUID */
2518286e41bSbeck 
2528286e41bSbeck static int cl[] = {
2538286e41bSbeck 	CLOCK_REALTIME,
2548286e41bSbeck #ifdef CLOCK_MONOTONIC
2558286e41bSbeck 	CLOCK_MONOTONIC,
2568286e41bSbeck #endif
2578286e41bSbeck #ifdef CLOCK_MONOTONIC_RAW
2588286e41bSbeck 	CLOCK_MONOTONIC_RAW,
2598286e41bSbeck #endif
2608286e41bSbeck #ifdef CLOCK_TAI
2618286e41bSbeck 	CLOCK_TAI,
2628286e41bSbeck #endif
2638286e41bSbeck #ifdef CLOCK_VIRTUAL
2648286e41bSbeck 	CLOCK_VIRTUAL,
2658286e41bSbeck #endif
2668286e41bSbeck #ifdef CLOCK_UPTIME
2678286e41bSbeck 	CLOCK_UPTIME,
2688286e41bSbeck #endif
2698286e41bSbeck #ifdef CLOCK_PROCESS_CPUTIME_ID
2708286e41bSbeck 	CLOCK_PROCESS_CPUTIME_ID,
2718286e41bSbeck #endif
2728286e41bSbeck #ifdef CLOCK_THREAD_CPUTIME_ID
2738286e41bSbeck 	CLOCK_THREAD_CPUTIME_ID,
2748286e41bSbeck #endif
2758286e41bSbeck };
2768286e41bSbeck 
2778286e41bSbeck static int
2788286e41bSbeck getentropy_fallback(void *buf, size_t len)
2798286e41bSbeck {
2808286e41bSbeck 	uint8_t results[SHA512_DIGEST_LENGTH];
2818286e41bSbeck 	int save_errno = errno, e, m, pgsiz = getpagesize(), repeat;
2828286e41bSbeck 	static int counter;
2838286e41bSbeck 	struct timespec ts;
2848286e41bSbeck 	struct timeval tv;
2858286e41bSbeck 	struct rusage ru;
2868286e41bSbeck 	sigset_t sigset;
2878286e41bSbeck 	struct stat st;
2888286e41bSbeck 	SHA512_CTX ctx;
2898286e41bSbeck 	pid_t pid;
2908286e41bSbeck 	size_t i, ii;
2918286e41bSbeck 	void *p;
2928286e41bSbeck 
2938286e41bSbeck 	for (i = 0; i < len; ) {
2948286e41bSbeck 		SHA512_Init(&ctx);
2958286e41bSbeck 		for (repeat = 0; repeat < REPEAT; repeat++) {
2968286e41bSbeck 
2978286e41bSbeck 			HASHX((e = gettimeofday(&tv, NULL)) == -1, tv);
2988286e41bSbeck 			if (e != -1) {
2998286e41bSbeck 				counter += (int)tv.tv_sec;
3008286e41bSbeck 				counter += (int)tv.tv_usec;
3018286e41bSbeck 			}
3028286e41bSbeck 
3038286e41bSbeck 			for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
3048286e41bSbeck 				HASHX(clock_gettime(cl[ii], &ts) == -1, ts);
3058286e41bSbeck 
3068286e41bSbeck 			HASHX((pid = getpid()) == -1, pid);
3078286e41bSbeck 			HASHX((pid = getsid(pid)) == -1, pid);
3088286e41bSbeck 			HASHX((pid = getppid()) == -1, pid);
3098286e41bSbeck 			HASHX((pid = getpgid(0)) == -1, pid);
3108286e41bSbeck 			HASHX((m = getpriority(0, 0)) == -1, m);
3118286e41bSbeck 
3128286e41bSbeck 			ts.tv_sec = 0;
3138286e41bSbeck 			ts.tv_nsec = 1;
3148286e41bSbeck 			(void) nanosleep(&ts, NULL);
3158286e41bSbeck 
3168286e41bSbeck 			HASHX(sigpending(&sigset) == -1, sigset);
317*93d8086cSbeck 			HASHX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
318*93d8086cSbeck 			    sigset);
3198286e41bSbeck 
3208286e41bSbeck 			HASHD(main);	   /* an address in the main program */
321*93d8086cSbeck 			HASHD(getentropy); /* man address in this library */
3228286e41bSbeck 			HASHD(printf);	   /* an address in libc */
3238286e41bSbeck 			p = (void *)&p;
3248286e41bSbeck 			HASHD(p); 	  /* an address on stack */
3258286e41bSbeck 			p = (void *)&errno;
3268286e41bSbeck 			HASHD(p); 	 /* the address of errno */
3278286e41bSbeck 
3288286e41bSbeck 		if (i == 0) {
3298286e41bSbeck 			struct sockaddr_storage ss;
3308286e41bSbeck 			struct statvfs stvfs;
3318286e41bSbeck 			struct termios tios;
3328286e41bSbeck 			struct statfs stfs;
3338286e41bSbeck 			socklen_t ssl;
3348286e41bSbeck 			off_t off;
3358286e41bSbeck 
3368286e41bSbeck 			/*
3378286e41bSbeck 			 * Prime-sized mappings encourage fragmentation;
3388286e41bSbeck 			 * thus exposing some address entropy.
3398286e41bSbeck 			 */
3408286e41bSbeck 			struct mm {
3418286e41bSbeck 				size_t	npg;
3428286e41bSbeck 				void	*p;
3438286e41bSbeck 			} mm[] =	 {
3448286e41bSbeck 				{ 17, MAP_FAILED }, { 3, MAP_FAILED },
3458286e41bSbeck 				{ 11, MAP_FAILED }, { 2, MAP_FAILED },
3468286e41bSbeck 				{ 5, MAP_FAILED }, { 3, MAP_FAILED },
3478286e41bSbeck 				{ 7, MAP_FAILED }, { 1, MAP_FAILED },
3488286e41bSbeck 				{ 57, MAP_FAILED }, { 3, MAP_FAILED },
3498286e41bSbeck 				{ 131, MAP_FAILED }, { 1, MAP_FAILED },
3508286e41bSbeck 			};
3518286e41bSbeck 
3528286e41bSbeck 			for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
3538286e41bSbeck 				HASHX(mm[m].p = mmap(NULL, mm[m].npg * pgsiz,
3548286e41bSbeck 				    PROT_READ|PROT_WRITE,
3558286e41bSbeck 				    MAP_PRIVATE|MAP_ANON, -1, (off_t)0), p);
3568286e41bSbeck 				if (mm[m].p != MAP_FAILED) {
3578286e41bSbeck 					char *mp;
3588286e41bSbeck 
3598286e41bSbeck 					/* Touch some memory... */
3608286e41bSbeck 					mp = mm[m].p;
361*93d8086cSbeck 					mp[counter % (mm[m].npg *
362*93d8086cSbeck 					    pgsiz - 1)] = 1;
363*93d8086cSbeck 					counter += (int)((long)(mm[m].p)
364*93d8086cSbeck 					    / pgsiz);
3658286e41bSbeck 				}
3668286e41bSbeck 
3678286e41bSbeck 				/* Check counters and times... */
3688286e41bSbeck 				for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]);
3698286e41bSbeck 				    ii++) {
370*93d8086cSbeck 					HASHX((e = clock_gettime(cl[ii],
371*93d8086cSbeck 					    &ts)) == -1, ts);
3728286e41bSbeck 					if (e != -1)
3738286e41bSbeck 						counter += (int)ts.tv_nsec;
3748286e41bSbeck 				}
3758286e41bSbeck 
376*93d8086cSbeck 				HASHX((e = getrusage(RUSAGE_SELF, &ru)) == -1,
377*93d8086cSbeck 				    ru);
3788286e41bSbeck 				if (e != -1) {
3798286e41bSbeck 					counter += (int)ru.ru_utime.tv_sec;
3808286e41bSbeck 					counter += (int)ru.ru_utime.tv_usec;
3818286e41bSbeck 				}
3828286e41bSbeck 			}
3838286e41bSbeck 
3848286e41bSbeck 			for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
3858286e41bSbeck 				if (mm[m].p != MAP_FAILED)
3868286e41bSbeck 					munmap(mm[m].p, mm[m].npg * pgsiz);
3878286e41bSbeck 				mm[m].p = MAP_FAILED;
3888286e41bSbeck 			}
3898286e41bSbeck 
3908286e41bSbeck 			HASHX(stat(".", &st) == -1, st);
3918286e41bSbeck 			HASHX(statvfs(".", &stvfs) == -1, stvfs);
3928286e41bSbeck 			HASHX(statfs(".", &stfs) == -1, stfs);
3938286e41bSbeck 
3948286e41bSbeck 			HASHX(stat("/", &st) == -1, st);
3958286e41bSbeck 			HASHX(statvfs("/", &stvfs) == -1, stvfs);
3968286e41bSbeck 			HASHX(statfs("/", &stfs) == -1, stfs);
3978286e41bSbeck 
3988286e41bSbeck 			HASHX((e = fstat(0, &st)) == -1, st);
3998286e41bSbeck 			if (e == -1) {
400*93d8086cSbeck 				if (S_ISREG(st.st_mode) ||
401*93d8086cSbeck 				    S_ISFIFO(st.st_mode) ||
4028286e41bSbeck 				    S_ISSOCK(st.st_mode)) {
403*93d8086cSbeck 					HASHX(fstatvfs(0, &stvfs) == -1,
404*93d8086cSbeck 					    stvfs);
4058286e41bSbeck 					HASHX(fstatfs(0, &stfs) == -1, stfs);
4068286e41bSbeck 					HASHX((off = lseek(0, (off_t)0,
4078286e41bSbeck 					    SEEK_CUR)) < 0, off);
4088286e41bSbeck 				}
4098286e41bSbeck 				if (S_ISCHR(st.st_mode)) {
4108286e41bSbeck 					HASHX(tcgetattr(0, &tios) == -1, tios);
4118286e41bSbeck 				} else if (S_ISSOCK(st.st_mode)) {
4128286e41bSbeck 					memset(&ss, 0, sizeof ss);
4138286e41bSbeck 					ssl = sizeof(ss);
4148286e41bSbeck 					HASHX(getpeername(0, (void *)&ss,
4158286e41bSbeck 					    &ssl) == -1, ss);
4168286e41bSbeck 				}
4178286e41bSbeck 			}
4188286e41bSbeck 
4198286e41bSbeck 			HASHX((e = getrusage(RUSAGE_CHILDREN, &ru)) == -1, ru);
4208286e41bSbeck 			if (e != -1) {
4218286e41bSbeck 				counter += (int)ru.ru_utime.tv_sec;
4228286e41bSbeck 				counter += (int)ru.ru_utime.tv_usec;
4238286e41bSbeck 			}
4248286e41bSbeck 		} else {
4258286e41bSbeck 			/* Subsequent hashes absorb previous result */
4268286e41bSbeck 			HASHD(results);
4278286e41bSbeck 		}
4288286e41bSbeck 
4298286e41bSbeck 		HASHX((e = gettimeofday(&tv, NULL)) == -1, tv);
4308286e41bSbeck 		if (e != -1) {
4318286e41bSbeck 			counter += (int)tv.tv_sec;
4328286e41bSbeck 			counter += (int)tv.tv_usec;
4338286e41bSbeck 		}
4348286e41bSbeck 
4358286e41bSbeck 		HASHD(counter);
4368286e41bSbeck 
4378286e41bSbeck 		} /* repeat */
4388286e41bSbeck 		SHA512_Final(results, &ctx);
4398286e41bSbeck 		memcpy(buf + i, results, min(sizeof(results), len - i));
4408286e41bSbeck 		i += min(sizeof(results), len - i);
4418286e41bSbeck 	}
4428286e41bSbeck 	memset(results, 0, sizeof results);
4438286e41bSbeck 	if (gotdata(buf, len) == 0) {
4448286e41bSbeck 		errno = save_errno;
4458286e41bSbeck 		return 0;		/* satisfied */
4468286e41bSbeck 	}
4478286e41bSbeck 	errno = EIO;
4488286e41bSbeck 	return -1;
4498286e41bSbeck }
450