kern/143298: random_yarrow_block() doesn't actually block when not seeded

James Juran james.juran at baesystems.com
Wed Jan 27 19:00:02 UTC 2010


>Number:         143298
>Category:       kern
>Synopsis:       random_yarrow_block() doesn't actually block when not seeded
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jan 27 19:00:01 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator:     James Juran
>Release:        FreeBSD-8.0
>Organization:
BAE Systems
>Environment:
FreeBSD freebsd8.goldlnk.rootlnka.net 8.0-RELEASE FreeBSD 8.0-RELEASE #0: Sat Nov 21 15:48:17 UTC 2009     root at almeida.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386
>Description:
I believe r153575 introduced a problem with the /dev/random yarrow random number generator's blocking when it is not seeded.

This has likely not been noticed until now because yarrow is marked as seeded when it is loaded by default, so someone would have to change the sysctl value from the default.  This problem likely only affects users who want to do "better" seeding of /dev/random than is provided by /etc/rc.d/initrandom.

In this change the blocking logic was moved from random_read() into a .block method for the particular random number generation method so that the GIANT lock could be removed.  In doing this though, the loop guard appears to have been inadvertently changed from

while (!random_systat.seeded && !error)

to 

while (random_systat.seeded && !error)

>How-To-Repeat:
In FreeBSD 8.0, this incorrect behavior can be observed by doing:

// By default it is seeded and outputs data; no problem here
[root at freebsd8 ~]# sysctl kern.random.sys.seeded
kern.random.sys.seeded: 1
[root at freebsd8 ~]# time dd if=/dev/random bs=1 count=1
=1+0 records in
1+0 records out
1 bytes transferred in 0.000006 secs (167772 bytes/sec)

real    0m0.005s
user    0m0.000s
sys     0m0.006s


// Now mark it as unseeded.  It still produces data and is still marked
// as unseeded after the data is produced.  It should block until the
// seeding is complete.
[root at freebsd8 ~]# sysctl kern.random.sys.seeded=0
kern.random.sys.seeded: 1 -> 0
[root at freebsd8 ~]# time dd if=/dev/random bs=1 count=1
¿1+0 records in
1+0 records out
1 bytes transferred in 0.000006 secs (167772 bytes/sec)

real    0m0.006s
user    0m0.000s
sys     0m0.006s
[root at freebsd8 ~]# sysctl kern.random.sys.seeded
kern.random.sys.seeded: 0

>Fix:
I have not tested this fix and am not able to do so, but I think this will solve the problem and restore the intended behavior.




Patch attached with submission follows:

Index: sys/dev/random/randomdev_soft.c
===================================================================
--- sys/dev/random/randomdev_soft.c	(revision 203082)
+++ sys/dev/random/randomdev_soft.c	(working copy)
@@ -391,7 +391,7 @@ random_yarrow_block(int flag)
 	mtx_lock(&random_reseed_mtx);
 
 	/* Blocking logic */
-	while (random_systat.seeded && !error) {
+	while (!random_systat.seeded && !error) {
 		if (flag & O_NONBLOCK)
 			error = EWOULDBLOCK;
 		else {


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list