1228753Smm/*	$OpenBSD: arc4random_freebsd.h,v 1.4 2016/06/30 12:19:51 bcook Exp $	*/
2228753Smm
3228753Smm/*
4228753Smm * Copyright (c) 1996, David Mazieres <dm@uun.org>
5228753Smm * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
6228753Smm * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
7228753Smm * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>
8228753Smm *
9228753Smm * Permission to use, copy, modify, and distribute this software for any
10228753Smm * purpose with or without fee is hereby granted, provided that the above
11228753Smm * copyright notice and this permission notice appear in all copies.
12228753Smm *
13228753Smm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14228753Smm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15228753Smm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16228753Smm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17228753Smm * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18228753Smm * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19228753Smm * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20228753Smm */
21228753Smm
22228753Smm/*
23228753Smm * Stub functions for portability.
24228753Smm */
25228763Smm
26228753Smm#include <sys/mman.h>
27228753Smm
28358090Smm#include <pthread.h>
29358090Smm#include <signal.h>
30358090Smm
31228753Smmstatic pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
32228753Smm#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx)
33228753Smm#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx)
34228753Smm
35232153Smm/*
36232153Smm * Unfortunately, pthread_atfork() is broken on FreeBSD (at least 9 and 10) if
37232153Smm * a program does not link to -lthr. Callbacks registered with pthread_atfork()
38232153Smm * appear to fail silently. So, it is not always possible to detect a PID
39228753Smm * wraparound.
40228753Smm */
41228753Smm#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f))
42228753Smm
43228753Smmstatic inline void
44228753Smm_getentropy_fail(void)
45228753Smm{
46228753Smm	raise(SIGKILL);
47228753Smm}
48228753Smm
49228753Smmstatic volatile sig_atomic_t _rs_forked;
50228753Smm
51228753Smmstatic inline void
52228753Smm_rs_forkhandler(void)
53238856Smm{
54228753Smm	_rs_forked = 1;
55228753Smm}
56228753Smm
57228753Smmstatic inline void
58228753Smm_rs_forkdetect(void)
59228753Smm{
60228753Smm	static pid_t _rs_pid = 0;
61232153Smm	pid_t pid = getpid();
62228753Smm
63228753Smm	if (_rs_pid == 0 || _rs_pid != pid || _rs_forked) {
64228753Smm		_rs_pid = pid;
65228773Smm		_rs_forked = 0;
66228753Smm		if (rs)
67228753Smm			memset(rs, 0, sizeof(*rs));
68228753Smm	}
69228753Smm}
70228753Smm
71228753Smmstatic inline int
72232153Smm_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
73232153Smm{
74232153Smm	if ((*rsp = mmap(NULL, sizeof(**rsp), PROT_READ|PROT_WRITE,
75232153Smm	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
76232153Smm		return (-1);
77232153Smm
78232153Smm	if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
79232153Smm	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
80232153Smm		munmap(*rsp, sizeof(**rsp));
81232153Smm		*rsp = NULL;
82232153Smm		return (-1);
83232153Smm	}
84232153Smm
85228753Smm	_ARC4_ATFORK(_rs_forkhandler);
86228753Smm	return (0);
87232153Smm}
88232153Smm