1*b7041c07Sderaadt /* $OpenBSD: getentropy_linux.c,v 1.48 2021/10/24 21:24:20 deraadt 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.
18b5f12122Sderaadt *
19b5f12122Sderaadt * Emulation of getentropy(2) as documented at:
20b8461433Stb * http://man.openbsd.org/getentropy.2
218286e41bSbeck */
228286e41bSbeck
238286e41bSbeck #define _POSIX_C_SOURCE 199309L
248286e41bSbeck #define _GNU_SOURCE 1
258286e41bSbeck #include <sys/types.h>
268286e41bSbeck #include <sys/param.h>
278286e41bSbeck #include <sys/ioctl.h>
288286e41bSbeck #include <sys/resource.h>
298286e41bSbeck #include <sys/syscall.h>
303e3a5746Sbcook #ifdef SYS__sysctl
313e3a5746Sbcook #include <linux/sysctl.h>
3280de5d26Sbeck #endif
338286e41bSbeck #include <sys/statvfs.h>
348286e41bSbeck #include <sys/socket.h>
358286e41bSbeck #include <sys/mount.h>
368286e41bSbeck #include <sys/mman.h>
378286e41bSbeck #include <sys/stat.h>
388286e41bSbeck #include <sys/time.h>
398286e41bSbeck #include <stdlib.h>
408286e41bSbeck #include <stdint.h>
418286e41bSbeck #include <stdio.h>
425a30a5b2Sderaadt #include <link.h>
438286e41bSbeck #include <termios.h>
448286e41bSbeck #include <fcntl.h>
458286e41bSbeck #include <signal.h>
468286e41bSbeck #include <string.h>
478286e41bSbeck #include <errno.h>
488286e41bSbeck #include <unistd.h>
498286e41bSbeck #include <time.h>
508286e41bSbeck #include <openssl/sha.h>
518286e41bSbeck
522ce34de7Sbcook #include <linux/types.h>
538286e41bSbeck #include <linux/random.h>
544f735644Sbeck #ifdef HAVE_GETAUXVAL
554f735644Sbeck #include <sys/auxv.h>
564f735644Sbeck #endif
578286e41bSbeck #include <sys/vfs.h>
588286e41bSbeck
598286e41bSbeck #define REPEAT 5
60557f50beSderaadt #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
618286e41bSbeck
6256419eb2Sderaadt #define HX(a, b) \
638286e41bSbeck do { \
648286e41bSbeck if ((a)) \
6556419eb2Sderaadt HD(errno); \
668286e41bSbeck else \
6756419eb2Sderaadt HD(b); \
688286e41bSbeck } while (0)
698286e41bSbeck
704f735644Sbeck #define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
714f735644Sbeck #define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
7254dec340Swouter #define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
738286e41bSbeck
748286e41bSbeck int getentropy(void *buf, size_t len);
758286e41bSbeck
76e698281dSbcook #if defined(SYS_getrandom) && defined(GRND_NONBLOCK)
77fea29d55Sderaadt static int getentropy_getrandom(void *buf, size_t len);
78dc80d86aSbcook #endif
7995438510Sotto static int getentropy_urandom(void *buf, size_t len);
806cb1baa1Sderaadt #ifdef SYS__sysctl
8195438510Sotto static int getentropy_sysctl(void *buf, size_t len);
823279ccb0Sbeck #endif
8395438510Sotto static int getentropy_fallback(void *buf, size_t len);
845a30a5b2Sderaadt static int getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data);
8595438510Sotto
8695438510Sotto int
getentropy(void * buf,size_t len)8795438510Sotto getentropy(void *buf, size_t len)
8895438510Sotto {
8995438510Sotto int ret = -1;
9095438510Sotto
9195438510Sotto if (len > 256) {
9295438510Sotto errno = EIO;
93044fc755Sderaadt return (-1);
9495438510Sotto }
9595438510Sotto
96e698281dSbcook #if defined(SYS_getrandom) && defined(GRND_NONBLOCK)
9795438510Sotto /*
98edb2eeb7Sbeck * Try descriptor-less getrandom(), in non-blocking mode.
99edb2eeb7Sbeck *
100edb2eeb7Sbeck * The design of Linux getrandom is broken. It has an
101edb2eeb7Sbeck * uninitialized phase coupled with blocking behaviour, which
102edb2eeb7Sbeck * is unacceptable from within a library at boot time without
103edb2eeb7Sbeck * possible recovery. See http://bugs.python.org/issue26839#msg267745
104fea29d55Sderaadt */
105fea29d55Sderaadt ret = getentropy_getrandom(buf, len);
106fea29d55Sderaadt if (ret != -1)
107fea29d55Sderaadt return (ret);
108dc80d86aSbcook #endif
109fea29d55Sderaadt
110fea29d55Sderaadt /*
11195438510Sotto * Try to get entropy with /dev/urandom
11295438510Sotto *
11395438510Sotto * This can fail if the process is inside a chroot or if file
11495438510Sotto * descriptors are exhausted.
11595438510Sotto */
11695438510Sotto ret = getentropy_urandom(buf, len);
11795438510Sotto if (ret != -1)
11895438510Sotto return (ret);
11995438510Sotto
1206cb1baa1Sderaadt #ifdef SYS__sysctl
12195438510Sotto /*
12293d8086cSbeck * Try to use sysctl CTL_KERN, KERN_RANDOM, RANDOM_UUID.
12393d8086cSbeck * sysctl is a failsafe API, so it guarantees a result. This
12493d8086cSbeck * should work inside a chroot, or when file descriptors are
1252e9828cbStj * exhausted.
12695438510Sotto *
12793d8086cSbeck * However this can fail if the Linux kernel removes support
12893d8086cSbeck * for sysctl. Starting in 2007, there have been efforts to
12993d8086cSbeck * deprecate the sysctl API/ABI, and push callers towards use
13093d8086cSbeck * of the chroot-unavailable fd-using /proc mechanism --
13193d8086cSbeck * essentially the same problems as /dev/urandom.
13295438510Sotto *
13395438510Sotto * Numerous setbacks have been encountered in their deprecation
134edcadc37Sbeck * schedule, so as of June 2014 the kernel ABI still exists on
135edcadc37Sbeck * most Linux architectures. The sysctl() stub in libc is missing
136edcadc37Sbeck * on some systems. There are also reports that some kernels
137edcadc37Sbeck * spew messages to the console.
13895438510Sotto */
13995438510Sotto ret = getentropy_sysctl(buf, len);
14095438510Sotto if (ret != -1)
14195438510Sotto return (ret);
1426cb1baa1Sderaadt #endif /* SYS__sysctl */
14395438510Sotto
14495438510Sotto /*
14595438510Sotto * Entropy collection via /dev/urandom and sysctl have failed.
14695438510Sotto *
14795438510Sotto * No other API exists for collecting entropy. See the large
14895438510Sotto * comment block above.
14995438510Sotto *
15095438510Sotto * We have very few options:
15195438510Sotto * - Even syslog_r is unsafe to call at this low level, so
15295438510Sotto * there is no way to alert the user or program.
15393d8086cSbeck * - Cannot call abort() because some systems have unsafe
15493d8086cSbeck * corefiles.
15595438510Sotto * - Could raise(SIGKILL) resulting in silent program termination.
15695438510Sotto * - Return EIO, to hint that arc4random's stir function
15795438510Sotto * should raise(SIGKILL)
15895438510Sotto * - Do the best under the circumstances....
15995438510Sotto *
16095438510Sotto * This code path exists to bring light to the issue that Linux
161edb2eeb7Sbeck * still does not provide a failsafe API for entropy collection.
16295438510Sotto *
16395438510Sotto * We hope this demonstrates that Linux should either retain their
16495438510Sotto * sysctl ABI, or consider providing a new failsafe API which
16595438510Sotto * works in a chroot or when file descriptors are exhausted.
16695438510Sotto */
167190c328cSderaadt #undef FAIL_INSTEAD_OF_TRYING_FALLBACK
168190c328cSderaadt #ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
16995438510Sotto raise(SIGKILL);
17095438510Sotto #endif
17195438510Sotto ret = getentropy_fallback(buf, len);
17295438510Sotto if (ret != -1)
17395438510Sotto return (ret);
17495438510Sotto
17595438510Sotto errno = EIO;
17695438510Sotto return (ret);
17795438510Sotto }
1788286e41bSbeck
179e698281dSbcook #if defined(SYS_getrandom) && defined(GRND_NONBLOCK)
1808286e41bSbeck static int
getentropy_getrandom(void * buf,size_t len)181fea29d55Sderaadt getentropy_getrandom(void *buf, size_t len)
182fea29d55Sderaadt {
1833237117aSbcook int pre_errno = errno;
184aac66879Sbcook int ret;
185fea29d55Sderaadt if (len > 256)
186fea29d55Sderaadt return (-1);
187aac66879Sbcook do {
188edb2eeb7Sbeck ret = syscall(SYS_getrandom, buf, len, GRND_NONBLOCK);
189aac66879Sbcook } while (ret == -1 && errno == EINTR);
190aac66879Sbcook
1913237117aSbcook if (ret != len)
192aac66879Sbcook return (-1);
1933237117aSbcook errno = pre_errno;
1943237117aSbcook return (0);
195fea29d55Sderaadt }
196dc80d86aSbcook #endif
197fea29d55Sderaadt
198fea29d55Sderaadt static int
getentropy_urandom(void * buf,size_t len)1998286e41bSbeck getentropy_urandom(void *buf, size_t len)
2008286e41bSbeck {
2018286e41bSbeck struct stat st;
2028286e41bSbeck size_t i;
203f155de65Sbeck int fd, cnt, flags;
2048286e41bSbeck int save_errno = errno;
2058286e41bSbeck
2068286e41bSbeck start:
207f155de65Sbeck
208f155de65Sbeck flags = O_RDONLY;
209f155de65Sbeck #ifdef O_NOFOLLOW
210f155de65Sbeck flags |= O_NOFOLLOW;
211f155de65Sbeck #endif
2128286e41bSbeck #ifdef O_CLOEXEC
213f155de65Sbeck flags |= O_CLOEXEC;
214f155de65Sbeck #endif
215*b7041c07Sderaadt fd = open("/dev/urandom", flags);
2168286e41bSbeck if (fd == -1) {
2178286e41bSbeck if (errno == EINTR)
2188286e41bSbeck goto start;
2198286e41bSbeck goto nodevrandom;
2208286e41bSbeck }
221f155de65Sbeck #ifndef O_CLOEXEC
2228286e41bSbeck fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
2238286e41bSbeck #endif
2248286e41bSbeck
2258286e41bSbeck /* Lightly verify that the device node looks sane */
2268286e41bSbeck if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
2278286e41bSbeck close(fd);
2288286e41bSbeck goto nodevrandom;
2298286e41bSbeck }
2308286e41bSbeck if (ioctl(fd, RNDGETENTCNT, &cnt) == -1) {
2318286e41bSbeck close(fd);
2328286e41bSbeck goto nodevrandom;
2338286e41bSbeck }
2348286e41bSbeck for (i = 0; i < len; ) {
2358286e41bSbeck size_t wanted = len - i;
23654dec340Swouter ssize_t ret = read(fd, (char *)buf + i, wanted);
2378286e41bSbeck
2388286e41bSbeck if (ret == -1) {
2398286e41bSbeck if (errno == EAGAIN || errno == EINTR)
2408286e41bSbeck continue;
2418286e41bSbeck close(fd);
2428286e41bSbeck goto nodevrandom;
2438286e41bSbeck }
2448286e41bSbeck i += ret;
2458286e41bSbeck }
2468286e41bSbeck close(fd);
2478286e41bSbeck errno = save_errno;
248044fc755Sderaadt return (0); /* satisfied */
2498286e41bSbeck nodevrandom:
2508286e41bSbeck errno = EIO;
251044fc755Sderaadt return (-1);
2528286e41bSbeck }
2538286e41bSbeck
2546cb1baa1Sderaadt #ifdef SYS__sysctl
2558286e41bSbeck static int
getentropy_sysctl(void * buf,size_t len)2568286e41bSbeck getentropy_sysctl(void *buf, size_t len)
2578286e41bSbeck {
2583279ccb0Sbeck static int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
25954dec340Swouter size_t i;
2608286e41bSbeck int save_errno = errno;
2618286e41bSbeck
2628286e41bSbeck for (i = 0; i < len; ) {
263557f50beSderaadt size_t chunk = MINIMUM(len - i, 16);
2648286e41bSbeck
2658286e41bSbeck /* SYS__sysctl because some systems already removed sysctl() */
2668286e41bSbeck struct __sysctl_args args = {
2678286e41bSbeck .name = mib,
2688286e41bSbeck .nlen = 3,
269b8457ac7Sderaadt .oldval = (char *)buf + i,
2708286e41bSbeck .oldlenp = &chunk,
2718286e41bSbeck };
2728286e41bSbeck if (syscall(SYS__sysctl, &args) != 0)
2738286e41bSbeck goto sysctlfailed;
2748286e41bSbeck i += chunk;
2758286e41bSbeck }
2768286e41bSbeck errno = save_errno;
2778286e41bSbeck return (0); /* satisfied */
2788286e41bSbeck sysctlfailed:
2798286e41bSbeck errno = EIO;
280044fc755Sderaadt return (-1);
2818286e41bSbeck }
2826cb1baa1Sderaadt #endif /* SYS__sysctl */
2838286e41bSbeck
284092b0306Sderaadt static const int cl[] = {
2858286e41bSbeck CLOCK_REALTIME,
2868286e41bSbeck #ifdef CLOCK_MONOTONIC
2878286e41bSbeck CLOCK_MONOTONIC,
2888286e41bSbeck #endif
2898286e41bSbeck #ifdef CLOCK_MONOTONIC_RAW
2908286e41bSbeck CLOCK_MONOTONIC_RAW,
2918286e41bSbeck #endif
2928286e41bSbeck #ifdef CLOCK_TAI
2938286e41bSbeck CLOCK_TAI,
2948286e41bSbeck #endif
2958286e41bSbeck #ifdef CLOCK_VIRTUAL
2968286e41bSbeck CLOCK_VIRTUAL,
2978286e41bSbeck #endif
2988286e41bSbeck #ifdef CLOCK_UPTIME
2998286e41bSbeck CLOCK_UPTIME,
3008286e41bSbeck #endif
3018286e41bSbeck #ifdef CLOCK_PROCESS_CPUTIME_ID
3028286e41bSbeck CLOCK_PROCESS_CPUTIME_ID,
3038286e41bSbeck #endif
3048286e41bSbeck #ifdef CLOCK_THREAD_CPUTIME_ID
3058286e41bSbeck CLOCK_THREAD_CPUTIME_ID,
3068286e41bSbeck #endif
3078286e41bSbeck };
3088286e41bSbeck
3098286e41bSbeck static int
getentropy_phdr(struct dl_phdr_info * info,size_t size,void * data)3105a30a5b2Sderaadt getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data)
3115a30a5b2Sderaadt {
3125a30a5b2Sderaadt SHA512_CTX *ctx = data;
3135a30a5b2Sderaadt
3145a30a5b2Sderaadt SHA512_Update(ctx, &info->dlpi_addr, sizeof (info->dlpi_addr));
315044fc755Sderaadt return (0);
3165a30a5b2Sderaadt }
3175a30a5b2Sderaadt
3185a30a5b2Sderaadt static int
getentropy_fallback(void * buf,size_t len)3198286e41bSbeck getentropy_fallback(void *buf, size_t len)
3208286e41bSbeck {
3218286e41bSbeck uint8_t results[SHA512_DIGEST_LENGTH];
32254dec340Swouter int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
32356419eb2Sderaadt static int cnt;
3248286e41bSbeck struct timespec ts;
3258286e41bSbeck struct timeval tv;
3268286e41bSbeck struct rusage ru;
3278286e41bSbeck sigset_t sigset;
3288286e41bSbeck struct stat st;
3298286e41bSbeck SHA512_CTX ctx;
330581198e5Sderaadt static pid_t lastpid;
3318286e41bSbeck pid_t pid;
33254dec340Swouter size_t i, ii, m;
33356419eb2Sderaadt char *p;
3348286e41bSbeck
335581198e5Sderaadt pid = getpid();
336203e5dbfSbeck if (lastpid == pid) {
337203e5dbfSbeck faster = 1;
338203e5dbfSbeck repeat = 2;
339203e5dbfSbeck } else {
340203e5dbfSbeck faster = 0;
341581198e5Sderaadt lastpid = pid;
342203e5dbfSbeck repeat = REPEAT;
343203e5dbfSbeck }
3448286e41bSbeck for (i = 0; i < len; ) {
345e4e2062fSbeck int j;
3468286e41bSbeck SHA512_Init(&ctx);
347203e5dbfSbeck for (j = 0; j < repeat; j++) {
34856419eb2Sderaadt HX((e = gettimeofday(&tv, NULL)) == -1, tv);
3498286e41bSbeck if (e != -1) {
35056419eb2Sderaadt cnt += (int)tv.tv_sec;
35180a8e717Sbeck cnt += (int)tv.tv_usec;
3528286e41bSbeck }
3538286e41bSbeck
3545a30a5b2Sderaadt dl_iterate_phdr(getentropy_phdr, &ctx);
3555a30a5b2Sderaadt
3568286e41bSbeck for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
35756419eb2Sderaadt HX(clock_gettime(cl[ii], &ts) == -1, ts);
3588286e41bSbeck
35956419eb2Sderaadt HX((pid = getpid()) == -1, pid);
36056419eb2Sderaadt HX((pid = getsid(pid)) == -1, pid);
36156419eb2Sderaadt HX((pid = getppid()) == -1, pid);
36256419eb2Sderaadt HX((pid = getpgid(0)) == -1, pid);
36354dec340Swouter HX((e = getpriority(0, 0)) == -1, e);
3648286e41bSbeck
365203e5dbfSbeck if (!faster) {
3668286e41bSbeck ts.tv_sec = 0;
3678286e41bSbeck ts.tv_nsec = 1;
3688286e41bSbeck (void) nanosleep(&ts, NULL);
369203e5dbfSbeck }
3708286e41bSbeck
37156419eb2Sderaadt HX(sigpending(&sigset) == -1, sigset);
37256419eb2Sderaadt HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
37393d8086cSbeck sigset);
3748286e41bSbeck
37554dec340Swouter HF(getentropy); /* an addr in this library */
37654dec340Swouter HF(printf); /* an addr in libc */
37756419eb2Sderaadt p = (char *)&p;
37856419eb2Sderaadt HD(p); /* an addr on stack */
37956419eb2Sderaadt p = (char *)&errno;
38056419eb2Sderaadt HD(p); /* the addr of errno */
3818286e41bSbeck
3828286e41bSbeck if (i == 0) {
3838286e41bSbeck struct sockaddr_storage ss;
3848286e41bSbeck struct statvfs stvfs;
3858286e41bSbeck struct termios tios;
3868286e41bSbeck struct statfs stfs;
3878286e41bSbeck socklen_t ssl;
3888286e41bSbeck off_t off;
3898286e41bSbeck
3908286e41bSbeck /*
3918286e41bSbeck * Prime-sized mappings encourage fragmentation;
3928286e41bSbeck * thus exposing some address entropy.
3938286e41bSbeck */
3948286e41bSbeck struct mm {
3958286e41bSbeck size_t npg;
3968286e41bSbeck void *p;
3978286e41bSbeck } mm[] = {
3988286e41bSbeck { 17, MAP_FAILED }, { 3, MAP_FAILED },
3998286e41bSbeck { 11, MAP_FAILED }, { 2, MAP_FAILED },
4008286e41bSbeck { 5, MAP_FAILED }, { 3, MAP_FAILED },
4018286e41bSbeck { 7, MAP_FAILED }, { 1, MAP_FAILED },
4028286e41bSbeck { 57, MAP_FAILED }, { 3, MAP_FAILED },
4038286e41bSbeck { 131, MAP_FAILED }, { 1, MAP_FAILED },
4048286e41bSbeck };
4058286e41bSbeck
4068286e41bSbeck for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
40756419eb2Sderaadt HX(mm[m].p = mmap(NULL,
40856419eb2Sderaadt mm[m].npg * pgs,
4098286e41bSbeck PROT_READ|PROT_WRITE,
41056419eb2Sderaadt MAP_PRIVATE|MAP_ANON, -1,
41156419eb2Sderaadt (off_t)0), mm[m].p);
4128286e41bSbeck if (mm[m].p != MAP_FAILED) {
41356419eb2Sderaadt size_t mo;
4148286e41bSbeck
4158286e41bSbeck /* Touch some memory... */
41656419eb2Sderaadt p = mm[m].p;
41756419eb2Sderaadt mo = cnt %
41856419eb2Sderaadt (mm[m].npg * pgs - 1);
41956419eb2Sderaadt p[mo] = 1;
42056419eb2Sderaadt cnt += (int)((long)(mm[m].p)
42156419eb2Sderaadt / pgs);
4228286e41bSbeck }
4238286e41bSbeck
42456419eb2Sderaadt /* Check cnts and times... */
4258286e41bSbeck for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]);
4268286e41bSbeck ii++) {
42756419eb2Sderaadt HX((e = clock_gettime(cl[ii],
42893d8086cSbeck &ts)) == -1, ts);
4298286e41bSbeck if (e != -1)
43056419eb2Sderaadt cnt += (int)ts.tv_nsec;
4318286e41bSbeck }
4328286e41bSbeck
43356419eb2Sderaadt HX((e = getrusage(RUSAGE_SELF,
43456419eb2Sderaadt &ru)) == -1, ru);
4358286e41bSbeck if (e != -1) {
43656419eb2Sderaadt cnt += (int)ru.ru_utime.tv_sec;
43756419eb2Sderaadt cnt += (int)ru.ru_utime.tv_usec;
4388286e41bSbeck }
4398286e41bSbeck }
4408286e41bSbeck
4418286e41bSbeck for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
4428286e41bSbeck if (mm[m].p != MAP_FAILED)
44356419eb2Sderaadt munmap(mm[m].p, mm[m].npg * pgs);
4448286e41bSbeck mm[m].p = MAP_FAILED;
4458286e41bSbeck }
4468286e41bSbeck
44756419eb2Sderaadt HX(stat(".", &st) == -1, st);
44856419eb2Sderaadt HX(statvfs(".", &stvfs) == -1, stvfs);
44956419eb2Sderaadt HX(statfs(".", &stfs) == -1, stfs);
4508286e41bSbeck
45156419eb2Sderaadt HX(stat("/", &st) == -1, st);
45256419eb2Sderaadt HX(statvfs("/", &stvfs) == -1, stvfs);
45356419eb2Sderaadt HX(statfs("/", &stfs) == -1, stfs);
4548286e41bSbeck
45556419eb2Sderaadt HX((e = fstat(0, &st)) == -1, st);
4568286e41bSbeck if (e == -1) {
45793d8086cSbeck if (S_ISREG(st.st_mode) ||
45893d8086cSbeck S_ISFIFO(st.st_mode) ||
4598286e41bSbeck S_ISSOCK(st.st_mode)) {
46056419eb2Sderaadt HX(fstatvfs(0, &stvfs) == -1,
46193d8086cSbeck stvfs);
46256419eb2Sderaadt HX(fstatfs(0, &stfs) == -1,
46356419eb2Sderaadt stfs);
46456419eb2Sderaadt HX((off = lseek(0, (off_t)0,
4658286e41bSbeck SEEK_CUR)) < 0, off);
4668286e41bSbeck }
4678286e41bSbeck if (S_ISCHR(st.st_mode)) {
46856419eb2Sderaadt HX(tcgetattr(0, &tios) == -1,
46956419eb2Sderaadt tios);
4708286e41bSbeck } else if (S_ISSOCK(st.st_mode)) {
4718286e41bSbeck memset(&ss, 0, sizeof ss);
4728286e41bSbeck ssl = sizeof(ss);
47356419eb2Sderaadt HX(getpeername(0,
47456419eb2Sderaadt (void *)&ss, &ssl) == -1,
47556419eb2Sderaadt ss);
4768286e41bSbeck }
4778286e41bSbeck }
4788286e41bSbeck
47956419eb2Sderaadt HX((e = getrusage(RUSAGE_CHILDREN,
48056419eb2Sderaadt &ru)) == -1, ru);
4818286e41bSbeck if (e != -1) {
48256419eb2Sderaadt cnt += (int)ru.ru_utime.tv_sec;
48356419eb2Sderaadt cnt += (int)ru.ru_utime.tv_usec;
4848286e41bSbeck }
4858286e41bSbeck } else {
4868286e41bSbeck /* Subsequent hashes absorb previous result */
48756419eb2Sderaadt HD(results);
4888286e41bSbeck }
4898286e41bSbeck
49056419eb2Sderaadt HX((e = gettimeofday(&tv, NULL)) == -1, tv);
4918286e41bSbeck if (e != -1) {
49256419eb2Sderaadt cnt += (int)tv.tv_sec;
49356419eb2Sderaadt cnt += (int)tv.tv_usec;
4948286e41bSbeck }
4958286e41bSbeck
49656419eb2Sderaadt HD(cnt);
49756419eb2Sderaadt }
498912a9ab1Skettenis #ifdef HAVE_GETAUXVAL
4994f735644Sbeck #ifdef AT_RANDOM
5004f735644Sbeck /* Not as random as you think but we take what we are given */
5014f735644Sbeck p = (char *) getauxval(AT_RANDOM);
5024f735644Sbeck if (p)
5034f735644Sbeck HR(p, 16);
5044f735644Sbeck #endif
5054f735644Sbeck #ifdef AT_SYSINFO_EHDR
5064f735644Sbeck p = (char *) getauxval(AT_SYSINFO_EHDR);
5074f735644Sbeck if (p)
50811014432Sbeck HR(p, pgs);
5094f735644Sbeck #endif
5104f735644Sbeck #ifdef AT_BASE
5114f735644Sbeck p = (char *) getauxval(AT_BASE);
5124f735644Sbeck if (p)
513900d1301Sderaadt HD(p);
5144f735644Sbeck #endif
515912a9ab1Skettenis #endif
5164f735644Sbeck
5178286e41bSbeck SHA512_Final(results, &ctx);
518557f50beSderaadt memcpy((char *)buf + i, results, MINIMUM(sizeof(results), len - i));
519557f50beSderaadt i += MINIMUM(sizeof(results), len - i);
5208286e41bSbeck }
5215fd8226cSguenther explicit_bzero(&ctx, sizeof ctx);
5225fd8226cSguenther explicit_bzero(results, sizeof results);
5238286e41bSbeck errno = save_errno;
524044fc755Sderaadt return (0); /* satisfied */
5258286e41bSbeck }
526