Index: sys/dev/random/dummy_rng.c =================================================================== --- sys/dev/random/dummy_rng.c +++ sys/dev/random/dummy_rng.c @@ -63,40 +63,6 @@ #ifdef RANDOM_DEBUG printf("random: %s\n", __func__); #endif - - randomdev_init_reader(dummy_random_read_phony); -} - -/* This is used only by the internal read_random(9) call, and then only - * if no entropy processor is loaded. - * - * Make a token effort to provide _some_ kind of output. No warranty of - * the quality of this output is made, mainly because its lousy. - * - * This is only used by the internal read_random(9) call when no other - * adaptor is active. - * - * It has external scope due to the way things work in - * randomdev_[de]init_reader() that the rest of the world doesn't need to - * know about. - * - * Caveat Emptor. - */ -void -dummy_random_read_phony(uint8_t *buf, u_int count) -{ - /* If no entropy device is loaded, don't spam the console with warnings */ - u_long randval; - size_t size, i; - - /* srandom() is called in kern/init_main.c:proc0_post() */ - - /* Fill buf[] with random(9) output */ - for (i = 0; i < count; i += sizeof(randval)) { - randval = random(); - size = MIN(count - i, sizeof(randval)); - memcpy(buf + i, &randval, (size_t)size); - } } struct random_adaptor randomdev_dummy = { Index: sys/dev/random/randomdev.h =================================================================== --- sys/dev/random/randomdev.h +++ sys/dev/random/randomdev.h @@ -41,9 +41,6 @@ void randomdev_deinit_harvester(void); void randomdev_deinit_reader(void); -/* Stub/fake routines for when no entropy processor is loaded */ -extern void dummy_random_read_phony(uint8_t *, u_int); - /* kern.random sysctls */ #ifdef SYSCTL_DECL /* from sysctl.h */ SYSCTL_DECL(_kern_random); Index: sys/dev/random/randomdev.c =================================================================== --- sys/dev/random/randomdev.c +++ sys/dev/random/randomdev.c @@ -214,7 +214,7 @@ */ /* Hold the address of the routine which is actually called */ -static void (*read_func)(uint8_t *, u_int) = dummy_random_read_phony; +static void (*read_func)(uint8_t *, u_int); /* Initialise the reader when/if it is loaded */ void @@ -229,7 +229,7 @@ randomdev_deinit_reader(void) { - read_func = dummy_random_read_phony; + read_func = NULL; } /* Kernel API version of read_random(). @@ -237,10 +237,10 @@ * the entropy device. */ int -read_random(void *buf, int count) +priv_read_random(void *buf, int count) { - if (count < 0) + if (count <= 0 || read_func == NULL) return 0; read_func(buf, count); Index: sys/dev/random/yarrow.c =================================================================== --- sys/dev/random/yarrow.c +++ sys/dev/random/yarrow.c @@ -147,7 +147,7 @@ /* Set up the lock for the reseed/gate state */ #ifdef _KERNEL - mtx_init(&random_reseed_mtx, "reseed mutex", NULL, MTX_DEF); + mtx_init(&random_reseed_mtx, "reseed mutex", NULL, MTX_SPIN); #else /* !_KERNEL */ mtx_init(&random_reseed_mtx, mtx_plain); #endif /* _KERNEL */ @@ -265,7 +265,7 @@ { u_int pl; - mtx_lock(&random_reseed_mtx); + mtx_lock_spin(&random_reseed_mtx); /* Accumulate the event into the appropriate pool * where each event carries the destination information. @@ -278,7 +278,7 @@ random_yarrow_post_insert(); - mtx_unlock(&random_reseed_mtx); + mtx_unlock_spin(&random_reseed_mtx); } /* Process a block of data suspected to be slightly stochastic */ @@ -440,7 +440,7 @@ return; /* The reseed task must not be jumped on */ - mtx_lock(&random_reseed_mtx); + mtx_lock_spin(&random_reseed_mtx); blockcount = (bytecount + BLOCKSIZE - 1)/BLOCKSIZE; for (i = 0; i < blockcount; i++) { @@ -461,7 +461,7 @@ } } - mtx_unlock(&random_reseed_mtx); + mtx_unlock_spin(&random_reseed_mtx); } /* Internal function to hand external entropy to the PRNG */ @@ -471,7 +471,7 @@ uintmax_t timestamp; /* We must be locked for all this as plenty of state gets messed with */ - mtx_lock(&random_reseed_mtx); + mtx_lock_spin(&random_reseed_mtx); timestamp = get_cyclecount(); randomdev_hash_iterate(&yarrow_state.start_cache.hash, ×tamp, sizeof(timestamp)); @@ -495,7 +495,7 @@ random_yarrow_process_buffer(yarrow_state.start_cache.junk, KEYSIZE); memset(yarrow_state.start_cache.junk, 0, KEYSIZE); - mtx_unlock(&random_reseed_mtx); + mtx_unlock_spin(&random_reseed_mtx); } static void @@ -517,9 +517,9 @@ random_yarrow_reseed(void) { - mtx_lock(&random_reseed_mtx); + mtx_lock_spin(&random_reseed_mtx); reseed(SLOW); - mtx_unlock(&random_reseed_mtx); + mtx_unlock_spin(&random_reseed_mtx); } int Index: sys/libkern/arc4random.c =================================================================== --- sys/libkern/arc4random.c +++ sys/libkern/arc4random.c @@ -14,12 +14,17 @@ #include #include #include +#include #include #include #include #include #include +#include + +#include + #define ARC4_RESEED_BYTES 65536 #define ARC4_RESEED_SECONDS 300 #define ARC4_KEYBYTES (256 / 8) @@ -44,6 +49,29 @@ *b = c; } +static int +get_last_resort_seed(uint8_t *key, int cnt) +{ + struct timespec ts; + uint8_t buf[8 + sizeof ts]; + int pos; + + KASSERT(cnt >= 32, ("not enough space for sha256 digest")); + + pos = 0; + + be64enc(&buf[pos], get_cyclecount()); + pos += 8; + + nanotime(&ts); + memcpy(&buf[pos], &ts, sizeof ts); + pos += sizeof ts; + + SHA256_Data(&buf[0], pos, key); + + return 32; +} + /* * Stir our S-box. */ @@ -58,15 +86,18 @@ * XXX read_random() returns unsafe numbers if the entropy * device is not loaded -- MarkM. */ - r = read_random(key, ARC4_KEYBYTES); + r = priv_read_random(key, ARC4_KEYBYTES); getmicrouptime(&tv_now); - mtx_lock(&arc4_mtx); - /* If r == 0 || -1, just use what was on the stack. */ - if (r > 0) { - for (n = r; n < sizeof(key); n++) - key[n] = key[n % r]; + mtx_lock_spin(&arc4_mtx); + if (r <= 0) { + r = get_last_resort_seed(key, sizeof key); + + /* XXX - we should always reseed till random(4) is ready */ } + for (n = r; n < sizeof(key); n++) + key[n] = key[n % r]; + for (n = 0; n < 256; n++) { arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256; arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]); @@ -84,7 +115,7 @@ */ for (n = 0; n < 256*4; n++) arc4_randbyte(); - mtx_unlock(&arc4_mtx); + mtx_unlock_spin(&arc4_mtx); } /* @@ -95,7 +126,7 @@ { int n; - mtx_init(&arc4_mtx, "arc4_mtx", NULL, MTX_DEF); + mtx_init(&arc4_mtx, "arc4_mtx", NULL, MTX_SPIN); arc4_i = arc4_j = 0; for (n = 0; n < 256; n++) arc4_sbox[n] = (u_int8_t) n; @@ -138,12 +169,12 @@ (tv.tv_sec > arc4_t_reseed)) arc4_randomstir(); - mtx_lock(&arc4_mtx); + mtx_lock_spin(&arc4_mtx); arc4_numruns += len; p = ptr; while (len--) *p++ = arc4_randbyte(); - mtx_unlock(&arc4_mtx); + mtx_unlock_spin(&arc4_mtx); } uint32_t Index: sys/libkern/random.c =================================================================== --- sys/libkern/random.c +++ sys/libkern/random.c @@ -34,45 +34,33 @@ #include -#define NSHUFF 50 /* to drop some "seed -> 1st value" linearity */ - -static u_long randseed = 937186357; /* after srandom(1), NSHUFF counted */ - void -srandom(seed) - u_long seed; +srandom(u_long seed __unused) { - int i; - - randseed = seed; - for (i = 0; i < NSHUFF; i++) - (void)random(); } /* - * Pseudo-random number generator for randomizing the profiling clock, - * and whatever else we might use it for. The result is uniform on - * [0, 2^31 - 1]. + * Return a uniformly random value over [0, top). + * + * Use the simple algorithm that if random value v is in the range + * [0, n * top) where n is an integer, return v % top. If v is + * equal to or larger than n * top, it would not be uniform, so pick a + * new v and try again. */ -u_long -random() +uint64_t +random_uniform(uint64_t top) { - register long x, hi, lo, t; + uint64_t r; + uint64_t max; + + /* XXX - should be 2^64 */ + max = UINT64_MAX / top * top; + + for (;;) { + r = random64(); + if (r >= max) + continue; - /* - * Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1). - * From "Random number generators: good ones are hard to find", - * Park and Miller, Communications of the ACM, vol. 31, no. 10, - * October 1988, p. 1195. - */ - /* Can't be initialized with 0, so use another value. */ - if ((x = randseed) == 0) - x = 123459876; - hi = x / 127773; - lo = x % 127773; - t = 16807 * lo - 2836 * hi; - if (t < 0) - t += 0x7fffffff; - randseed = t; - return (t); + return r % top; + } } Index: sys/sys/libkern.h =================================================================== --- sys/sys/libkern.h +++ sys/sys/libkern.h @@ -75,10 +75,43 @@ #define ARC4_ENTR_SEED 2 /* Reseeding. */ extern int arc4rand_iniseed_state; -/* Prototypes for non-quad routines. */ -struct malloc_type; +/* Deprecated random functions */ uint32_t arc4random(void); void arc4rand(void *ptr, u_int len, int reseed); +void srandom(u_long); + +/* Random functions */ +static __inline uint32_t +random(void) +{ + uint32_t r; + + arc4rand((uint8_t *)&r, sizeof r, 0); + + return r; +} + +static __inline uint64_t +random64(void) +{ + uint64_t r; + + arc4rand((uint8_t *)&r, sizeof r, 0); + + return r; +} + +static __inline void +random_buf(uint8_t *buf, size_t cnt) +{ + + arc4rand(buf, cnt, 0); +} + +uint64_t random_uniform(uint64_t); + +/* Prototypes for non-quad routines. */ +struct malloc_type; int bcmp(const void *, const void *, size_t); int timingsafe_bcmp(const void *, const void *, size_t); void *bsearch(const void *, const void *, size_t, @@ -109,9 +142,7 @@ int (*compar)(const void *, const void *)); void qsort_r(void *base, size_t nmemb, size_t size, void *thunk, int (*compar)(void *, const void *, const void *)); -u_long random(void); int scanc(u_int, const u_char *, const u_char *, int); -void srandom(u_long); int strcasecmp(const char *, const char *); char *strcat(char * __restrict, const char * __restrict); char *strchr(const char *, int); Index: sys/sys/random.h =================================================================== --- sys/sys/random.h +++ sys/sys/random.h @@ -31,7 +31,20 @@ #ifdef _KERNEL -int read_random(void *, int); +#include + +/* Deprecated */ +static __inline int +read_random(void *buf, int cnt) +{ + + arc4rand(buf, cnt, 0); + + return cnt; +} + +/* Temporary internal interface to random adaptors */ +int priv_read_random(void *, int); /* * Note: if you add or remove members of random_entropy_source, remember to also update the