getentropy_linux.c revision 294190
1226586Sdim/*	$OpenBSD: getentropy_linux.c,v 1.20 2014/07/12 15:43:49 beck Exp $	*/
2226586Sdim
3226586Sdim/*
4226586Sdim * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org>
5226586Sdim * Copyright (c) 2014 Bob Beck <beck@obtuse.com>
6226586Sdim *
7226586Sdim * Permission to use, copy, modify, and distribute this software for any
8226586Sdim * purpose with or without fee is hereby granted, provided that the above
9226586Sdim * copyright notice and this permission notice appear in all copies.
10239462Sdim *
11239462Sdim * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12239462Sdim * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13239462Sdim * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14226586Sdim * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15226586Sdim * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16226586Sdim * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17226586Sdim * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18226586Sdim */
19249423Sdim#include "config.h"
20249423Sdim
21249423Sdim/*
22226586Sdim#define	_POSIX_C_SOURCE 199309L
23249423Sdim#define	_GNU_SOURCE     1
24249423Sdim*/
25249423Sdim#include <sys/types.h>
26226586Sdim#include <sys/param.h>
27226586Sdim#include <sys/ioctl.h>
28226586Sdim#include <sys/resource.h>
29226586Sdim#include <sys/syscall.h>
30226586Sdim#ifdef HAVE_SYS_SYSCTL_H
31226586Sdim#include <sys/sysctl.h>
32249423Sdim#endif
33234353Sdim#include <sys/statvfs.h>
34226586Sdim#include <sys/socket.h>
35226586Sdim#include <sys/mount.h>
36249423Sdim#include <sys/mman.h>
37226586Sdim#include <sys/stat.h>
38234353Sdim#include <sys/time.h>
39234353Sdim#include <stdlib.h>
40234353Sdim#include <stdint.h>
41234353Sdim#include <stdio.h>
42234353Sdim#include <termios.h>
43234353Sdim#include <fcntl.h>
44234353Sdim#include <signal.h>
45234353Sdim#include <string.h>
46234353Sdim#include <errno.h>
47226586Sdim#include <unistd.h>
48226586Sdim#include <time.h>
49226586Sdim
50226586Sdim#if defined(HAVE_SSL)
51226586Sdim#include <openssl/sha.h>
52226586Sdim#elif defined(HAVE_NETTLE)
53226586Sdim#include <nettle/sha.h>
54226586Sdim#endif
55226586Sdim
56226586Sdim#include <linux/types.h>
57226586Sdim#include <linux/random.h>
58226586Sdim#include <linux/sysctl.h>
59226586Sdim#ifdef HAVE_GETAUXVAL
60226586Sdim#include <sys/auxv.h>
61249423Sdim#endif
62249423Sdim#include <sys/vfs.h>
63226586Sdim
64226586Sdim#define REPEAT 5
65226586Sdim#define min(a, b) (((a) < (b)) ? (a) : (b))
66234353Sdim
67234353Sdim#define HX(a, b) \
68226586Sdim	do { \
69226586Sdim		if ((a)) \
70234353Sdim			HD(errno); \
71234353Sdim		else \
72234353Sdim			HD(b); \
73234353Sdim	} while (0)
74234353Sdim
75234353Sdim#if defined(HAVE_SSL)
76234353Sdim#define CRYPTO_SHA512_CTX		SHA512_CTX
77234353Sdim#define CRYPTO_SHA512_INIT(x)		SHA512_Init(x)
78226586Sdim#define CRYPTO_SHA512_FINAL(r, c)	SHA512_Final(r, c)
79226586Sdim#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
80226586Sdim#define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
81226586Sdim#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
82#elif defined(HAVE_NETTLE)
83#define CRYPTO_SHA512_CTX		struct sha512_ctx
84#define CRYPTO_SHA512_INIT(x)		sha512_init(x)
85#define CRYPTO_SHA512_FINAL(r, c)	sha512_digest(c, SHA512_DIGEST_SIZE, r)
86#define HR(x, l) (sha512_update(&ctx, (l), (uint8_t *)(x)))
87#define HD(x)	 (sha512_update(&ctx, sizeof (x), (uint8_t *)&(x)))
88#define HF(x)    (sha512_update(&ctx, sizeof (void*), (uint8_t *)&(x)))
89#endif
90
91int	getentropy(void *buf, size_t len);
92
93#ifdef CAN_REFERENCE_MAIN
94extern int main(int, char *argv[]);
95#endif
96static int gotdata(char *buf, size_t len);
97#ifdef SYS_getrandom
98static int getentropy_getrandom(void *buf, size_t len);
99#endif
100static int getentropy_urandom(void *buf, size_t len);
101#ifdef SYS__sysctl
102static int getentropy_sysctl(void *buf, size_t len);
103#endif
104static int getentropy_fallback(void *buf, size_t len);
105
106int
107getentropy(void *buf, size_t len)
108{
109	int ret = -1;
110
111	if (len > 256) {
112		errno = EIO;
113		return -1;
114	}
115
116#ifdef SYS_getrandom
117	/*
118	 * Try descriptor-less getrandom()
119	 */
120	ret = getentropy_getrandom(buf, len);
121	if (ret != -1)
122		return (ret);
123	if (errno != ENOSYS)
124		return (-1);
125#endif
126
127	/*
128	 * Try to get entropy with /dev/urandom
129	 *
130	 * This can fail if the process is inside a chroot or if file
131	 * descriptors are exhausted.
132	 */
133	ret = getentropy_urandom(buf, len);
134	if (ret != -1)
135		return (ret);
136
137#ifdef SYS__sysctl
138	/*
139	 * Try to use sysctl CTL_KERN, KERN_RANDOM, RANDOM_UUID.
140	 * sysctl is a failsafe API, so it guarantees a result.  This
141	 * should work inside a chroot, or when file descriptors are
142	 * exhausted.
143	 *
144	 * However this can fail if the Linux kernel removes support
145	 * for sysctl.  Starting in 2007, there have been efforts to
146	 * deprecate the sysctl API/ABI, and push callers towards use
147	 * of the chroot-unavailable fd-using /proc mechanism --
148	 * essentially the same problems as /dev/urandom.
149	 *
150	 * Numerous setbacks have been encountered in their deprecation
151	 * schedule, so as of June 2014 the kernel ABI still exists on
152	 * most Linux architectures. The sysctl() stub in libc is missing
153	 * on some systems.  There are also reports that some kernels
154	 * spew messages to the console.
155	 */
156	ret = getentropy_sysctl(buf, len);
157	if (ret != -1)
158		return (ret);
159#endif /* SYS__sysctl */
160
161	/*
162	 * Entropy collection via /dev/urandom and sysctl have failed.
163	 *
164	 * No other API exists for collecting entropy.  See the large
165	 * comment block above.
166	 *
167	 * We have very few options:
168	 *     - Even syslog_r is unsafe to call at this low level, so
169	 *	 there is no way to alert the user or program.
170	 *     - Cannot call abort() because some systems have unsafe
171	 *	 corefiles.
172	 *     - Could raise(SIGKILL) resulting in silent program termination.
173	 *     - Return EIO, to hint that arc4random's stir function
174	 *       should raise(SIGKILL)
175	 *     - Do the best under the circumstances....
176	 *
177	 * This code path exists to bring light to the issue that Linux
178	 * does not provide a failsafe API for entropy collection.
179	 *
180	 * We hope this demonstrates that Linux should either retain their
181	 * sysctl ABI, or consider providing a new failsafe API which
182	 * works in a chroot or when file descriptors are exhausted.
183	 */
184#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
185#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
186	raise(SIGKILL);
187#endif
188	ret = getentropy_fallback(buf, len);
189	if (ret != -1)
190		return (ret);
191
192	errno = EIO;
193	return (ret);
194}
195
196/*
197 * Basic sanity checking; wish we could do better.
198 */
199static int
200gotdata(char *buf, size_t len)
201{
202	char	any_set = 0;
203	size_t	i;
204
205	for (i = 0; i < len; ++i)
206		any_set |= buf[i];
207	if (any_set == 0)
208		return -1;
209	return 0;
210}
211
212#ifdef SYS_getrandom
213static int
214getentropy_getrandom(void *buf, size_t len)
215{
216	int pre_errno = errno;
217	int ret;
218	if (len > 256)
219		return (-1);
220	do {
221		ret = syscall(SYS_getrandom, buf, len, 0);
222	} while (ret == -1 && errno == EINTR);
223
224	if (ret != (int)len)
225		return (-1);
226	errno = pre_errno;
227	return (0);
228}
229#endif
230
231static int
232getentropy_urandom(void *buf, size_t len)
233{
234	struct stat st;
235	size_t i;
236	int fd, cnt, flags;
237	int save_errno = errno;
238
239start:
240
241	flags = O_RDONLY;
242#ifdef O_NOFOLLOW
243	flags |= O_NOFOLLOW;
244#endif
245#ifdef O_CLOEXEC
246	flags |= O_CLOEXEC;
247#endif
248	fd = open("/dev/urandom", flags, 0);
249	if (fd == -1) {
250		if (errno == EINTR)
251			goto start;
252		goto nodevrandom;
253	}
254#ifndef O_CLOEXEC
255	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
256#endif
257
258	/* Lightly verify that the device node looks sane */
259	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
260		close(fd);
261		goto nodevrandom;
262	}
263	if (ioctl(fd, RNDGETENTCNT, &cnt) == -1) {
264		close(fd);
265		goto nodevrandom;
266	}
267	for (i = 0; i < len; ) {
268		size_t wanted = len - i;
269		ssize_t ret = read(fd, (char*)buf + i, wanted);
270
271		if (ret == -1) {
272			if (errno == EAGAIN || errno == EINTR)
273				continue;
274			close(fd);
275			goto nodevrandom;
276		}
277		i += ret;
278	}
279	close(fd);
280	if (gotdata(buf, len) == 0) {
281		errno = save_errno;
282		return 0;		/* satisfied */
283	}
284nodevrandom:
285	errno = EIO;
286	return -1;
287}
288
289#ifdef SYS__sysctl
290static int
291getentropy_sysctl(void *buf, size_t len)
292{
293	static int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
294	size_t i;
295	int save_errno = errno;
296
297	for (i = 0; i < len; ) {
298		size_t chunk = min(len - i, 16);
299
300		/* SYS__sysctl because some systems already removed sysctl() */
301		struct __sysctl_args args = {
302			.name = mib,
303			.nlen = 3,
304			.oldval = (char *)buf + i,
305			.oldlenp = &chunk,
306		};
307		if (syscall(SYS__sysctl, &args) != 0)
308			goto sysctlfailed;
309		i += chunk;
310	}
311	if (gotdata(buf, len) == 0) {
312		errno = save_errno;
313		return (0);			/* satisfied */
314	}
315sysctlfailed:
316	errno = EIO;
317	return -1;
318}
319#endif /* SYS__sysctl */
320
321static int cl[] = {
322	CLOCK_REALTIME,
323#ifdef CLOCK_MONOTONIC
324	CLOCK_MONOTONIC,
325#endif
326#ifdef CLOCK_MONOTONIC_RAW
327	CLOCK_MONOTONIC_RAW,
328#endif
329#ifdef CLOCK_TAI
330	CLOCK_TAI,
331#endif
332#ifdef CLOCK_VIRTUAL
333	CLOCK_VIRTUAL,
334#endif
335#ifdef CLOCK_UPTIME
336	CLOCK_UPTIME,
337#endif
338#ifdef CLOCK_PROCESS_CPUTIME_ID
339	CLOCK_PROCESS_CPUTIME_ID,
340#endif
341#ifdef CLOCK_THREAD_CPUTIME_ID
342	CLOCK_THREAD_CPUTIME_ID,
343#endif
344};
345
346static int
347getentropy_fallback(void *buf, size_t len)
348{
349	uint8_t results[SHA512_DIGEST_LENGTH];
350	int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
351	static int cnt;
352	struct timespec ts;
353	struct timeval tv;
354	struct rusage ru;
355	sigset_t sigset;
356	struct stat st;
357	CRYPTO_SHA512_CTX ctx;
358	static pid_t lastpid;
359	pid_t pid;
360	size_t i, ii, m;
361	char *p;
362
363	pid = getpid();
364	if (lastpid == pid) {
365		faster = 1;
366		repeat = 2;
367	} else {
368		faster = 0;
369		lastpid = pid;
370		repeat = REPEAT;
371	}
372	for (i = 0; i < len; ) {
373		int j;
374		CRYPTO_SHA512_INIT(&ctx);
375		for (j = 0; j < repeat; j++) {
376			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
377			if (e != -1) {
378				cnt += (int)tv.tv_sec;
379				cnt += (int)tv.tv_usec;
380			}
381
382			for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
383				HX(clock_gettime(cl[ii], &ts) == -1, ts);
384
385			HX((pid = getpid()) == -1, pid);
386			HX((pid = getsid(pid)) == -1, pid);
387			HX((pid = getppid()) == -1, pid);
388			HX((pid = getpgid(0)) == -1, pid);
389			HX((e = getpriority(0, 0)) == -1, e);
390
391			if (!faster) {
392				ts.tv_sec = 0;
393				ts.tv_nsec = 1;
394				(void) nanosleep(&ts, NULL);
395			}
396
397			HX(sigpending(&sigset) == -1, sigset);
398			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
399			    sigset);
400
401#ifdef CAN_REFERENCE_MAIN
402			HF(main);		/* an addr in program */
403#endif
404			HF(getentropy);	/* an addr in this library */
405			HF(printf);		/* an addr in libc */
406			p = (char *)&p;
407			HD(p);		/* an addr on stack */
408			p = (char *)&errno;
409			HD(p);		/* the addr of errno */
410
411			if (i == 0) {
412				struct sockaddr_storage ss;
413				struct statvfs stvfs;
414				struct termios tios;
415				struct statfs stfs;
416				socklen_t ssl;
417				off_t off;
418
419				/*
420				 * Prime-sized mappings encourage fragmentation;
421				 * thus exposing some address entropy.
422				 */
423				struct mm {
424					size_t	npg;
425					void	*p;
426				} mm[] =	 {
427					{ 17, MAP_FAILED }, { 3, MAP_FAILED },
428					{ 11, MAP_FAILED }, { 2, MAP_FAILED },
429					{ 5, MAP_FAILED }, { 3, MAP_FAILED },
430					{ 7, MAP_FAILED }, { 1, MAP_FAILED },
431					{ 57, MAP_FAILED }, { 3, MAP_FAILED },
432					{ 131, MAP_FAILED }, { 1, MAP_FAILED },
433				};
434
435				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
436					HX(mm[m].p = mmap(NULL,
437					    mm[m].npg * pgs,
438					    PROT_READ|PROT_WRITE,
439					    MAP_PRIVATE|MAP_ANON, -1,
440					    (off_t)0), mm[m].p);
441					if (mm[m].p != MAP_FAILED) {
442						size_t mo;
443
444						/* Touch some memory... */
445						p = mm[m].p;
446						mo = cnt %
447						    (mm[m].npg * pgs - 1);
448						p[mo] = 1;
449						cnt += (int)((long)(mm[m].p)
450						    / pgs);
451					}
452
453					/* Check cnts and times... */
454					for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]);
455					    ii++) {
456						HX((e = clock_gettime(cl[ii],
457						    &ts)) == -1, ts);
458						if (e != -1)
459							cnt += (int)ts.tv_nsec;
460					}
461
462					HX((e = getrusage(RUSAGE_SELF,
463					    &ru)) == -1, ru);
464					if (e != -1) {
465						cnt += (int)ru.ru_utime.tv_sec;
466						cnt += (int)ru.ru_utime.tv_usec;
467					}
468				}
469
470				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
471					if (mm[m].p != MAP_FAILED)
472						munmap(mm[m].p, mm[m].npg * pgs);
473					mm[m].p = MAP_FAILED;
474				}
475
476				HX(stat(".", &st) == -1, st);
477				HX(statvfs(".", &stvfs) == -1, stvfs);
478				HX(statfs(".", &stfs) == -1, stfs);
479
480				HX(stat("/", &st) == -1, st);
481				HX(statvfs("/", &stvfs) == -1, stvfs);
482				HX(statfs("/", &stfs) == -1, stfs);
483
484				HX((e = fstat(0, &st)) == -1, st);
485				if (e == -1) {
486					if (S_ISREG(st.st_mode) ||
487					    S_ISFIFO(st.st_mode) ||
488					    S_ISSOCK(st.st_mode)) {
489						HX(fstatvfs(0, &stvfs) == -1,
490						    stvfs);
491						HX(fstatfs(0, &stfs) == -1,
492						    stfs);
493						HX((off = lseek(0, (off_t)0,
494						    SEEK_CUR)) < 0, off);
495					}
496					if (S_ISCHR(st.st_mode)) {
497						HX(tcgetattr(0, &tios) == -1,
498						    tios);
499					} else if (S_ISSOCK(st.st_mode)) {
500						memset(&ss, 0, sizeof ss);
501						ssl = sizeof(ss);
502						HX(getpeername(0,
503						    (void *)&ss, &ssl) == -1,
504						    ss);
505					}
506				}
507
508				HX((e = getrusage(RUSAGE_CHILDREN,
509				    &ru)) == -1, ru);
510				if (e != -1) {
511					cnt += (int)ru.ru_utime.tv_sec;
512					cnt += (int)ru.ru_utime.tv_usec;
513				}
514			} else {
515				/* Subsequent hashes absorb previous result */
516				HD(results);
517			}
518
519			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
520			if (e != -1) {
521				cnt += (int)tv.tv_sec;
522				cnt += (int)tv.tv_usec;
523			}
524
525			HD(cnt);
526		}
527#ifdef HAVE_GETAUXVAL
528#  ifdef AT_RANDOM
529		/* Not as random as you think but we take what we are given */
530		p = (char *) getauxval(AT_RANDOM);
531		if (p)
532			HR(p, 16);
533#  endif
534#  ifdef AT_SYSINFO_EHDR
535		p = (char *) getauxval(AT_SYSINFO_EHDR);
536		if (p)
537			HR(p, pgs);
538#  endif
539#  ifdef AT_BASE
540		p = (char *) getauxval(AT_BASE);
541		if (p)
542			HD(p);
543#  endif
544#endif /* HAVE_GETAUXVAL */
545
546		CRYPTO_SHA512_FINAL(results, &ctx);
547		memcpy((char*)buf + i, results, min(sizeof(results), len - i));
548		i += min(sizeof(results), len - i);
549	}
550	memset(results, 0, sizeof results);
551	if (gotdata(buf, len) == 0) {
552		errno = save_errno;
553		return 0;		/* satisfied */
554	}
555	errno = EIO;
556	return -1;
557}
558