2015-08-17 07:36:12 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 2015 Mark R V Murray
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer
|
|
|
|
* in this position and unchanged.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/random.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
|
|
|
|
#if defined(RANDOM_LOADABLE)
|
|
|
|
#include <sys/lock.h>
|
|
|
|
#include <sys/sx.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <dev/random/randomdev.h>
|
|
|
|
|
|
|
|
/* Set up the sysctl root node for the entropy device */
|
random(4): Restore availability tradeoff prior to r346250
As discussed in that commit message, it is a dangerous default. But the
safe default causes enough pain on a variety of platforms that for now,
restore the prior default.
Some of this is self-induced pain we should/could do better about; for
example, programmatic CI systems and VM managers should introduce entropy
from the host for individual VM instances. This is considered a future work
item.
On modern x86 and Power9 systems, this may be wholly unnecessary after
D19928 lands (even in the non-ideal case where early /boot/entropy is
unavailable), because they have fast hardware random sources available early
in boot. But D19928 is not yet landed and we have a host of architectures
which do not provide fast random sources.
This change adds several tunables and diagnostic sysctls, documented
thoroughly in UPDATING and sys/dev/random/random_infra.c.
PR: 230875 (reopens)
Reported by: adrian, jhb, imp, and probably others
Reviewed by: delphij, imp (earlier version), markm (earlier version)
Discussed with: adrian
Approved by: secteam(delphij)
Relnotes: yeah
Security: related
Differential Revision: https://reviews.freebsd.org/D19944
2019-04-18 20:48:54 +00:00
|
|
|
SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0,
|
|
|
|
"Cryptographically Secure Random Number Generator");
|
|
|
|
SYSCTL_NODE(_kern_random, OID_AUTO, initial_seeding, CTLFLAG_RW, 0,
|
|
|
|
"Initial seeding control and information");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* N.B., this is a dangerous default, but it matches the behavior prior to
|
|
|
|
* r346250 (and, say, OpenBSD -- although they get some guaranteed saved
|
|
|
|
* entropy from the prior boot because of their KARL system, on RW media).
|
|
|
|
*/
|
|
|
|
bool random_bypass_before_seeding = true;
|
|
|
|
SYSCTL_BOOL(_kern_random_initial_seeding, OID_AUTO,
|
|
|
|
bypass_before_seeding, CTLFLAG_RDTUN, &random_bypass_before_seeding,
|
|
|
|
0, "If set non-zero, bypass the random device in requests for random "
|
|
|
|
"data when the random device is not yet seeded. This is considered "
|
|
|
|
"dangerous. Ordinarily, the random device will block requests until "
|
|
|
|
"it is seeded by sufficient entropy.");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is a read-only diagnostic that reports the combination of the former
|
|
|
|
* tunable and actual bypass. It is intended for programmatic inspection by
|
|
|
|
* userspace administrative utilities after boot.
|
|
|
|
*/
|
|
|
|
bool read_random_bypassed_before_seeding = false;
|
|
|
|
SYSCTL_BOOL(_kern_random_initial_seeding, OID_AUTO,
|
|
|
|
read_random_bypassed_before_seeding, CTLFLAG_RD,
|
|
|
|
&read_random_bypassed_before_seeding, 0, "If non-zero, the random device "
|
|
|
|
"was bypassed because the 'bypass_before_seeding' knob was enabled and a "
|
|
|
|
"request was submitted prior to initial seeding.");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is a read-only diagnostic that reports the combination of the former
|
|
|
|
* tunable and actual bypass for arc4random initial seeding. It is intended
|
|
|
|
* for programmatic inspection by userspace administrative utilities after
|
|
|
|
* boot.
|
|
|
|
*/
|
|
|
|
bool arc4random_bypassed_before_seeding = false;
|
|
|
|
SYSCTL_BOOL(_kern_random_initial_seeding, OID_AUTO,
|
|
|
|
arc4random_bypassed_before_seeding, CTLFLAG_RD,
|
|
|
|
&arc4random_bypassed_before_seeding, 0, "If non-zero, the random device "
|
|
|
|
"was bypassed when initially seeding the kernel arc4random(9), because "
|
|
|
|
"the 'bypass_before_seeding' knob was enabled and a request was submitted "
|
|
|
|
"prior to initial seeding.");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This knob is for users who do not want additional warnings in their logs
|
|
|
|
* because they intend to handle bypass by inspecting the status of the
|
|
|
|
* diagnostic sysctls.
|
|
|
|
*/
|
|
|
|
bool random_bypass_disable_warnings = false;
|
|
|
|
SYSCTL_BOOL(_kern_random_initial_seeding, OID_AUTO,
|
|
|
|
disable_bypass_warnings, CTLFLAG_RDTUN,
|
|
|
|
&random_bypass_disable_warnings, 0, "If non-zero, do not log a warning "
|
|
|
|
"if the 'bypass_before_seeding' knob is enabled and a request is "
|
|
|
|
"submitted prior to initial seeding.");
|
2015-08-17 07:36:12 +00:00
|
|
|
|
|
|
|
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
|
|
|
|
|
|
|
|
struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list);
|
|
|
|
|
|
|
|
#if defined(RANDOM_LOADABLE)
|
|
|
|
struct random_algorithm *p_random_alg_context = NULL;
|
|
|
|
#else /* !defined(RANDOM_LOADABLE) */
|
|
|
|
struct random_algorithm *p_random_alg_context = &random_alg_context;
|
|
|
|
#endif /* defined(RANDOM_LOADABLE) */
|
|
|
|
|
|
|
|
#if defined(RANDOM_LOADABLE)
|
|
|
|
|
random(4): Block read_random(9) on initial seeding
read_random() is/was used, mostly without error checking, in a lot of
very sensitive places in the kernel -- including seeding the widely used
arc4random(9).
Most uses, especially arc4random(9), should block until the device is seeded
rather than proceeding with a bogus or empty seed. I did not spy any
obvious kernel consumers where blocking would be inappropriate (in the
sense that lack of entropy would be ok -- I did not investigate locking
angle thoroughly). In many instances, arc4random_buf(9) or that family
of APIs would be more appropriate anyway; that work was done in r345865.
A minor cleanup was made to the implementation of the READ_RANDOM function:
instead of using a variable-length array on the stack to temporarily store
all full random blocks sufficient to satisfy the requested 'len', only store
a single block on the stack. This has some benefit in terms of reducing
stack usage, reducing memcpy overhead and reducing devrandom output leakage
via the stack. Additionally, the stack block is now safely zeroed if it was
used.
One caveat of this change is that the kern.arandom sysctl no longer returns
zero bytes immediately if the random device is not seeded. This means that
FreeBSD-specific userspace applications which attempted to handle an
unseeded random device may be broken by this change. If such behavior is
needed, it can be replaced by the more portable getrandom(2) GRND_NONBLOCK
option.
On any typical FreeBSD system, entropy is persisted on read/write media and
used to seed the random device very early in boot, and blocking is never a
problem.
This change primarily impacts the behavior of /dev/random on embedded
systems with read-only media that do not configure "nodevice random". We
toggle the default from 'charge on blindly with no entropy' to 'block
indefinitely.' This default is safer, but may cause frustration. Embedded
system designers using FreeBSD have several options. The most obvious is to
plan to have a small writable NVRAM or NAND to persist entropy, like larger
systems. Early entropy can be fed from any loader, or by writing directly
to /dev/random during boot. Some embedded SoCs now provide a fast hardware
entropy source; this would also work for quickly seeding Fortuna. A 3rd
option would be creating an embedded-specific, more simplistic random
module, like that designed by DJB in [1] (this design still requires a small
rewritable media for forward secrecy). Finally, the least preferred option
might be "nodevice random", although I plan to remove this in a subsequent
revision.
To help developers emulate the behavior of these embedded systems on
ordinary workstations, the tunable kern.random.block_seeded_status was
added. When set to 1, it blocks the random device.
I attempted to document this change in random.4 and random.9 and ran into a
bunch of out-of-date or irrelevant or inaccurate content and ended up
rototilling those documents more than I intended to. Sorry. I think
they're in a better state now.
PR: 230875
Reviewed by: delphij, markm (earlier version)
Approved by: secteam(delphij), devrandom(markm)
Relnotes: yes
Differential Revision: https://reviews.freebsd.org/D19744
2019-04-15 18:40:36 +00:00
|
|
|
static void
|
|
|
|
null_read_random(void *dummy __unused, u_int dummy2 __unused)
|
|
|
|
{
|
|
|
|
panic("%s: no random module is loaded", __func__);
|
|
|
|
}
|
|
|
|
|
2019-04-16 17:12:17 +00:00
|
|
|
static bool
|
|
|
|
null_is_random_seeded(void)
|
|
|
|
{
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
2015-08-17 07:36:12 +00:00
|
|
|
struct random_readers {
|
|
|
|
int (*read_random_uio)(struct uio *, bool);
|
random(4): Block read_random(9) on initial seeding
read_random() is/was used, mostly without error checking, in a lot of
very sensitive places in the kernel -- including seeding the widely used
arc4random(9).
Most uses, especially arc4random(9), should block until the device is seeded
rather than proceeding with a bogus or empty seed. I did not spy any
obvious kernel consumers where blocking would be inappropriate (in the
sense that lack of entropy would be ok -- I did not investigate locking
angle thoroughly). In many instances, arc4random_buf(9) or that family
of APIs would be more appropriate anyway; that work was done in r345865.
A minor cleanup was made to the implementation of the READ_RANDOM function:
instead of using a variable-length array on the stack to temporarily store
all full random blocks sufficient to satisfy the requested 'len', only store
a single block on the stack. This has some benefit in terms of reducing
stack usage, reducing memcpy overhead and reducing devrandom output leakage
via the stack. Additionally, the stack block is now safely zeroed if it was
used.
One caveat of this change is that the kern.arandom sysctl no longer returns
zero bytes immediately if the random device is not seeded. This means that
FreeBSD-specific userspace applications which attempted to handle an
unseeded random device may be broken by this change. If such behavior is
needed, it can be replaced by the more portable getrandom(2) GRND_NONBLOCK
option.
On any typical FreeBSD system, entropy is persisted on read/write media and
used to seed the random device very early in boot, and blocking is never a
problem.
This change primarily impacts the behavior of /dev/random on embedded
systems with read-only media that do not configure "nodevice random". We
toggle the default from 'charge on blindly with no entropy' to 'block
indefinitely.' This default is safer, but may cause frustration. Embedded
system designers using FreeBSD have several options. The most obvious is to
plan to have a small writable NVRAM or NAND to persist entropy, like larger
systems. Early entropy can be fed from any loader, or by writing directly
to /dev/random during boot. Some embedded SoCs now provide a fast hardware
entropy source; this would also work for quickly seeding Fortuna. A 3rd
option would be creating an embedded-specific, more simplistic random
module, like that designed by DJB in [1] (this design still requires a small
rewritable media for forward secrecy). Finally, the least preferred option
might be "nodevice random", although I plan to remove this in a subsequent
revision.
To help developers emulate the behavior of these embedded systems on
ordinary workstations, the tunable kern.random.block_seeded_status was
added. When set to 1, it blocks the random device.
I attempted to document this change in random.4 and random.9 and ran into a
bunch of out-of-date or irrelevant or inaccurate content and ended up
rototilling those documents more than I intended to. Sorry. I think
they're in a better state now.
PR: 230875
Reviewed by: delphij, markm (earlier version)
Approved by: secteam(delphij), devrandom(markm)
Relnotes: yes
Differential Revision: https://reviews.freebsd.org/D19744
2019-04-15 18:40:36 +00:00
|
|
|
void (*read_random)(void *, u_int);
|
2019-04-16 17:12:17 +00:00
|
|
|
bool (*is_random_seeded)(void);
|
2015-08-17 07:36:12 +00:00
|
|
|
} random_reader_context = {
|
|
|
|
(int (*)(struct uio *, bool))nullop,
|
random(4): Block read_random(9) on initial seeding
read_random() is/was used, mostly without error checking, in a lot of
very sensitive places in the kernel -- including seeding the widely used
arc4random(9).
Most uses, especially arc4random(9), should block until the device is seeded
rather than proceeding with a bogus or empty seed. I did not spy any
obvious kernel consumers where blocking would be inappropriate (in the
sense that lack of entropy would be ok -- I did not investigate locking
angle thoroughly). In many instances, arc4random_buf(9) or that family
of APIs would be more appropriate anyway; that work was done in r345865.
A minor cleanup was made to the implementation of the READ_RANDOM function:
instead of using a variable-length array on the stack to temporarily store
all full random blocks sufficient to satisfy the requested 'len', only store
a single block on the stack. This has some benefit in terms of reducing
stack usage, reducing memcpy overhead and reducing devrandom output leakage
via the stack. Additionally, the stack block is now safely zeroed if it was
used.
One caveat of this change is that the kern.arandom sysctl no longer returns
zero bytes immediately if the random device is not seeded. This means that
FreeBSD-specific userspace applications which attempted to handle an
unseeded random device may be broken by this change. If such behavior is
needed, it can be replaced by the more portable getrandom(2) GRND_NONBLOCK
option.
On any typical FreeBSD system, entropy is persisted on read/write media and
used to seed the random device very early in boot, and blocking is never a
problem.
This change primarily impacts the behavior of /dev/random on embedded
systems with read-only media that do not configure "nodevice random". We
toggle the default from 'charge on blindly with no entropy' to 'block
indefinitely.' This default is safer, but may cause frustration. Embedded
system designers using FreeBSD have several options. The most obvious is to
plan to have a small writable NVRAM or NAND to persist entropy, like larger
systems. Early entropy can be fed from any loader, or by writing directly
to /dev/random during boot. Some embedded SoCs now provide a fast hardware
entropy source; this would also work for quickly seeding Fortuna. A 3rd
option would be creating an embedded-specific, more simplistic random
module, like that designed by DJB in [1] (this design still requires a small
rewritable media for forward secrecy). Finally, the least preferred option
might be "nodevice random", although I plan to remove this in a subsequent
revision.
To help developers emulate the behavior of these embedded systems on
ordinary workstations, the tunable kern.random.block_seeded_status was
added. When set to 1, it blocks the random device.
I attempted to document this change in random.4 and random.9 and ran into a
bunch of out-of-date or irrelevant or inaccurate content and ended up
rototilling those documents more than I intended to. Sorry. I think
they're in a better state now.
PR: 230875
Reviewed by: delphij, markm (earlier version)
Approved by: secteam(delphij), devrandom(markm)
Relnotes: yes
Differential Revision: https://reviews.freebsd.org/D19744
2019-04-15 18:40:36 +00:00
|
|
|
null_read_random,
|
2019-04-16 17:12:17 +00:00
|
|
|
null_is_random_seeded,
|
2015-08-17 07:36:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct sx randomdev_config_lock;
|
|
|
|
|
|
|
|
static void
|
|
|
|
random_infra_sysinit(void *dummy __unused)
|
|
|
|
{
|
|
|
|
|
|
|
|
RANDOM_CONFIG_INIT_LOCK();
|
|
|
|
}
|
|
|
|
SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysinit, NULL);
|
|
|
|
|
|
|
|
void
|
2019-04-16 17:12:17 +00:00
|
|
|
random_infra_init(int (*p_random_read_uio)(struct uio *, bool),
|
|
|
|
void (*p_random_read)(void *, u_int),
|
|
|
|
bool (*p_is_random_seeded)(void))
|
2015-08-17 07:36:12 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
RANDOM_CONFIG_X_LOCK();
|
|
|
|
random_reader_context.read_random_uio = p_random_read_uio;
|
|
|
|
random_reader_context.read_random = p_random_read;
|
2019-04-16 17:12:17 +00:00
|
|
|
random_reader_context.is_random_seeded = p_is_random_seeded;
|
2015-08-17 07:36:12 +00:00
|
|
|
RANDOM_CONFIG_X_UNLOCK();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
random_infra_uninit(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
RANDOM_CONFIG_X_LOCK();
|
|
|
|
random_reader_context.read_random_uio = (int (*)(struct uio *, bool))nullop;
|
random(4): Block read_random(9) on initial seeding
read_random() is/was used, mostly without error checking, in a lot of
very sensitive places in the kernel -- including seeding the widely used
arc4random(9).
Most uses, especially arc4random(9), should block until the device is seeded
rather than proceeding with a bogus or empty seed. I did not spy any
obvious kernel consumers where blocking would be inappropriate (in the
sense that lack of entropy would be ok -- I did not investigate locking
angle thoroughly). In many instances, arc4random_buf(9) or that family
of APIs would be more appropriate anyway; that work was done in r345865.
A minor cleanup was made to the implementation of the READ_RANDOM function:
instead of using a variable-length array on the stack to temporarily store
all full random blocks sufficient to satisfy the requested 'len', only store
a single block on the stack. This has some benefit in terms of reducing
stack usage, reducing memcpy overhead and reducing devrandom output leakage
via the stack. Additionally, the stack block is now safely zeroed if it was
used.
One caveat of this change is that the kern.arandom sysctl no longer returns
zero bytes immediately if the random device is not seeded. This means that
FreeBSD-specific userspace applications which attempted to handle an
unseeded random device may be broken by this change. If such behavior is
needed, it can be replaced by the more portable getrandom(2) GRND_NONBLOCK
option.
On any typical FreeBSD system, entropy is persisted on read/write media and
used to seed the random device very early in boot, and blocking is never a
problem.
This change primarily impacts the behavior of /dev/random on embedded
systems with read-only media that do not configure "nodevice random". We
toggle the default from 'charge on blindly with no entropy' to 'block
indefinitely.' This default is safer, but may cause frustration. Embedded
system designers using FreeBSD have several options. The most obvious is to
plan to have a small writable NVRAM or NAND to persist entropy, like larger
systems. Early entropy can be fed from any loader, or by writing directly
to /dev/random during boot. Some embedded SoCs now provide a fast hardware
entropy source; this would also work for quickly seeding Fortuna. A 3rd
option would be creating an embedded-specific, more simplistic random
module, like that designed by DJB in [1] (this design still requires a small
rewritable media for forward secrecy). Finally, the least preferred option
might be "nodevice random", although I plan to remove this in a subsequent
revision.
To help developers emulate the behavior of these embedded systems on
ordinary workstations, the tunable kern.random.block_seeded_status was
added. When set to 1, it blocks the random device.
I attempted to document this change in random.4 and random.9 and ran into a
bunch of out-of-date or irrelevant or inaccurate content and ended up
rototilling those documents more than I intended to. Sorry. I think
they're in a better state now.
PR: 230875
Reviewed by: delphij, markm (earlier version)
Approved by: secteam(delphij), devrandom(markm)
Relnotes: yes
Differential Revision: https://reviews.freebsd.org/D19744
2019-04-15 18:40:36 +00:00
|
|
|
random_reader_context.read_random = null_read_random;
|
2019-04-16 17:12:17 +00:00
|
|
|
random_reader_context.is_random_seeded = null_is_random_seeded;
|
2015-08-17 07:36:12 +00:00
|
|
|
RANDOM_CONFIG_X_UNLOCK();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
random_infra_sysuninit(void *dummy __unused)
|
|
|
|
{
|
|
|
|
|
|
|
|
RANDOM_CONFIG_DEINIT_LOCK();
|
|
|
|
}
|
|
|
|
SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysuninit, NULL);
|
|
|
|
|
|
|
|
int
|
|
|
|
read_random_uio(struct uio *uio, bool nonblock)
|
|
|
|
{
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
RANDOM_CONFIG_S_LOCK();
|
|
|
|
retval = random_reader_context.read_random_uio(uio, nonblock);
|
|
|
|
RANDOM_CONFIG_S_UNLOCK();
|
|
|
|
return (retval);
|
|
|
|
}
|
|
|
|
|
random(4): Block read_random(9) on initial seeding
read_random() is/was used, mostly without error checking, in a lot of
very sensitive places in the kernel -- including seeding the widely used
arc4random(9).
Most uses, especially arc4random(9), should block until the device is seeded
rather than proceeding with a bogus or empty seed. I did not spy any
obvious kernel consumers where blocking would be inappropriate (in the
sense that lack of entropy would be ok -- I did not investigate locking
angle thoroughly). In many instances, arc4random_buf(9) or that family
of APIs would be more appropriate anyway; that work was done in r345865.
A minor cleanup was made to the implementation of the READ_RANDOM function:
instead of using a variable-length array on the stack to temporarily store
all full random blocks sufficient to satisfy the requested 'len', only store
a single block on the stack. This has some benefit in terms of reducing
stack usage, reducing memcpy overhead and reducing devrandom output leakage
via the stack. Additionally, the stack block is now safely zeroed if it was
used.
One caveat of this change is that the kern.arandom sysctl no longer returns
zero bytes immediately if the random device is not seeded. This means that
FreeBSD-specific userspace applications which attempted to handle an
unseeded random device may be broken by this change. If such behavior is
needed, it can be replaced by the more portable getrandom(2) GRND_NONBLOCK
option.
On any typical FreeBSD system, entropy is persisted on read/write media and
used to seed the random device very early in boot, and blocking is never a
problem.
This change primarily impacts the behavior of /dev/random on embedded
systems with read-only media that do not configure "nodevice random". We
toggle the default from 'charge on blindly with no entropy' to 'block
indefinitely.' This default is safer, but may cause frustration. Embedded
system designers using FreeBSD have several options. The most obvious is to
plan to have a small writable NVRAM or NAND to persist entropy, like larger
systems. Early entropy can be fed from any loader, or by writing directly
to /dev/random during boot. Some embedded SoCs now provide a fast hardware
entropy source; this would also work for quickly seeding Fortuna. A 3rd
option would be creating an embedded-specific, more simplistic random
module, like that designed by DJB in [1] (this design still requires a small
rewritable media for forward secrecy). Finally, the least preferred option
might be "nodevice random", although I plan to remove this in a subsequent
revision.
To help developers emulate the behavior of these embedded systems on
ordinary workstations, the tunable kern.random.block_seeded_status was
added. When set to 1, it blocks the random device.
I attempted to document this change in random.4 and random.9 and ran into a
bunch of out-of-date or irrelevant or inaccurate content and ended up
rototilling those documents more than I intended to. Sorry. I think
they're in a better state now.
PR: 230875
Reviewed by: delphij, markm (earlier version)
Approved by: secteam(delphij), devrandom(markm)
Relnotes: yes
Differential Revision: https://reviews.freebsd.org/D19744
2019-04-15 18:40:36 +00:00
|
|
|
void
|
2015-08-17 07:36:12 +00:00
|
|
|
read_random(void *buf, u_int len)
|
|
|
|
{
|
|
|
|
|
|
|
|
RANDOM_CONFIG_S_LOCK();
|
random(4): Block read_random(9) on initial seeding
read_random() is/was used, mostly without error checking, in a lot of
very sensitive places in the kernel -- including seeding the widely used
arc4random(9).
Most uses, especially arc4random(9), should block until the device is seeded
rather than proceeding with a bogus or empty seed. I did not spy any
obvious kernel consumers where blocking would be inappropriate (in the
sense that lack of entropy would be ok -- I did not investigate locking
angle thoroughly). In many instances, arc4random_buf(9) or that family
of APIs would be more appropriate anyway; that work was done in r345865.
A minor cleanup was made to the implementation of the READ_RANDOM function:
instead of using a variable-length array on the stack to temporarily store
all full random blocks sufficient to satisfy the requested 'len', only store
a single block on the stack. This has some benefit in terms of reducing
stack usage, reducing memcpy overhead and reducing devrandom output leakage
via the stack. Additionally, the stack block is now safely zeroed if it was
used.
One caveat of this change is that the kern.arandom sysctl no longer returns
zero bytes immediately if the random device is not seeded. This means that
FreeBSD-specific userspace applications which attempted to handle an
unseeded random device may be broken by this change. If such behavior is
needed, it can be replaced by the more portable getrandom(2) GRND_NONBLOCK
option.
On any typical FreeBSD system, entropy is persisted on read/write media and
used to seed the random device very early in boot, and blocking is never a
problem.
This change primarily impacts the behavior of /dev/random on embedded
systems with read-only media that do not configure "nodevice random". We
toggle the default from 'charge on blindly with no entropy' to 'block
indefinitely.' This default is safer, but may cause frustration. Embedded
system designers using FreeBSD have several options. The most obvious is to
plan to have a small writable NVRAM or NAND to persist entropy, like larger
systems. Early entropy can be fed from any loader, or by writing directly
to /dev/random during boot. Some embedded SoCs now provide a fast hardware
entropy source; this would also work for quickly seeding Fortuna. A 3rd
option would be creating an embedded-specific, more simplistic random
module, like that designed by DJB in [1] (this design still requires a small
rewritable media for forward secrecy). Finally, the least preferred option
might be "nodevice random", although I plan to remove this in a subsequent
revision.
To help developers emulate the behavior of these embedded systems on
ordinary workstations, the tunable kern.random.block_seeded_status was
added. When set to 1, it blocks the random device.
I attempted to document this change in random.4 and random.9 and ran into a
bunch of out-of-date or irrelevant or inaccurate content and ended up
rototilling those documents more than I intended to. Sorry. I think
they're in a better state now.
PR: 230875
Reviewed by: delphij, markm (earlier version)
Approved by: secteam(delphij), devrandom(markm)
Relnotes: yes
Differential Revision: https://reviews.freebsd.org/D19744
2019-04-15 18:40:36 +00:00
|
|
|
random_reader_context.read_random(buf, len);
|
2015-08-17 07:36:12 +00:00
|
|
|
RANDOM_CONFIG_S_UNLOCK();
|
|
|
|
}
|
|
|
|
|
2019-04-16 17:12:17 +00:00
|
|
|
bool
|
|
|
|
is_random_seeded(void)
|
|
|
|
{
|
|
|
|
RANDOM_CONFIG_S_LOCK();
|
|
|
|
random_reader_context.is_random_seeded();
|
|
|
|
RANDOM_CONFIG_S_UNLOCK();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-17 07:36:12 +00:00
|
|
|
#endif /* defined(RANDOM_LOADABLE) */
|