xref: /openbsd-src/lib/libcrypto/arc4random/getentropy_osx.c (revision b7041c0781c8668129da8084451ded41b0c43954)
1*b7041c07Sderaadt /*	$OpenBSD: getentropy_osx.c,v 1.14 2021/10/24 21:24:20 deraadt Exp $	*/
23f84b207Sbeck 
33f84b207Sbeck /*
43f84b207Sbeck  * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org>
53f84b207Sbeck  * Copyright (c) 2014 Bob Beck <beck@obtuse.com>
63f84b207Sbeck  *
73f84b207Sbeck  * Permission to use, copy, modify, and distribute this software for any
83f84b207Sbeck  * purpose with or without fee is hereby granted, provided that the above
93f84b207Sbeck  * copyright notice and this permission notice appear in all copies.
103f84b207Sbeck  *
113f84b207Sbeck  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
123f84b207Sbeck  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
133f84b207Sbeck  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
143f84b207Sbeck  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
153f84b207Sbeck  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
163f84b207Sbeck  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
173f84b207Sbeck  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18b5f12122Sderaadt  *
19b5f12122Sderaadt  * Emulation of getentropy(2) as documented at:
20b8461433Stb  * http://man.openbsd.org/getentropy.2
213f84b207Sbeck  */
223f84b207Sbeck 
23c283a6cdSbcook #include <TargetConditionals.h>
243f84b207Sbeck #include <sys/types.h>
253f84b207Sbeck #include <sys/param.h>
263f84b207Sbeck #include <sys/ioctl.h>
273f84b207Sbeck #include <sys/resource.h>
283f84b207Sbeck #include <sys/syscall.h>
293f84b207Sbeck #include <sys/sysctl.h>
303f84b207Sbeck #include <sys/statvfs.h>
313f84b207Sbeck #include <sys/socket.h>
323f84b207Sbeck #include <sys/mount.h>
333f84b207Sbeck #include <sys/mman.h>
343f84b207Sbeck #include <sys/stat.h>
353f84b207Sbeck #include <sys/time.h>
363f84b207Sbeck #include <stdlib.h>
373f84b207Sbeck #include <stdint.h>
383f84b207Sbeck #include <stdio.h>
393f84b207Sbeck #include <termios.h>
403f84b207Sbeck #include <fcntl.h>
413f84b207Sbeck #include <signal.h>
423f84b207Sbeck #include <string.h>
433f84b207Sbeck #include <errno.h>
443f84b207Sbeck #include <unistd.h>
453f84b207Sbeck #include <time.h>
463f84b207Sbeck #include <mach/mach_time.h>
473f84b207Sbeck #include <mach/mach_host.h>
483f84b207Sbeck #include <mach/host_info.h>
49c283a6cdSbcook #if TARGET_OS_OSX
503f84b207Sbeck #include <sys/socketvar.h>
513f84b207Sbeck #include <sys/vmmeter.h>
52c283a6cdSbcook #endif
533f84b207Sbeck #include <netinet/in.h>
543f84b207Sbeck #include <netinet/tcp.h>
55c283a6cdSbcook #if TARGET_OS_OSX
563f84b207Sbeck #include <netinet/udp.h>
573f84b207Sbeck #include <netinet/ip_var.h>
583f84b207Sbeck #include <netinet/tcp_var.h>
593f84b207Sbeck #include <netinet/udp_var.h>
60c283a6cdSbcook #endif
613f84b207Sbeck #include <CommonCrypto/CommonDigest.h>
623f84b207Sbeck #define SHA512_Update(a, b, c)	(CC_SHA512_Update((a), (b), (c)))
633f84b207Sbeck #define SHA512_Init(xxx) (CC_SHA512_Init((xxx)))
643f84b207Sbeck #define SHA512_Final(xxx, yyy) (CC_SHA512_Final((xxx), (yyy)))
653f84b207Sbeck #define SHA512_CTX CC_SHA512_CTX
663f84b207Sbeck #define SHA512_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH
673f84b207Sbeck 
683f84b207Sbeck #define REPEAT 5
69557f50beSderaadt #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
703f84b207Sbeck 
713f84b207Sbeck #define HX(a, b) \
723f84b207Sbeck 	do { \
733f84b207Sbeck 		if ((a)) \
743f84b207Sbeck 			HD(errno); \
753f84b207Sbeck 		else \
763f84b207Sbeck 			HD(b); \
773f84b207Sbeck 	} while (0)
78fed6411aSderaadt 
793f84b207Sbeck #define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
803f84b207Sbeck #define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
8154dec340Swouter #define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
82fed6411aSderaadt 
833f84b207Sbeck int	getentropy(void *buf, size_t len);
843f84b207Sbeck 
853f84b207Sbeck static int getentropy_urandom(void *buf, size_t len);
863f84b207Sbeck static int getentropy_fallback(void *buf, size_t len);
873f84b207Sbeck 
883f84b207Sbeck int
getentropy(void * buf,size_t len)893f84b207Sbeck getentropy(void *buf, size_t len)
903f84b207Sbeck {
913f84b207Sbeck 	int ret = -1;
923f84b207Sbeck 
933f84b207Sbeck 	if (len > 256) {
943f84b207Sbeck 		errno = EIO;
95044fc755Sderaadt 		return (-1);
963f84b207Sbeck 	}
973f84b207Sbeck 
983f84b207Sbeck 	/*
993f84b207Sbeck 	 * Try to get entropy with /dev/urandom
1003f84b207Sbeck 	 *
1013f84b207Sbeck 	 * This can fail if the process is inside a chroot or if file
1023f84b207Sbeck 	 * descriptors are exhausted.
1033f84b207Sbeck 	 */
1043f84b207Sbeck 	ret = getentropy_urandom(buf, len);
1053f84b207Sbeck 	if (ret != -1)
1063f84b207Sbeck 		return (ret);
1073f84b207Sbeck 
1083f84b207Sbeck 	/*
1093f84b207Sbeck 	 * Entropy collection via /dev/urandom and sysctl have failed.
1103f84b207Sbeck 	 *
1113f84b207Sbeck 	 * No other API exists for collecting entropy, and we have
1123f84b207Sbeck 	 * no failsafe way to get it on OSX that is not sensitive
1133f84b207Sbeck 	 * to resource exhaustion.
1143f84b207Sbeck 	 *
1153f84b207Sbeck 	 * We have very few options:
1163f84b207Sbeck 	 *     - Even syslog_r is unsafe to call at this low level, so
1173f84b207Sbeck 	 *	 there is no way to alert the user or program.
1183f84b207Sbeck 	 *     - Cannot call abort() because some systems have unsafe
1193f84b207Sbeck 	 *	 corefiles.
1203f84b207Sbeck 	 *     - Could raise(SIGKILL) resulting in silent program termination.
1213f84b207Sbeck 	 *     - Return EIO, to hint that arc4random's stir function
1223f84b207Sbeck 	 *       should raise(SIGKILL)
1233f84b207Sbeck 	 *     - Do the best under the circumstances....
1243f84b207Sbeck 	 *
1253f84b207Sbeck 	 * This code path exists to bring light to the issue that OSX
1263f84b207Sbeck 	 * does not provide a failsafe API for entropy collection.
1273f84b207Sbeck 	 *
1283f84b207Sbeck 	 * We hope this demonstrates that OSX should consider
1293f84b207Sbeck 	 * providing a new failsafe API which works in a chroot or
1303f84b207Sbeck 	 * when file descriptors are exhausted.
1313f84b207Sbeck 	 */
132fed6411aSderaadt #undef FAIL_INSTEAD_OF_TRYING_FALLBACK
133fed6411aSderaadt #ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
1343f84b207Sbeck 	raise(SIGKILL);
1353f84b207Sbeck #endif
1363f84b207Sbeck 	ret = getentropy_fallback(buf, len);
1373f84b207Sbeck 	if (ret != -1)
1383f84b207Sbeck 		return (ret);
1393f84b207Sbeck 
1403f84b207Sbeck 	errno = EIO;
1413f84b207Sbeck 	return (ret);
1423f84b207Sbeck }
1433f84b207Sbeck 
1443f84b207Sbeck static int
getentropy_urandom(void * buf,size_t len)1453f84b207Sbeck getentropy_urandom(void *buf, size_t len)
1463f84b207Sbeck {
1473f84b207Sbeck 	struct stat st;
1483f84b207Sbeck 	size_t i;
149599b801fSbcook 	int fd, flags;
1503f84b207Sbeck 	int save_errno = errno;
1513f84b207Sbeck 
1523f84b207Sbeck start:
1533f84b207Sbeck 
1543f84b207Sbeck 	flags = O_RDONLY;
1553f84b207Sbeck #ifdef O_NOFOLLOW
1563f84b207Sbeck 	flags |= O_NOFOLLOW;
1573f84b207Sbeck #endif
1583f84b207Sbeck #ifdef O_CLOEXEC
1593f84b207Sbeck 	flags |= O_CLOEXEC;
1603f84b207Sbeck #endif
161*b7041c07Sderaadt 	fd = open("/dev/urandom", flags);
1623f84b207Sbeck 	if (fd == -1) {
1633f84b207Sbeck 		if (errno == EINTR)
1643f84b207Sbeck 			goto start;
1653f84b207Sbeck 		goto nodevrandom;
1663f84b207Sbeck 	}
1673f84b207Sbeck #ifndef O_CLOEXEC
1683f84b207Sbeck 	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
1693f84b207Sbeck #endif
1703f84b207Sbeck 
1713f84b207Sbeck 	/* Lightly verify that the device node looks sane */
1723f84b207Sbeck 	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
1733f84b207Sbeck 		close(fd);
1743f84b207Sbeck 		goto nodevrandom;
1753f84b207Sbeck 	}
1763f84b207Sbeck 	for (i = 0; i < len; ) {
1773f84b207Sbeck 		size_t wanted = len - i;
17854dec340Swouter 		ssize_t ret = read(fd, (char *)buf + i, wanted);
1793f84b207Sbeck 
1803f84b207Sbeck 		if (ret == -1) {
1813f84b207Sbeck 			if (errno == EAGAIN || errno == EINTR)
1823f84b207Sbeck 				continue;
1833f84b207Sbeck 			close(fd);
1843f84b207Sbeck 			goto nodevrandom;
1853f84b207Sbeck 		}
1863f84b207Sbeck 		i += ret;
1873f84b207Sbeck 	}
1883f84b207Sbeck 	close(fd);
1893f84b207Sbeck 	errno = save_errno;
190044fc755Sderaadt 	return (0);		/* satisfied */
1913f84b207Sbeck nodevrandom:
1923f84b207Sbeck 	errno = EIO;
193044fc755Sderaadt 	return (-1);
1943f84b207Sbeck }
1953f84b207Sbeck 
196c283a6cdSbcook #if TARGET_OS_OSX
197fed6411aSderaadt static int tcpmib[] = { CTL_NET, AF_INET, IPPROTO_TCP, TCPCTL_STATS };
198fed6411aSderaadt static int udpmib[] = { CTL_NET, AF_INET, IPPROTO_UDP, UDPCTL_STATS };
199fed6411aSderaadt static int ipmib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_STATS };
200c283a6cdSbcook #endif
201fed6411aSderaadt static int kmib[] = { CTL_KERN, KERN_USRSTACK };
202fed6411aSderaadt static int hwmib[] = { CTL_HW, HW_USERMEM };
203fed6411aSderaadt 
2043f84b207Sbeck static int
getentropy_fallback(void * buf,size_t len)2053f84b207Sbeck getentropy_fallback(void *buf, size_t len)
2063f84b207Sbeck {
2073f84b207Sbeck 	uint8_t results[SHA512_DIGEST_LENGTH];
20854dec340Swouter 	int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
209fed6411aSderaadt 	static int cnt;
2103f84b207Sbeck 	struct timespec ts;
2113f84b207Sbeck 	struct timeval tv;
2123f84b207Sbeck 	struct rusage ru;
2133f84b207Sbeck 	sigset_t sigset;
2143f84b207Sbeck 	struct stat st;
2153f84b207Sbeck 	SHA512_CTX ctx;
2163f84b207Sbeck 	static pid_t lastpid;
2173f84b207Sbeck 	pid_t pid;
21854dec340Swouter 	size_t i, ii, m;
2193f84b207Sbeck 	char *p;
220c283a6cdSbcook #if TARGET_OS_OSX
221fed6411aSderaadt 	struct tcpstat tcpstat;
222fed6411aSderaadt 	struct udpstat udpstat;
223fed6411aSderaadt 	struct ipstat ipstat;
224c283a6cdSbcook #endif
225fed6411aSderaadt 	u_int64_t mach_time;
226fed6411aSderaadt 	unsigned int idata;
227fed6411aSderaadt 	void *addr;
2283f84b207Sbeck 
2293f84b207Sbeck 	pid = getpid();
2303f84b207Sbeck 	if (lastpid == pid) {
2313f84b207Sbeck 		faster = 1;
2323f84b207Sbeck 		repeat = 2;
2333f84b207Sbeck 	} else {
2343f84b207Sbeck 		faster = 0;
2353f84b207Sbeck 		lastpid = pid;
2363f84b207Sbeck 		repeat = REPEAT;
2373f84b207Sbeck 	}
2383f84b207Sbeck 	for (i = 0; i < len; ) {
2393f84b207Sbeck 		int j;
2403f84b207Sbeck 		SHA512_Init(&ctx);
2413f84b207Sbeck 		for (j = 0; j < repeat; j++) {
2423f84b207Sbeck 			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
2433f84b207Sbeck 			if (e != -1) {
2443f84b207Sbeck 				cnt += (int)tv.tv_sec;
2453f84b207Sbeck 				cnt += (int)tv.tv_usec;
2463f84b207Sbeck 			}
2473f84b207Sbeck 
2483f84b207Sbeck 			mach_time = mach_absolute_time();
2493f84b207Sbeck 			HD(mach_time);
2503f84b207Sbeck 
251fed6411aSderaadt 			ii = sizeof(addr);
2523f84b207Sbeck 			HX(sysctl(kmib, sizeof(kmib) / sizeof(kmib[0]),
253fed6411aSderaadt 			    &addr, &ii, NULL, 0) == -1, addr);
2543f84b207Sbeck 
255fed6411aSderaadt 			ii = sizeof(idata);
2563f84b207Sbeck 			HX(sysctl(hwmib, sizeof(hwmib) / sizeof(hwmib[0]),
257fed6411aSderaadt 			    &idata, &ii, NULL, 0) == -1, idata);
2583f84b207Sbeck 
259c283a6cdSbcook #if TARGET_OS_OSX
260fed6411aSderaadt 			ii = sizeof(tcpstat);
2613f84b207Sbeck 			HX(sysctl(tcpmib, sizeof(tcpmib) / sizeof(tcpmib[0]),
262fed6411aSderaadt 			    &tcpstat, &ii, NULL, 0) == -1, tcpstat);
2633f84b207Sbeck 
264fed6411aSderaadt 			ii = sizeof(udpstat);
2653f84b207Sbeck 			HX(sysctl(udpmib, sizeof(udpmib) / sizeof(udpmib[0]),
266fed6411aSderaadt 			    &udpstat, &ii, NULL, 0) == -1, udpstat);
2673f84b207Sbeck 
268fed6411aSderaadt 			ii = sizeof(ipstat);
2693f84b207Sbeck 			HX(sysctl(ipmib, sizeof(ipmib) / sizeof(ipmib[0]),
270fed6411aSderaadt 			    &ipstat, &ii, NULL, 0) == -1, ipstat);
271c283a6cdSbcook #endif
2723f84b207Sbeck 
2733f84b207Sbeck 			HX((pid = getpid()) == -1, pid);
2743f84b207Sbeck 			HX((pid = getsid(pid)) == -1, pid);
2753f84b207Sbeck 			HX((pid = getppid()) == -1, pid);
2763f84b207Sbeck 			HX((pid = getpgid(0)) == -1, pid);
27754dec340Swouter 			HX((e = getpriority(0, 0)) == -1, e);
2783f84b207Sbeck 
2793f84b207Sbeck 			if (!faster) {
2803f84b207Sbeck 				ts.tv_sec = 0;
2813f84b207Sbeck 				ts.tv_nsec = 1;
2823f84b207Sbeck 				(void) nanosleep(&ts, NULL);
2833f84b207Sbeck 			}
2843f84b207Sbeck 
2853f84b207Sbeck 			HX(sigpending(&sigset) == -1, sigset);
2863f84b207Sbeck 			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
2873f84b207Sbeck 			    sigset);
2883f84b207Sbeck 
28954dec340Swouter 			HF(getentropy);	/* an addr in this library */
29054dec340Swouter 			HF(printf);		/* an addr in libc */
2913f84b207Sbeck 			p = (char *)&p;
2923f84b207Sbeck 			HD(p);		/* an addr on stack */
2933f84b207Sbeck 			p = (char *)&errno;
2943f84b207Sbeck 			HD(p);		/* the addr of errno */
2953f84b207Sbeck 
2963f84b207Sbeck 			if (i == 0) {
2973f84b207Sbeck 				struct sockaddr_storage ss;
2983f84b207Sbeck 				struct statvfs stvfs;
2993f84b207Sbeck 				struct termios tios;
3003f84b207Sbeck 				struct statfs stfs;
3013f84b207Sbeck 				socklen_t ssl;
3023f84b207Sbeck 				off_t off;
3033f84b207Sbeck 
3043f84b207Sbeck 				/*
3053f84b207Sbeck 				 * Prime-sized mappings encourage fragmentation;
3063f84b207Sbeck 				 * thus exposing some address entropy.
3073f84b207Sbeck 				 */
3083f84b207Sbeck 				struct mm {
3093f84b207Sbeck 					size_t	npg;
3103f84b207Sbeck 					void	*p;
3113f84b207Sbeck 				} mm[] =	 {
3123f84b207Sbeck 					{ 17, MAP_FAILED }, { 3, MAP_FAILED },
3133f84b207Sbeck 					{ 11, MAP_FAILED }, { 2, MAP_FAILED },
3143f84b207Sbeck 					{ 5, MAP_FAILED }, { 3, MAP_FAILED },
3153f84b207Sbeck 					{ 7, MAP_FAILED }, { 1, MAP_FAILED },
3163f84b207Sbeck 					{ 57, MAP_FAILED }, { 3, MAP_FAILED },
3173f84b207Sbeck 					{ 131, MAP_FAILED }, { 1, MAP_FAILED },
3183f84b207Sbeck 				};
3193f84b207Sbeck 
3203f84b207Sbeck 				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
3213f84b207Sbeck 					HX(mm[m].p = mmap(NULL,
3223f84b207Sbeck 					    mm[m].npg * pgs,
3233f84b207Sbeck 					    PROT_READ|PROT_WRITE,
3243f84b207Sbeck 					    MAP_PRIVATE|MAP_ANON, -1,
3253f84b207Sbeck 					    (off_t)0), mm[m].p);
3263f84b207Sbeck 					if (mm[m].p != MAP_FAILED) {
3273f84b207Sbeck 						size_t mo;
3283f84b207Sbeck 
3293f84b207Sbeck 						/* Touch some memory... */
3303f84b207Sbeck 						p = mm[m].p;
3313f84b207Sbeck 						mo = cnt %
3323f84b207Sbeck 						    (mm[m].npg * pgs - 1);
3333f84b207Sbeck 						p[mo] = 1;
3343f84b207Sbeck 						cnt += (int)((long)(mm[m].p)
3353f84b207Sbeck 						    / pgs);
3363f84b207Sbeck 					}
3373f84b207Sbeck 
3383f84b207Sbeck 					/* Check cnts and times... */
3393f84b207Sbeck 					mach_time = mach_absolute_time();
3403f84b207Sbeck 					HD(mach_time);
3413f84b207Sbeck 					cnt += (int)mach_time;
3423f84b207Sbeck 
3433f84b207Sbeck 					HX((e = getrusage(RUSAGE_SELF,
3443f84b207Sbeck 					    &ru)) == -1, ru);
3453f84b207Sbeck 					if (e != -1) {
3463f84b207Sbeck 						cnt += (int)ru.ru_utime.tv_sec;
3473f84b207Sbeck 						cnt += (int)ru.ru_utime.tv_usec;
3483f84b207Sbeck 					}
3493f84b207Sbeck 				}
3503f84b207Sbeck 
3513f84b207Sbeck 				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
3523f84b207Sbeck 					if (mm[m].p != MAP_FAILED)
3533f84b207Sbeck 						munmap(mm[m].p, mm[m].npg * pgs);
3543f84b207Sbeck 					mm[m].p = MAP_FAILED;
3553f84b207Sbeck 				}
3563f84b207Sbeck 
3573f84b207Sbeck 				HX(stat(".", &st) == -1, st);
3583f84b207Sbeck 				HX(statvfs(".", &stvfs) == -1, stvfs);
3593f84b207Sbeck 				HX(statfs(".", &stfs) == -1, stfs);
3603f84b207Sbeck 
3613f84b207Sbeck 				HX(stat("/", &st) == -1, st);
3623f84b207Sbeck 				HX(statvfs("/", &stvfs) == -1, stvfs);
3633f84b207Sbeck 				HX(statfs("/", &stfs) == -1, stfs);
3643f84b207Sbeck 
3653f84b207Sbeck 				HX((e = fstat(0, &st)) == -1, st);
3663f84b207Sbeck 				if (e == -1) {
3673f84b207Sbeck 					if (S_ISREG(st.st_mode) ||
3683f84b207Sbeck 					    S_ISFIFO(st.st_mode) ||
3693f84b207Sbeck 					    S_ISSOCK(st.st_mode)) {
3703f84b207Sbeck 						HX(fstatvfs(0, &stvfs) == -1,
3713f84b207Sbeck 						    stvfs);
3723f84b207Sbeck 						HX(fstatfs(0, &stfs) == -1,
3733f84b207Sbeck 						    stfs);
3743f84b207Sbeck 						HX((off = lseek(0, (off_t)0,
3753f84b207Sbeck 						    SEEK_CUR)) < 0, off);
3763f84b207Sbeck 					}
3773f84b207Sbeck 					if (S_ISCHR(st.st_mode)) {
3783f84b207Sbeck 						HX(tcgetattr(0, &tios) == -1,
3793f84b207Sbeck 						    tios);
3803f84b207Sbeck 					} else if (S_ISSOCK(st.st_mode)) {
3813f84b207Sbeck 						memset(&ss, 0, sizeof ss);
3823f84b207Sbeck 						ssl = sizeof(ss);
3833f84b207Sbeck 						HX(getpeername(0,
3843f84b207Sbeck 						    (void *)&ss, &ssl) == -1,
3853f84b207Sbeck 						    ss);
3863f84b207Sbeck 					}
3873f84b207Sbeck 				}
3883f84b207Sbeck 
3893f84b207Sbeck 				HX((e = getrusage(RUSAGE_CHILDREN,
3903f84b207Sbeck 				    &ru)) == -1, ru);
3913f84b207Sbeck 				if (e != -1) {
3923f84b207Sbeck 					cnt += (int)ru.ru_utime.tv_sec;
3933f84b207Sbeck 					cnt += (int)ru.ru_utime.tv_usec;
3943f84b207Sbeck 				}
3953f84b207Sbeck 			} else {
3963f84b207Sbeck 				/* Subsequent hashes absorb previous result */
3973f84b207Sbeck 				HD(results);
3983f84b207Sbeck 			}
3993f84b207Sbeck 
4003f84b207Sbeck 			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
4013f84b207Sbeck 			if (e != -1) {
4023f84b207Sbeck 				cnt += (int)tv.tv_sec;
4033f84b207Sbeck 				cnt += (int)tv.tv_usec;
4043f84b207Sbeck 			}
4053f84b207Sbeck 
4063f84b207Sbeck 			HD(cnt);
4073f84b207Sbeck 		}
4083f84b207Sbeck 
4093f84b207Sbeck 		SHA512_Final(results, &ctx);
410557f50beSderaadt 		memcpy((char *)buf + i, results, MINIMUM(sizeof(results), len - i));
411557f50beSderaadt 		i += MINIMUM(sizeof(results), len - i);
4123f84b207Sbeck 	}
4135fd8226cSguenther 	explicit_bzero(&ctx, sizeof ctx);
4145fd8226cSguenther 	explicit_bzero(results, sizeof results);
4153f84b207Sbeck 	errno = save_errno;
416044fc755Sderaadt 	return (0);		/* satisfied */
4173f84b207Sbeck }
418