xref: /third_party/FreeBSD/lib/libc/gen/arc4random.h (revision f9f848fa)
1/*	$OpenBSD: arc4random.h,v 1.4 2015/01/15 06:57:18 deraadt Exp $	*/
2
3/*
4 * Copyright (c) 1996, David Mazieres <dm@uun.org>
5 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
6 * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
7 * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * Stub functions for portability.
24 */
25#ifndef ARC4RANDOM_H
26#define ARC4RANDOM_H
27
28#include <sys/mman.h>
29
30#include <pthread.h>
31#include <signal.h>
32
33static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
34#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx)
35#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx)
36
37/*
38 * Unfortunately, pthread_atfork() is broken on FreeBSD (at least 9 and 10) if
39 * a program does not link to -lthr. Callbacks registered with pthread_atfork()
40 * appear to fail silently. So, it is not always possible to detect a PID
41 * wraparound.
42 */
43#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f))
44
45static inline void
46_getentropy_fail(void)
47{
48	raise(SIGKILL);
49}
50
51static volatile sig_atomic_t _rs_forked;
52
53static inline void
54_rs_forkhandler(void)
55{
56	_rs_forked = 1;
57}
58
59static inline void
60_rs_forkdetect(void)
61{
62	static pid_t _rs_pid = 0;
63	pid_t pid = getpid();
64
65	if (_rs_pid == 0 || _rs_pid != pid || _rs_forked) {
66		_rs_pid = pid;
67		_rs_forked = 0;
68		if (rs)
69			memset(rs, 0, sizeof(*rs));
70	}
71}
72
73static inline int
74_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
75{
76	if ((*rsp = mmap(NULL, sizeof(**rsp), PROT_READ|PROT_WRITE,
77	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
78		return (-1);
79
80	if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
81	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
82		munmap(*rsp, sizeof(**rsp));
83		*rsp = NULL;
84		return (-1);
85	}
86
87	_ARC4_ATFORK(_rs_forkhandler);
88	return (0);
89}
90#endif