Date: Mon, 28 Apr 2008 20:19:43 GMT From: Robert Woolley <freebsd-pr08@mlists.homeunix.com> To: freebsd-gnats-submit@FreeBSD.org Subject: kern/123177: arc4rand(9) produces the same sequence on each boot Message-ID: <200804282019.m3SKJhHf087335@www.freebsd.org> Resent-Message-ID: <200804282030.m3SKU3gt005559@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 123177 >Category: kern >Synopsis: arc4rand(9) produces the same sequence on each boot >Confidential: no >Severity: critical >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Mon Apr 28 20:30:03 UTC 2008 >Closed-Date: >Last-Modified: >Originator: Robert Woolley >Release: 7.0 >Organization: >Environment: FreeBSD gumby.homeunix.com 7.0-RELEASE-p1 FreeBSD 7.0-RELEASE-p1 #18: Mon Apr 28 14:53:51 BST 2008 root@gumby.homeunix.com:/usr/obj/usr/src/sys/MUSTARD i386 >Description: arc4rand(9) is used as a source of secure random numbers in the kernel. As far as I can tell, it's the source of the disposable keys for "geli onetime" partitions. It's seeded the first time it's called using read_random(), which is implemented by yarrow (except on VIA Nehemiah). The problem is that the first call happens before yarrow is seeded and the yarrow cipher-context is initialized. This results in a given kernel producing the same sequence on each boot, and it wont reseed for 5 minutes or 64KB. It also appears that the use of an uninitialized cipher-context may be causing dubious memory accesses. The sequence alters if the kernel is modified, despite the relevant data structures being static (i.e. pre-zeroed) or explicitly set-up. >How-To-Repeat: In /etc/rc.d/initrandom, add some calls to "sysctl kern.arandom" after the line: feed_dev_random "${entropy_file}" and cycle the machine a few times. I'm seeing the same sequence each time. By this point in the boot sequence yarrow must have seeded. (BTW a few lines up "sysctl -a" is dumped into /dev/random before the entropy file. This does cause a call to arc4rand(), but it's not first. You may wish to remove this.) >Fix: The patch does two things: 1. Reseeds arc4rand when root closes /dev/random (just after yarrow is reseeded by the entropy file). 2. Provides a provisional yarrow cipher-context to support early calls to read_random. Patch attached with submission follows: diff -ur /usr/src.orig/sys/dev/random/randomdev.c /usr/src/sys/dev/random/randomdev.c --- /usr/src.orig/sys/dev/random/randomdev.c 2006-11-06 13:41:55.000000000 +0000 +++ /usr/src/sys/dev/random/randomdev.c 2008-04-28 14:34:57.000000000 +0100 @@ -36,6 +36,7 @@ #include <sys/filio.h> #include <sys/kernel.h> #include <sys/kthread.h> +#include <sys/libkern.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/module.h> @@ -88,8 +89,12 @@ { if ((flags & FWRITE) && (priv_check(td, PRIV_RANDOM_RESEED) == 0) && (securelevel_gt(td->td_ucred, 0) == 0)) { + (*random_systat.reseed)(); random_systat.seeded = 1; + + /* Reseed any other secure PRNGs */ + arc4rand(NULL, 0, 1); } return (0); diff -ur /usr/src.orig/sys/dev/random/yarrow.c /usr/src/sys/dev/random/yarrow.c --- /usr/src.orig/sys/dev/random/yarrow.c 2007-11-29 16:05:38.000000000 +0000 +++ /usr/src/sys/dev/random/yarrow.c 2008-04-28 14:38:49.000000000 +0100 @@ -37,6 +37,8 @@ #include <sys/sysctl.h> #include <sys/systm.h> +#include <machine/cpu.h> + #include <crypto/rijndael/rijndael-api-fst.h> #include <crypto/sha2/sha2.h> @@ -160,6 +162,14 @@ for (i = 0; i < 2; i++) yarrow_hash_init(&random_state.pool[i].hash); + /* Generate a provisional cipher key so that read_random + * can be used to seed arc4rand(9) (must be securely reseeded). + * We do a second get_cyclecount() later, as some CPUs need + * to fall back to nanotime, which doesn't work properly yet. + */ + random_state.counter[0] = get_cyclecount(); + yarrow_encrypt_init(&random_state.key, random_state.counter); + /* Clear the counter */ for (i = 0; i < 4; i++) random_state.counter[i] = 0; @@ -274,6 +284,10 @@ int i; int retval; + /* Some entropy may be needed on the first call. */ + if (gate) + random_state.counter[1] = get_cyclecount(); + /* The reseed task must not be jumped on */ mtx_lock(&random_reseed_mtx); >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200804282019.m3SKJhHf087335>