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