diff options
author | Conrad Meyer <cem@FreeBSD.org> | 2019-04-18 20:48:54 +0000 |
---|---|---|
committer | Conrad Meyer <cem@FreeBSD.org> | 2019-04-18 20:48:54 +0000 |
commit | 3782136ff1fc1e076c939246f199e659d950bad5 (patch) | |
tree | 7e46162167ecb901ed19723832fccc946f4586b1 /sys/dev/random | |
parent | db92a6cd5148c3b112346a8e463c28a44f85aa2d (diff) | |
download | src-3782136ff1fc1e076c939246f199e659d950bad5.tar.gz src-3782136ff1fc1e076c939246f199e659d950bad5.zip |
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
Notes
Notes:
svn path=/head/; revision=346358
Diffstat (limited to 'sys/dev/random')
-rw-r--r-- | sys/dev/random/random_infra.c | 56 | ||||
-rw-r--r-- | sys/dev/random/randomdev.c | 39 | ||||
-rw-r--r-- | sys/dev/random/randomdev.h | 6 |
3 files changed, 92 insertions, 9 deletions
diff --git a/sys/dev/random/random_infra.c b/sys/dev/random/random_infra.c index 59cd44280b95..9a40c35f12b7 100644 --- a/sys/dev/random/random_infra.c +++ b/sys/dev/random/random_infra.c @@ -43,7 +43,61 @@ __FBSDID("$FreeBSD$"); #include <dev/random/randomdev.h> /* Set up the sysctl root node for the entropy device */ -SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator"); +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."); MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index cbe01d1c5343..9e2ddb29ce0b 100644 --- a/sys/dev/random/randomdev.c +++ b/sys/dev/random/randomdev.c @@ -236,11 +236,15 @@ READ_RANDOM_UIO(struct uio *uio, bool nonblock) } /*- - * Kernel API version of read_random(). - * This is similar to random_alg_read(), - * except it doesn't interface with uio(9). - * It cannot assumed that random_buf is a multiple of - * RANDOM_BLOCKSIZE bytes. + * Kernel API version of read_random(). This is similar to read_random_uio(), + * except it doesn't interface with uio(9). It cannot assumed that random_buf + * is a multiple of RANDOM_BLOCKSIZE bytes. + * + * If the tunable 'kern.random.initial_seeding.bypass_before_seeding' is set + * non-zero, silently fail to emit random data (matching the pre-r346250 + * behavior). If read_random is called prior to seeding and bypassed because + * of this tunable, the condition is reported in the read-only sysctl + * 'kern.random.initial_seeding.read_random_bypassed_before_seeding'. */ void READ_RANDOM(void *random_buf, u_int len) @@ -249,12 +253,31 @@ READ_RANDOM(void *random_buf, u_int len) KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__)); p_random_alg_context->ra_pre_read(); + + if (len == 0) + return; + /* (Un)Blocking logic */ - if (!p_random_alg_context->ra_seeded()) + if (__predict_false(!p_random_alg_context->ra_seeded())) { + if (random_bypass_before_seeding) { + if (!read_random_bypassed_before_seeding) { + if (!random_bypass_disable_warnings) + printf("read_random: WARNING: bypassing" + " request for random data because " + "the random device is not yet " + "seeded and the knob " + "'bypass_before_seeding' was " + "enabled.\n"); + read_random_bypassed_before_seeding = true; + } + /* Avoid potentially leaking stack garbage */ + memset(random_buf, 0, len); + return; + } + (void)randomdev_wait_until_seeded(SEEDWAIT_UNINTERRUPTIBLE); + } read_rate_increment(roundup2(len, sizeof(uint32_t))); - if (len == 0) - return; /* * The underlying generator expects multiples of * RANDOM_BLOCKSIZE. diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h index e5df7efefa5b..91c93aee0805 100644 --- a/sys/dev/random/randomdev.h +++ b/sys/dev/random/randomdev.h @@ -37,6 +37,7 @@ #ifdef SYSCTL_DECL /* from sysctl.h */ SYSCTL_DECL(_kern_random); +SYSCTL_DECL(_kern_random_initial_seeding); #define RANDOM_CHECK_UINT(name, min, max) \ static int \ @@ -55,6 +56,11 @@ random_check_uint_##name(SYSCTL_HANDLER_ARGS) \ MALLOC_DECLARE(M_ENTROPY); +extern bool random_bypass_before_seeding; +extern bool read_random_bypassed_before_seeding; +extern bool arc4random_bypassed_before_seeding; +extern bool random_bypass_disable_warnings; + #endif /* _KERNEL */ struct harvest_event; |