xref: /openbsd-src/lib/libcrypto/arc4random/getentropy_solaris.c (revision b7041c0781c8668129da8084451ded41b0c43954)
1*b7041c07Sderaadt /*	$OpenBSD: getentropy_solaris.c,v 1.15 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 
233f84b207Sbeck #include <sys/types.h>
243f84b207Sbeck #include <sys/param.h>
253f84b207Sbeck #include <sys/ioctl.h>
263f84b207Sbeck #include <sys/resource.h>
273f84b207Sbeck #include <sys/syscall.h>
283f84b207Sbeck #include <sys/statvfs.h>
293f84b207Sbeck #include <sys/socket.h>
303f84b207Sbeck #include <sys/mount.h>
313f84b207Sbeck #include <sys/mman.h>
323f84b207Sbeck #include <sys/stat.h>
333f84b207Sbeck #include <sys/time.h>
343f84b207Sbeck #include <stdlib.h>
353f84b207Sbeck #include <stdint.h>
363f84b207Sbeck #include <stdio.h>
375a30a5b2Sderaadt #include <link.h>
383f84b207Sbeck #include <termios.h>
393f84b207Sbeck #include <fcntl.h>
403f84b207Sbeck #include <signal.h>
413f84b207Sbeck #include <string.h>
423f84b207Sbeck #include <errno.h>
433f84b207Sbeck #include <unistd.h>
443f84b207Sbeck #include <time.h>
453f84b207Sbeck #include <sys/sha2.h>
463f84b207Sbeck #define SHA512_Init SHA512Init
473f84b207Sbeck #define SHA512_Update SHA512Update
483f84b207Sbeck #define SHA512_Final SHA512Final
493f84b207Sbeck 
503f84b207Sbeck #include <sys/vfs.h>
513f84b207Sbeck #include <sys/statfs.h>
523f84b207Sbeck #include <sys/loadavg.h>
533f84b207Sbeck 
543f84b207Sbeck #define REPEAT 5
55557f50beSderaadt #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
563f84b207Sbeck 
573f84b207Sbeck #define HX(a, b) \
583f84b207Sbeck 	do { \
593f84b207Sbeck 		if ((a)) \
603f84b207Sbeck 			HD(errno); \
613f84b207Sbeck 		else \
623f84b207Sbeck 			HD(b); \
633f84b207Sbeck 	} while (0)
643f84b207Sbeck 
653f84b207Sbeck #define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
663f84b207Sbeck #define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
6754dec340Swouter #define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
683f84b207Sbeck 
693f84b207Sbeck int	getentropy(void *buf, size_t len);
703f84b207Sbeck 
71399b1dc5Sbeck static int getentropy_urandom(void *buf, size_t len, const char *path,
72399b1dc5Sbeck     int devfscheck);
733f84b207Sbeck static int getentropy_fallback(void *buf, size_t len);
745a30a5b2Sderaadt static int getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data);
753f84b207Sbeck 
763f84b207Sbeck int
getentropy(void * buf,size_t len)773f84b207Sbeck getentropy(void *buf, size_t len)
783f84b207Sbeck {
793f84b207Sbeck 	int ret = -1;
803f84b207Sbeck 
813f84b207Sbeck 	if (len > 256) {
823f84b207Sbeck 		errno = EIO;
83044fc755Sderaadt 		return (-1);
843f84b207Sbeck 	}
853f84b207Sbeck 
863f84b207Sbeck 	/*
87190c328cSderaadt 	 * Try to get entropy with /dev/urandom
88399b1dc5Sbeck 	 *
89399b1dc5Sbeck 	 * Solaris provides /dev/urandom as a symbolic link to
90399b1dc5Sbeck 	 * /devices/pseudo/random@0:urandom which is provided by
91399b1dc5Sbeck 	 * a devfs filesystem.  Best practice is to use O_NOFOLLOW,
92399b1dc5Sbeck 	 * so we must try the unpublished name directly.
93399b1dc5Sbeck 	 *
94399b1dc5Sbeck 	 * This can fail if the process is inside a chroot which lacks
95399b1dc5Sbeck 	 * the devfs mount, or if file descriptors are exhausted.
96399b1dc5Sbeck 	 */
97399b1dc5Sbeck 	ret = getentropy_urandom(buf, len,
98399b1dc5Sbeck 	    "/devices/pseudo/random@0:urandom", 1);
99399b1dc5Sbeck 	if (ret != -1)
100399b1dc5Sbeck 		return (ret);
101399b1dc5Sbeck 
102399b1dc5Sbeck 	/*
103399b1dc5Sbeck 	 * Unfortunately, chroot spaces on Solaris are sometimes setup
104399b1dc5Sbeck 	 * with direct device node of the well-known /dev/urandom name
105399b1dc5Sbeck 	 * (perhaps to avoid dragging all of devfs into the space).
1063f84b207Sbeck 	 *
1073f84b207Sbeck 	 * This can fail if the process is inside a chroot or if file
1083f84b207Sbeck 	 * descriptors are exhausted.
1093f84b207Sbeck 	 */
110399b1dc5Sbeck 	ret = getentropy_urandom(buf, len, "/dev/urandom", 0);
1113f84b207Sbeck 	if (ret != -1)
1123f84b207Sbeck 		return (ret);
113399b1dc5Sbeck 
1143f84b207Sbeck 	/*
115399b1dc5Sbeck 	 * Entropy collection via /dev/urandom has failed.
1163f84b207Sbeck 	 *
1173f84b207Sbeck 	 * No other API exists for collecting entropy, and we have
1183f84b207Sbeck 	 * no failsafe way to get it on Solaris that is not sensitive
1193f84b207Sbeck 	 * to resource exhaustion.
1203f84b207Sbeck 	 *
1213f84b207Sbeck 	 * We have very few options:
1223f84b207Sbeck 	 *     - Even syslog_r is unsafe to call at this low level, so
1233f84b207Sbeck 	 *	 there is no way to alert the user or program.
1243f84b207Sbeck 	 *     - Cannot call abort() because some systems have unsafe
1253f84b207Sbeck 	 *	 corefiles.
1263f84b207Sbeck 	 *     - Could raise(SIGKILL) resulting in silent program termination.
1273f84b207Sbeck 	 *     - Return EIO, to hint that arc4random's stir function
1283f84b207Sbeck 	 *       should raise(SIGKILL)
1293f84b207Sbeck 	 *     - Do the best under the circumstances....
1303f84b207Sbeck 	 *
1313f84b207Sbeck 	 * This code path exists to bring light to the issue that Solaris
1323f84b207Sbeck 	 * does not provide a failsafe API for entropy collection.
1333f84b207Sbeck 	 *
1343f84b207Sbeck 	 * We hope this demonstrates that Solaris should consider
1353f84b207Sbeck 	 * providing a new failsafe API which works in a chroot or
1363f84b207Sbeck 	 * when file descriptors are exhausted.
1373f84b207Sbeck 	 */
138190c328cSderaadt #undef FAIL_INSTEAD_OF_TRYING_FALLBACK
139190c328cSderaadt #ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
1403f84b207Sbeck 	raise(SIGKILL);
1413f84b207Sbeck #endif
1423f84b207Sbeck 	ret = getentropy_fallback(buf, len);
1433f84b207Sbeck 	if (ret != -1)
1443f84b207Sbeck 		return (ret);
1453f84b207Sbeck 
1463f84b207Sbeck 	errno = EIO;
1473f84b207Sbeck 	return (ret);
1483f84b207Sbeck }
1493f84b207Sbeck 
1503f84b207Sbeck static int
getentropy_urandom(void * buf,size_t len,const char * path,int devfscheck)151399b1dc5Sbeck getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck)
1523f84b207Sbeck {
1533f84b207Sbeck 	struct stat st;
1543f84b207Sbeck 	size_t i;
1553f84b207Sbeck 	int fd, flags;
1563f84b207Sbeck 	int save_errno = errno;
1573f84b207Sbeck 
1583f84b207Sbeck start:
1593f84b207Sbeck 
1603f84b207Sbeck 	flags = O_RDONLY;
1613f84b207Sbeck #ifdef O_NOFOLLOW
1623f84b207Sbeck 	flags |= O_NOFOLLOW;
1633f84b207Sbeck #endif
1643f84b207Sbeck #ifdef O_CLOEXEC
1653f84b207Sbeck 	flags |= O_CLOEXEC;
1663f84b207Sbeck #endif
167*b7041c07Sderaadt 	fd = open(path, flags);
1683f84b207Sbeck 	if (fd == -1) {
1693f84b207Sbeck 		if (errno == EINTR)
1703f84b207Sbeck 			goto start;
1713f84b207Sbeck 		goto nodevrandom;
1723f84b207Sbeck 	}
1733f84b207Sbeck #ifndef O_CLOEXEC
1743f84b207Sbeck 	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
1753f84b207Sbeck #endif
1763f84b207Sbeck 
1773f84b207Sbeck 	/* Lightly verify that the device node looks sane */
178399b1dc5Sbeck 	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode) ||
179399b1dc5Sbeck 	    (devfscheck && (strcmp(st.st_fstype, "devfs") != 0))) {
1803f84b207Sbeck 		close(fd);
1813f84b207Sbeck 		goto nodevrandom;
1823f84b207Sbeck 	}
1833f84b207Sbeck 	for (i = 0; i < len; ) {
1843f84b207Sbeck 		size_t wanted = len - i;
18554dec340Swouter 		ssize_t ret = read(fd, (char *)buf + i, wanted);
1863f84b207Sbeck 
1873f84b207Sbeck 		if (ret == -1) {
1883f84b207Sbeck 			if (errno == EAGAIN || errno == EINTR)
1893f84b207Sbeck 				continue;
1903f84b207Sbeck 			close(fd);
1913f84b207Sbeck 			goto nodevrandom;
1923f84b207Sbeck 		}
1933f84b207Sbeck 		i += ret;
1943f84b207Sbeck 	}
1953f84b207Sbeck 	close(fd);
1963f84b207Sbeck 	errno = save_errno;
197044fc755Sderaadt 	return (0);		/* satisfied */
1983f84b207Sbeck nodevrandom:
1993f84b207Sbeck 	errno = EIO;
200044fc755Sderaadt 	return (-1);
2013f84b207Sbeck }
2023f84b207Sbeck 
203190c328cSderaadt static const int cl[] = {
2043f84b207Sbeck 	CLOCK_REALTIME,
2053f84b207Sbeck #ifdef CLOCK_MONOTONIC
2063f84b207Sbeck 	CLOCK_MONOTONIC,
2073f84b207Sbeck #endif
2083f84b207Sbeck #ifdef CLOCK_MONOTONIC_RAW
2093f84b207Sbeck 	CLOCK_MONOTONIC_RAW,
2103f84b207Sbeck #endif
2113f84b207Sbeck #ifdef CLOCK_TAI
2123f84b207Sbeck 	CLOCK_TAI,
2133f84b207Sbeck #endif
2143f84b207Sbeck #ifdef CLOCK_VIRTUAL
2153f84b207Sbeck 	CLOCK_VIRTUAL,
2163f84b207Sbeck #endif
2173f84b207Sbeck #ifdef CLOCK_UPTIME
2183f84b207Sbeck 	CLOCK_UPTIME,
2193f84b207Sbeck #endif
2203f84b207Sbeck #ifdef CLOCK_PROCESS_CPUTIME_ID
2213f84b207Sbeck 	CLOCK_PROCESS_CPUTIME_ID,
2223f84b207Sbeck #endif
2233f84b207Sbeck #ifdef CLOCK_THREAD_CPUTIME_ID
2243f84b207Sbeck 	CLOCK_THREAD_CPUTIME_ID,
2253f84b207Sbeck #endif
2263f84b207Sbeck };
2273f84b207Sbeck 
2283f84b207Sbeck static int
getentropy_phdr(struct dl_phdr_info * info,size_t size,void * data)2295a30a5b2Sderaadt getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data)
2305a30a5b2Sderaadt {
2315a30a5b2Sderaadt 	SHA512_CTX *ctx = data;
2325a30a5b2Sderaadt 
2335a30a5b2Sderaadt 	SHA512_Update(ctx, &info->dlpi_addr, sizeof (info->dlpi_addr));
234044fc755Sderaadt 	return (0);
2355a30a5b2Sderaadt }
2365a30a5b2Sderaadt 
2375a30a5b2Sderaadt static int
getentropy_fallback(void * buf,size_t len)2383f84b207Sbeck getentropy_fallback(void *buf, size_t len)
2393f84b207Sbeck {
2403f84b207Sbeck 	uint8_t results[SHA512_DIGEST_LENGTH];
24154dec340Swouter 	int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
2423f84b207Sbeck 	static int cnt;
2433f84b207Sbeck 	struct timespec ts;
2443f84b207Sbeck 	struct timeval tv;
2453f84b207Sbeck 	double loadavg[3];
2463f84b207Sbeck 	struct rusage ru;
2473f84b207Sbeck 	sigset_t sigset;
2483f84b207Sbeck 	struct stat st;
2493f84b207Sbeck 	SHA512_CTX ctx;
2503f84b207Sbeck 	static pid_t lastpid;
2513f84b207Sbeck 	pid_t pid;
25254dec340Swouter 	size_t i, ii, m;
2533f84b207Sbeck 	char *p;
2543f84b207Sbeck 
2553f84b207Sbeck 	pid = getpid();
2563f84b207Sbeck 	if (lastpid == pid) {
2573f84b207Sbeck 		faster = 1;
2583f84b207Sbeck 		repeat = 2;
2593f84b207Sbeck 	} else {
2603f84b207Sbeck 		faster = 0;
2613f84b207Sbeck 		lastpid = pid;
2623f84b207Sbeck 		repeat = REPEAT;
2633f84b207Sbeck 	}
2643f84b207Sbeck 	for (i = 0; i < len; ) {
2653f84b207Sbeck 		int j;
2663f84b207Sbeck 		SHA512_Init(&ctx);
2673f84b207Sbeck 		for (j = 0; j < repeat; j++) {
2683f84b207Sbeck 			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
2693f84b207Sbeck 			if (e != -1) {
2703f84b207Sbeck 				cnt += (int)tv.tv_sec;
2713f84b207Sbeck 				cnt += (int)tv.tv_usec;
2723f84b207Sbeck 			}
2733f84b207Sbeck 
2745a30a5b2Sderaadt 			dl_iterate_phdr(getentropy_phdr, &ctx);
2755a30a5b2Sderaadt 
2763f84b207Sbeck 			for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
2773f84b207Sbeck 				HX(clock_gettime(cl[ii], &ts) == -1, ts);
278190c328cSderaadt 
2793f84b207Sbeck 			HX((pid = getpid()) == -1, pid);
2803f84b207Sbeck 			HX((pid = getsid(pid)) == -1, pid);
2813f84b207Sbeck 			HX((pid = getppid()) == -1, pid);
2823f84b207Sbeck 			HX((pid = getpgid(0)) == -1, pid);
28354dec340Swouter 			HX((e = getpriority(0, 0)) == -1, e);
2843f84b207Sbeck 			HX((getloadavg(loadavg, 3) == -1), loadavg);
2853f84b207Sbeck 
2863f84b207Sbeck 			if (!faster) {
2873f84b207Sbeck 				ts.tv_sec = 0;
2883f84b207Sbeck 				ts.tv_nsec = 1;
2893f84b207Sbeck 				(void) nanosleep(&ts, NULL);
2903f84b207Sbeck 			}
2913f84b207Sbeck 
2923f84b207Sbeck 			HX(sigpending(&sigset) == -1, sigset);
2933f84b207Sbeck 			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
2943f84b207Sbeck 			    sigset);
2953f84b207Sbeck 
29654dec340Swouter 			HF(getentropy);	/* an addr in this library */
29754dec340Swouter 			HF(printf);		/* an addr in libc */
2983f84b207Sbeck 			p = (char *)&p;
2993f84b207Sbeck 			HD(p);		/* an addr on stack */
3003f84b207Sbeck 			p = (char *)&errno;
3013f84b207Sbeck 			HD(p);		/* the addr of errno */
3023f84b207Sbeck 
3033f84b207Sbeck 			if (i == 0) {
3043f84b207Sbeck 				struct sockaddr_storage ss;
3053f84b207Sbeck 				struct statvfs stvfs;
3063f84b207Sbeck 				struct termios tios;
3073f84b207Sbeck 				socklen_t ssl;
3083f84b207Sbeck 				off_t off;
3093f84b207Sbeck 
3103f84b207Sbeck 				/*
3113f84b207Sbeck 				 * Prime-sized mappings encourage fragmentation;
3123f84b207Sbeck 				 * thus exposing some address entropy.
3133f84b207Sbeck 				 */
3143f84b207Sbeck 				struct mm {
3153f84b207Sbeck 					size_t	npg;
3163f84b207Sbeck 					void	*p;
3173f84b207Sbeck 				} mm[] =	 {
3183f84b207Sbeck 					{ 17, MAP_FAILED }, { 3, MAP_FAILED },
3193f84b207Sbeck 					{ 11, MAP_FAILED }, { 2, MAP_FAILED },
3203f84b207Sbeck 					{ 5, MAP_FAILED }, { 3, MAP_FAILED },
3213f84b207Sbeck 					{ 7, MAP_FAILED }, { 1, MAP_FAILED },
3223f84b207Sbeck 					{ 57, MAP_FAILED }, { 3, MAP_FAILED },
3233f84b207Sbeck 					{ 131, MAP_FAILED }, { 1, MAP_FAILED },
3243f84b207Sbeck 				};
3253f84b207Sbeck 
3263f84b207Sbeck 				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
3273f84b207Sbeck 					HX(mm[m].p = mmap(NULL,
3283f84b207Sbeck 					    mm[m].npg * pgs,
3293f84b207Sbeck 					    PROT_READ|PROT_WRITE,
3303f84b207Sbeck 					    MAP_PRIVATE|MAP_ANON, -1,
3313f84b207Sbeck 					    (off_t)0), mm[m].p);
3323f84b207Sbeck 					if (mm[m].p != MAP_FAILED) {
3333f84b207Sbeck 						size_t mo;
3343f84b207Sbeck 
3353f84b207Sbeck 						/* Touch some memory... */
3363f84b207Sbeck 						p = mm[m].p;
3373f84b207Sbeck 						mo = cnt %
3383f84b207Sbeck 						    (mm[m].npg * pgs - 1);
3393f84b207Sbeck 						p[mo] = 1;
3403f84b207Sbeck 						cnt += (int)((long)(mm[m].p)
3413f84b207Sbeck 						    / pgs);
3423f84b207Sbeck 					}
3433f84b207Sbeck 
3443f84b207Sbeck 					/* Check cnts and times... */
3453f84b207Sbeck 					for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]);
3463f84b207Sbeck 					    ii++) {
3473f84b207Sbeck 						HX((e = clock_gettime(cl[ii],
3483f84b207Sbeck 						    &ts)) == -1, ts);
3493f84b207Sbeck 						if (e != -1)
3503f84b207Sbeck 							cnt += (int)ts.tv_nsec;
3513f84b207Sbeck 					}
3523f84b207Sbeck 
3533f84b207Sbeck 					HX((e = getrusage(RUSAGE_SELF,
3543f84b207Sbeck 					    &ru)) == -1, ru);
3553f84b207Sbeck 					if (e != -1) {
3563f84b207Sbeck 						cnt += (int)ru.ru_utime.tv_sec;
3573f84b207Sbeck 						cnt += (int)ru.ru_utime.tv_usec;
3583f84b207Sbeck 					}
3593f84b207Sbeck 				}
3603f84b207Sbeck 
3613f84b207Sbeck 				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
3623f84b207Sbeck 					if (mm[m].p != MAP_FAILED)
3633f84b207Sbeck 						munmap(mm[m].p, mm[m].npg * pgs);
3643f84b207Sbeck 					mm[m].p = MAP_FAILED;
3653f84b207Sbeck 				}
3663f84b207Sbeck 
3673f84b207Sbeck 				HX(stat(".", &st) == -1, st);
3683f84b207Sbeck 				HX(statvfs(".", &stvfs) == -1, stvfs);
3693f84b207Sbeck 
3703f84b207Sbeck 				HX(stat("/", &st) == -1, st);
3713f84b207Sbeck 				HX(statvfs("/", &stvfs) == -1, stvfs);
3723f84b207Sbeck 
3733f84b207Sbeck 				HX((e = fstat(0, &st)) == -1, st);
3743f84b207Sbeck 				if (e == -1) {
3753f84b207Sbeck 					if (S_ISREG(st.st_mode) ||
3763f84b207Sbeck 					    S_ISFIFO(st.st_mode) ||
3773f84b207Sbeck 					    S_ISSOCK(st.st_mode)) {
3783f84b207Sbeck 						HX(fstatvfs(0, &stvfs) == -1,
3793f84b207Sbeck 						    stvfs);
3803f84b207Sbeck 						HX((off = lseek(0, (off_t)0,
3813f84b207Sbeck 						    SEEK_CUR)) < 0, off);
3823f84b207Sbeck 					}
3833f84b207Sbeck 					if (S_ISCHR(st.st_mode)) {
3843f84b207Sbeck 						HX(tcgetattr(0, &tios) == -1,
3853f84b207Sbeck 						    tios);
3863f84b207Sbeck 					} else if (S_ISSOCK(st.st_mode)) {
3873f84b207Sbeck 						memset(&ss, 0, sizeof ss);
3883f84b207Sbeck 						ssl = sizeof(ss);
3893f84b207Sbeck 						HX(getpeername(0,
3903f84b207Sbeck 						    (void *)&ss, &ssl) == -1,
3913f84b207Sbeck 						    ss);
3923f84b207Sbeck 					}
3933f84b207Sbeck 				}
3943f84b207Sbeck 
3953f84b207Sbeck 				HX((e = getrusage(RUSAGE_CHILDREN,
3963f84b207Sbeck 				    &ru)) == -1, ru);
3973f84b207Sbeck 				if (e != -1) {
3983f84b207Sbeck 					cnt += (int)ru.ru_utime.tv_sec;
3993f84b207Sbeck 					cnt += (int)ru.ru_utime.tv_usec;
4003f84b207Sbeck 				}
4013f84b207Sbeck 			} else {
4023f84b207Sbeck 				/* Subsequent hashes absorb previous result */
4033f84b207Sbeck 				HD(results);
4043f84b207Sbeck 			}
4053f84b207Sbeck 
4063f84b207Sbeck 			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
4073f84b207Sbeck 			if (e != -1) {
4083f84b207Sbeck 				cnt += (int)tv.tv_sec;
4093f84b207Sbeck 				cnt += (int)tv.tv_usec;
4103f84b207Sbeck 			}
4113f84b207Sbeck 
4123f84b207Sbeck 			HD(cnt);
4133f84b207Sbeck 		}
4143f84b207Sbeck 		SHA512_Final(results, &ctx);
415557f50beSderaadt 		memcpy((char *)buf + i, results, MINIMUM(sizeof(results), len - i));
416557f50beSderaadt 		i += MINIMUM(sizeof(results), len - i);
4173f84b207Sbeck 	}
4185fd8226cSguenther 	explicit_bzero(&ctx, sizeof ctx);
4195fd8226cSguenther 	explicit_bzero(results, sizeof results);
4203f84b207Sbeck 	errno = save_errno;
421044fc755Sderaadt 	return (0);		/* satisfied */
4223f84b207Sbeck }
423