Author: cem
Date: Thu Apr 18 20:48:54 2019
New Revision: 346358
URL: https://svnweb.freebsd.org/changeset/base/346358

Log:
  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

Modified:
  head/UPDATING
  head/sys/dev/random/random_infra.c
  head/sys/dev/random/randomdev.c
  head/sys/dev/random/randomdev.h
  head/sys/libkern/arc4random.c
  head/sys/mips/conf/PB92
  head/sys/sys/param.h

Modified: head/UPDATING
==============================================================================
--- head/UPDATING       Thu Apr 18 19:16:34 2019        (r346357)
+++ head/UPDATING       Thu Apr 18 20:48:54 2019        (r346358)
@@ -31,6 +31,30 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
        disable the most expensive debugging functionality run
        "ln -s 'abort:false,junk:false' /etc/malloc.conf".)
 
+20190418:
+       The following knobs have been added related to tradeoffs between
+       safe use of the random device and availability in the absence of
+       entropy:
+
+       kern.random.initial_seeding.bypass_before_seeding: tunable; set
+       non-zero to bypass the random device prior to seeding, or zero to
+       block random requests until the random device is initially seeded.
+       For now, set to 1 (unsafe) by default to restore pre-r346250 boot
+       availability properties.
+
+       kern.random.initial_seeding.read_random_bypassed_before_seeding:
+       read-only diagnostic sysctl that is set when bypass is enabled and
+       read_random(9) is bypassed, to enable programmatic handling of this
+       initial condition, if desired.
+
+       kern.random.initial_seeding.arc4random_bypassed_before_seeding:
+       Similar to the above, but for for arc4random(9) initial seeding.
+
+       kern.random.initial_seeding.disable_bypass_warnings: tunable; set
+       non-zero to disable warnings in dmesg when the same conditions are
+       met as for the diagnostic sysctls above.  Defaults to zero, i.e.,
+       produce warnings in dmesg when the conditions are met.
+
 20190416:
        The tunable "security.stack_protect.permit_nonrandom_cookies" may be
        set to a non-zero value to boot systems that do not provide early

Modified: head/sys/dev/random/random_infra.c
==============================================================================
--- head/sys/dev/random/random_infra.c  Thu Apr 18 19:16:34 2019        
(r346357)
+++ head/sys/dev/random/random_infra.c  Thu Apr 18 20:48:54 2019        
(r346358)
@@ -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");
 

Modified: head/sys/dev/random/randomdev.c
==============================================================================
--- head/sys/dev/random/randomdev.c     Thu Apr 18 19:16:34 2019        
(r346357)
+++ head/sys/dev/random/randomdev.c     Thu Apr 18 20:48:54 2019        
(r346358)
@@ -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.

Modified: head/sys/dev/random/randomdev.h
==============================================================================
--- head/sys/dev/random/randomdev.h     Thu Apr 18 19:16:34 2019        
(r346357)
+++ head/sys/dev/random/randomdev.h     Thu Apr 18 20:48:54 2019        
(r346358)
@@ -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                                                             \
@@ -54,6 +55,11 @@ random_check_uint_##name(SYSCTL_HANDLER_ARGS)                
                \
 #endif /* SYSCTL_DECL */
 
 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 */
 

Modified: head/sys/libkern/arc4random.c
==============================================================================
--- head/sys/libkern/arc4random.c       Thu Apr 18 19:16:34 2019        
(r346357)
+++ head/sys/libkern/arc4random.c       Thu Apr 18 20:48:54 2019        
(r346358)
@@ -41,6 +41,9 @@ __FBSDID("$FreeBSD$");
 #include <sys/time.h>
 
 #include <crypto/chacha20/chacha.h>
+#include <crypto/sha2/sha256.h>
+#include <dev/random/randomdev.h>
+#include <machine/cpu.h>
 
 #define        CHACHA20_RESEED_BYTES   65536
 #define        CHACHA20_RESEED_SECONDS 300
@@ -77,12 +80,43 @@ chacha20_randomstir(struct chacha20_s *chacha20)
        struct timeval tv_now;
        u_int8_t key[CHACHA20_KEYBYTES];
 
-       /*
-        * If the loader(8) did not have an entropy stash from the previous
-        * shutdown to load, then we will block.  The answer is to make sure
-        * there is an entropy stash at shutdown time.
-        */
-       read_random(key, CHACHA20_KEYBYTES);
+       if (__predict_false(random_bypass_before_seeding && 
!is_random_seeded())) {
+               SHA256_CTX ctx;
+               uint64_t cc;
+               uint32_t fver;
+
+               if (!arc4random_bypassed_before_seeding) {
+                       arc4random_bypassed_before_seeding = true;
+                       if (!random_bypass_disable_warnings)
+                               printf("arc4random: WARNING: initial seeding "
+                                   "bypassed the cryptographic random device "
+                                   "because it was not yet seeded and the "
+                                   "knob 'bypass_before_seeding' was "
+                                   "enabled.\n");
+               }
+
+               /* Last ditch effort to inject something in a bad condition. */
+               cc = get_cyclecount();
+               SHA256_Init(&ctx);
+               SHA256_Update(&ctx, key, sizeof(key));
+               SHA256_Update(&ctx, &cc, sizeof(cc));
+               fver = __FreeBSD_version;
+               SHA256_Update(&ctx, &fver, sizeof(fver));
+               _Static_assert(sizeof(key) == SHA256_DIGEST_LENGTH,
+                   "make sure 256 bits is still 256 bits");
+               SHA256_Final(key, &ctx);
+       } else {
+               /*
+               * If the loader(8) did not have an entropy stash from the
+               * previous shutdown to load, then we will block.  The answer is
+               * to make sure there is an entropy stash at shutdown time.
+               *
+               * On the other hand, if the random_bypass_before_seeding knob
+               * was set and we landed in this branch, we know this won't
+               * block because we know the random device is seeded.
+               */
+               read_random(key, CHACHA20_KEYBYTES);
+       }
        getmicrouptime(&tv_now);
        mtx_lock(&chacha20->mtx);
        chacha_keysetup(&chacha20->ctx, key, CHACHA20_KEYBYTES*8);

Modified: head/sys/mips/conf/PB92
==============================================================================
--- head/sys/mips/conf/PB92     Thu Apr 18 19:16:34 2019        (r346357)
+++ head/sys/mips/conf/PB92     Thu Apr 18 20:48:54 2019        (r346358)
@@ -133,5 +133,5 @@ device              loop
 device         ether
 #device                md
 #device                bpf
-#device                random
+device         random
 #device                if_bridge

Modified: head/sys/sys/param.h
==============================================================================
--- head/sys/sys/param.h        Thu Apr 18 19:16:34 2019        (r346357)
+++ head/sys/sys/param.h        Thu Apr 18 20:48:54 2019        (r346358)
@@ -60,7 +60,7 @@
  *             in the range 5 to 9.
  */
 #undef __FreeBSD_version
-#define __FreeBSD_version 1300019      /* Master, propagated to newvers */
+#define __FreeBSD_version 1300020      /* Master, propagated to newvers */
 
 /*
  * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,


_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to