svn commit: r347546 - head/sys/dev/random

Conrad Meyer cem at FreeBSD.org
Mon May 13 19:35:37 UTC 2019


Author: cem
Date: Mon May 13 19:35:35 2019
New Revision: 347546
URL: https://svnweb.freebsd.org/changeset/base/347546

Log:
  Fortuna: Fix false negatives in is_random_seeded()
  
  (1) We may have had sufficient entropy to consider Fortuna seeded, but the
  random_fortuna_seeded() function would produce a false negative if
  fs_counter was still zero.  This condition could arise after
  random_harvestq_prime() processed the /boot/entropy file and before any
  read-type operation invoked "pre_read()."  Fortuna's fs_counter variable is
  only incremented (if certain conditions are met) by reseeding, which is
  invoked by random_fortuna_pre_read().
  
  is_random_seeded(9) was introduced in r346282, but the function was unused
  prior to r346358, which introduced this regression.  The regression broke
  initial seeding of arc4random(9) and broke periodic reseeding[A], until something
  other than arc4random(9) invoked read_random(9) or read_random_uio(9) directly.
  (Such as userspace getrandom(2) or read(2) of /dev/random.  By default,
  /etc/rc.d/random does this during multiuser start-up.)
  
  (2) The conditions under which Fortuna will reseed (including initial seeding)
  are: (a) sufficient "entropy" (by sheer byte count; default 64) is collected
  in the zeroth pool (of 32 pools), and (b) it has been at least 100ms since
  the last reseed (to prevent trivial DoS; part of FS&K design).  Prior to
  this revision, initial seeding might have been prevented if the reseed
  function was invoked during the first 100ms of boot.
  
  This revision addresses both of these issues.  If random_fortuna_seeded()
  observes a zero fs_counter, it invokes random_fortuna_pre_read() and checks
  again.  This addresses the problem where entropy actually was sufficient,
  but nothing had attempted a read -> pre_read yet.
  
  The second change is to disable the 100ms reseed guard when Fortuna has
  never been seeded yet (fs_lasttime == 0).  The guard is intended to prevent
  gratuitous subsequent reseeds, not initial seeding!
  
  Machines running CURRENT between r346358 and this revision are encouraged to
  refresh when possible.  Keys generated by userspace with /dev/random or
  getrandom(9) during this timeframe are safe, but any long-term session keys
  generated by kernel arc4random consumers are potentially suspect.
  
  [A]: Broken in the sense that is_random_seeded(9) false negatives would cause
  arc4random(9) to (re-)seed with weak entropy (SHA256(cyclecount ||
  FreeBSD_version)).
  
  PR:		237869
  Reported by:	delphij, dim
  Reviewed by:	delphij
  Approved by:	secteam(delphij)
  X-MFC-With:	r346282, r346358 (if ever)
  Security:	yes
  Sponsored by:	Dell EMC Isilon
  Differential Revision:	https://reviews.freebsd.org/D20239

Modified:
  head/sys/dev/random/fortuna.c

Modified: head/sys/dev/random/fortuna.c
==============================================================================
--- head/sys/dev/random/fortuna.c	Mon May 13 19:31:09 2019	(r347545)
+++ head/sys/dev/random/fortuna.c	Mon May 13 19:35:35 2019	(r347546)
@@ -130,6 +130,7 @@ static uint8_t zero_region[RANDOM_ZERO_BLOCKSIZE];
 static void random_fortuna_pre_read(void);
 static void random_fortuna_read(uint8_t *, u_int);
 static bool random_fortuna_seeded(void);
+static bool random_fortuna_seeded_internal(void);
 static void random_fortuna_process_event(struct harvest_event *);
 static void random_fortuna_init_alg(void *);
 static void random_fortuna_deinit_alg(void *);
@@ -277,7 +278,7 @@ random_fortuna_reseed_internal(uint32_t *entropy_data,
 
 	RANDOM_RESEED_ASSERT_LOCK_OWNED();
 
-	seeded = random_fortuna_seeded();
+	seeded = random_fortuna_seeded_internal();
 	if (seeded) {
 		randomdev_getkey(&fortuna_state.fs_key, &keymaterial, &keysz);
 		KASSERT(keysz == RANDOM_KEYSIZE, ("%s: key size %zu not %u",
@@ -377,8 +378,12 @@ random_fortuna_pre_read(void)
 
 	if (fortuna_state.fs_pool[0].fsp_length < fortuna_state.fs_minpoolsize
 #ifdef _KERNEL
-	    /* FS&K - Use 'getsbinuptime()' to prevent reseed-spamming. */
-	    || (now - fortuna_state.fs_lasttime <= SBT_1S/10)
+	    /*
+	     * FS&K - Use 'getsbinuptime()' to prevent reseed-spamming, but do
+	     * not block initial seeding (fs_lasttime == 0).
+	     */
+	    || (__predict_true(fortuna_state.fs_lasttime != 0) &&
+		now - fortuna_state.fs_lasttime <= SBT_1S/10)
 #endif
 	) {
 		RANDOM_RESEED_UNLOCK();
@@ -460,7 +465,13 @@ SYSCTL_BOOL(_kern_random, OID_AUTO, block_seeded_statu
     "unavailable.");
 #endif
 
-bool
+static bool
+random_fortuna_seeded_internal(void)
+{
+	return (!uint128_is_zero(fortuna_state.fs_counter));
+}
+
+static bool
 random_fortuna_seeded(void)
 {
 
@@ -469,5 +480,14 @@ random_fortuna_seeded(void)
 		return (false);
 #endif
 
-	return (!uint128_is_zero(fortuna_state.fs_counter));
+	if (__predict_true(random_fortuna_seeded_internal()))
+		return (true);
+
+	/*
+	 * Maybe we have enough entropy in the zeroth pool but just haven't
+	 * kicked the initial seed step.  Do so now.
+	 */
+	random_fortuna_pre_read();
+
+	return (random_fortuna_seeded_internal());
 }


More information about the svn-src-all mailing list