Index: head/share/man/man4/random.4 =================================================================== --- head/share/man/man4/random.4 +++ head/share/man/man4/random.4 @@ -23,7 +23,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 26, 2018 +.Dd April 15, 2019 .Dt RANDOM 4 .Os .Sh NAME @@ -32,63 +32,44 @@ .Sh SYNOPSIS .Cd "device random" .Cd "options RANDOM_LOADABLE" +.Cd "options RANDOM_ENABLE_ETHER" .Cd "options RANDOM_ENABLE_UMA" .Sh DESCRIPTION The .Nm -device -returns an endless supply of random bytes when read. -It also accepts and reads data -as any ordinary file. +device returns an endless supply of random bytes when read. .Pp The generator will start in an .Em unseeded -state, and will block reads until -it is seeded for the first time. -This may cause trouble at system boot -when keys and the like -are generated from -.Nm -so steps should be taken to ensure a -seeding as soon as possible. +state, and will block reads until it is seeded for the first time. .Pp -It is also possible -to read random bytes -by using the KERN_ARND sysctl. -On the command line -this could be done by +To provide prompt access to the random device at boot time, +.Fx +automatically persists some entropy data in +.Pa /boot/entropy +for the loader to provide to the kernel. +Additional entropy is regularly saved in +.Pa /var/db/entropy . +This saved entropy is sufficient to unblock the random device on devices with +writeable media. .Pp -.Dl "sysctl -x -B 16 kern.arandom" +Embedded applications without writable media must determine their own scheme +for re-seeding the random device on boot, or accept that the device +will remain unseeded and block reads indefinitely. +See +.Sx SECURITY CONSIDERATIONS +for more detail. .Pp -This sysctl will not return -random bytes unless -the -.Nm -device is seeded. +In addition to +.Xr read 2 , +the direct output of the abstract kernel entropy device can be read with +.Xr getrandom 2 , +.Xr getentropy 3 , +or the +.Xr sysctl 8 +pseudo-variable +.Va kern.arandom . .Pp -This initial seeding -of random number generators -is a bootstrapping problem -that needs very careful attention. -In some cases, -it may be difficult -to find enough randomness -to seed a random number generator -until a system is fully operational, -but the system requires random numbers -to become fully operational. -It is (or more accurately should be) -critically important that the -.Nm -device is seeded -before the first time it is used. -In the case where a dummy or "blocking-only" -device is used, -it is the responsibility -of the system architect -to ensure that no blocking reads -hold up critical processes. -.Pp To see the current settings of the software .Nm device, use the command line: @@ -97,17 +78,20 @@ .Pp which results in something like: .Bd -literal -offset indent +kern.random.block_seeded_status: 0 kern.random.fortuna.minpoolsize: 64 -kern.random.harvest.mask_symbolic: [HIGH_PERFORMANCE], ... ,CACHED -kern.random.harvest.mask_bin: 00111111111 -kern.random.harvest.mask: 511 +kern.random.harvest.mask_symbolic: ENABLEDSOURCE,[DISABLEDSOURCE],...,CACHED +kern.random.harvest.mask_bin: 00000010000000111011111 +kern.random.harvest.mask: 66015 +kern.random.use_chacha20_cipher: 0 kern.random.random_sources: 'Intel Secure Key RNG' .Ed .Pp Other than -.Dl kern.random.fortuna.minpoolsize +.Va kern.random.block_seeded_status , +.Va kern.random.fortuna.minpoolsize , and -.Dl kern.random.harvest.mask +.Va kern.random.harvest.mask , all settings are read-only. .Pp The @@ -137,17 +121,66 @@ .Va kern.random.harvest.mask_symbolic sysctls can be used to confirm -that the choices are correct. -Note that disabled items +settings in a human readable form. +Disabled items in the latter item are listed in square brackets. See .Xr random_harvest 9 for more on the harvesting of entropy. +.Sh FILES +.Bl -tag -width ".Pa /dev/urandom" +.It Pa /dev/random +.It Pa /dev/urandom +.El +.Sh SEE ALSO +.Xr getrandom 2 , +.Xr arc4random 3 , +.Xr getentropy 3 , +.Xr random 3 , +.Xr sysctl 8 , +.Xr random 9 +.Rs +.%A Ferguson +.%A Schneier +.%A Kohno +.%B Cryptography Engineering +.%I Wiley +.%O ISBN 978-0-470-47424-2 +.Re +.Sh HISTORY +A +.Nm +device appeared in +.Fx 2.2 . +The implementation was changed to the +.Em Yarrow algorithm in +.Fx 5.0 . +In +.Fx 11.0 , +the Fortuna algorithm was introduced as the default. +In +.Fx 12.0 , +Yarrow was removed entirely. +.Sh AUTHORS +.An -nosplit +The current +.Nm +code was authored by +.An Mark R V Murray , +with significant contributions from many people. .Pp +The +.Em Fortuna +algorithm was designed by +.An Niels Ferguson , +.An Bruce Schneier , +and +.An Tadayoshi Kohno . +.Sh CAVEATS When .Cd "options RANDOM_LOADABLE" -is used, +is enabled, the .Pa /dev/random device is not created @@ -155,13 +188,9 @@ is loaded. The only module built by default is .Em random_fortuna . -The -.Em random_yarrow -module was removed in -.Fx 12 . -Note that this loadable module -is slightly less efficient -than its compiled-in equivalent. +Loadable random modules +are less efficient +than their compiled-in equivalents. This is because some functions must be locked against load and unload events, @@ -170,174 +199,40 @@ .Pp When .Cd "options RANDOM_ENABLE_UMA" -is used, +is enabled, the .Pa /dev/random device will obtain entropy from the zone allocator. -This is potentially very high rate, -and if so will be of questionable use. -If this is the case, -use of this option -is not recommended. -Determining this is not trivial, -so experimenting and measurement -using tools such as -.Xr dtrace 1 -will be required. -.Sh RANDOMNESS -The use of randomness in the field of computing -is a rather subtle issue because randomness means -different things to different people. -Consider generating a password randomly, -simulating a coin tossing experiment or -choosing a random back-off period when a server does not respond. -Each of these tasks requires random numbers, -but the random numbers in each case have different requirements. +This is a very high rate source with significant performance impact. +Therefore, it is disabled by default. .Pp -Generation of passwords, session keys and the like -requires cryptographic randomness. -A cryptographic random number generator should be designed -so that its output is difficult to guess, -even if a lot of auxiliary information is known -(such as when it was seeded, subsequent or previous output, and so on). -On -.Fx , -seeding for cryptographic random number generators is provided by the +When +.Cd "options RANDOM_ENABLE_ETHER" +is enabled, the .Nm -device, -which provides real randomness. -The -.Xr arc4random 3 -library call provides a pseudo-random sequence -which is generally reckoned to be suitable for -simple cryptographic use. -The OpenSSL library also provides functions for managing randomness -via functions such as -.Xr RAND_bytes 3 -and -.Xr RAND_add 3 . -Note that OpenSSL uses the -.Nm -device for seeding automatically. +device will obtain entropy from +.Vt mbuf +structures passing through the network stack. +This source is both extremely expensive and a poor source of entropy, so it is +disabled by default. +.Sh SECURITY CONSIDERATIONS +The initial seeding +of random number generators +is a bootstrapping problem +that needs very careful attention. +When writable media is available, the +.Em Fortuna +paper describes a robust system for rapidly reseeding the device. .Pp -Randomness for simulation is required in engineering or -scientific software and games. -The first requirement of these applications is -that the random numbers produced conform to some well-known, -usually uniform, distribution. -The sequence of numbers should also appear numerically uncorrelated, -as simulation often assumes independence of its random inputs. -Often it is desirable to reproduce -the results of a simulation exactly, -so that if the generator is seeded in the same way, -it should produce the same results. -A peripheral concern for simulation is -the speed of a random number generator. +In some embedded cases, it may be difficult to find enough randomness to seed a +random number generator until a system is fully operational. +In these cases, is the responsibility of the system architect to ensure that +blocking is acceptable, or that the random device is seeded. +(This advice does not apply to typical consumer systems.) .Pp -Another issue in simulation is -the size of the state associated with the random number generator, and -how frequently it repeats itself. -For example, -a program which shuffles a pack of cards should have 52!\& possible outputs, -which requires the random number generator to have 52!\& starting states. -This means the seed should have at least log_2(52!) ~ 226 bits of state -if the program is to stand a chance of outputting all possible sequences, -and the program needs some unbiased way of generating these bits. -Again, -the +To emulate embedded systems, developers may set the +.Va kern.random.block_seeded_status +tunable to 1 to verify boot does not require early availability of the .Nm -device could be used for seeding here, -but in practice, smaller seeds are usually considered acceptable. -.Pp -.Fx -provides two families of functions which are considered -suitable for simulation. -The -.Xr random 3 -family of functions provides a random integer -between 0 to -.if t 2\u\s731\s10\d\(mi1. -.if n (2**31)\(mi1. -The functions -.Xr srandom 3 , -.Xr initstate 3 -and -.Xr setstate 3 -are provided for deterministically setting -the state of the generator and -the function -.Xr srandomdev 3 -is provided for setting the state via the -.Nm device. -The -.Xr drand48 3 -family of functions are also provided, -which provide random floating point numbers in various ranges. -.Pp -Randomness that is used for collision avoidance -(for example, in certain network protocols) -has slightly different semantics again. -It is usually expected that the numbers will be uniform, -as this produces the lowest chances of collision. -Here again, -the seeding of the generator is very important, -as it is required that different instances of -the generator produce independent sequences. -However, the guessability or reproducibility of the sequence is unimportant, -unlike the previous cases. -.Pp -.Fx -does also provide the traditional -.Xr rand 3 -library call, -for compatibility purposes. -However, -it is known to be poor for simulation and -absolutely unsuitable for cryptographic purposes, -so its use is discouraged. -.Sh FILES -.Bl -tag -width ".Pa /dev/random" -.It Pa /dev/random -.El -.Sh SEE ALSO -.Xr arc4random 3 , -.Xr drand48 3 , -.Xr rand 3 , -.Xr RAND_add 3 , -.Xr RAND_bytes 3 , -.Xr random 3 , -.Xr sysctl 8 , -.Xr random 9 -.Rs -.%A Ferguson -.%A Schneier -.%A Kohno -.%B Cryptography Engineering -.%I Wiley -.%O ISBN 978-0-470-47424-2 -.Re -.Sh HISTORY -A -.Nm -device appeared in -.Fx 2.2 . -The current software implementation, -introduced in -.Fx 10.0 , -is by -.An Mark R V Murray , -and is an implementation of the -.Em Fortuna -algorithm by Ferguson -.Em et al . -It replaces the previous -.Em Yarrow -implementation, -introduced in -.Fx 5.0 . -The Yarrow algorithm -is no longer supported -by its authors, -and is therefore no longer available. Index: head/share/man/man9/random.9 =================================================================== --- head/share/man/man9/random.9 +++ head/share/man/man9/random.9 @@ -26,12 +26,13 @@ .\" .\" $FreeBSD$ .\" " -.Dd July 16, 2015 +.Dd April 15, 2019 .Dt RANDOM 9 .Os .Sh NAME .Nm arc4rand , .Nm arc4random , +.Nm arc4random_buf , .Nm random , .Nm read_random , .Nm read_random_uio , @@ -39,86 +40,72 @@ .Nd supply pseudo-random numbers .Sh SYNOPSIS .In sys/libkern.h +.Ft uint32_t +.Fn arc4random "void" .Ft void -.Fn srandom "u_long seed" -.Ft u_long -.Fn random "void" +.Fn arc4random_buf "void *ptr" "size_t len" .Ft void .Fn arc4rand "void *ptr" "u_int length" "int reseed" -.Ft uint32_t -.Fn arc4random "void" .Pp .In sys/random.h -.Ft int +.Ft void .Fn read_random "void *buffer" "int count" .Ft int .Fn read_random_uio "struct uio *uio" "bool nonblock" +.Ss LEGACY ROUTINES +.In sys/libkern.h +.Ft void +.Fn srandom "u_long seed" +.Ft u_long +.Fn random "void" .Sh DESCRIPTION The -.Fn random -function will by default produce -a sequence of numbers -that can be duplicated -by calling -.Fn srandom -with some constant -as the -.Fa seed . -The -.Fn srandom -function may be called with any arbitrary -.Fa seed -value to get slightly more unpredictable numbers. -It is important to remember that the -.Fn random -function is entirely predictable, -and is therefore not of use where -knowledge of the sequence of numbers -may be of benefit to an attacker. +.Fn arc4random +and +.Fn arc4random_buf +functions will return very good quality random numbers, suited for +security-related purposes. +Both are wrappers around the underlying +.Fn arc4rand +interface. +.Fn arc4random +returns a 32-bit random value, while +.Fn arc4random_buf +fills +.Fa ptr +with +.Fa len +bytes of random data. .Pp The .Fn arc4rand -function will return very good quality random numbers, -better suited -for security-related purposes. -The random numbers from -.Fn arc4rand -are seeded from the entropy device -if it is available. -Automatic reseeds happen -after a certain timeinterval -and after a certain number of bytes -have been delivered. -A forced reseed -can be forced -by passing a non-zero -value in the +CSPRNG +is seeded from the +.Xr random 4 +kernel abstract entropy device. +Automatic reseeding happens at unspecified time and bytes (of output) +intervals. +A reseed can be forced by passing a non-zero .Fa reseed -argument. +value. .Pp The .Fn read_random -function is used to return entropy directly from the entropy device -if it has been loaded. -If the entropy device is not loaded, then -the +function is used to read entropy directly from the kernel abstract entropy +device. +.Fn read_random +blocks if and until the entropy device is seeded. +The provided .Fa buffer -is ignored -and zero is returned. -The -.Fa buffer is filled with no more than .Fa count bytes. It is strongly advised that .Fn read_random -is not used; -instead use +is not used directly; +instead, use the .Fn arc4rand -unless it is -necessary to know -that no entropy -has been returned. +family of functions. .Pp The .Fn read_random_uio @@ -129,50 +116,35 @@ The .Fa uio argument points to a buffer where random data should be stored. -This function only returns data if the random device is seeded. -It blocks if unseeded, -except when the +If .Fa nonblock -argument is true. +is true and the random device is not seeded, this function does not return any +data. +Otherwise, this function may block interruptibly until the random device is seeded. +If the function is interrupted before the random device is seeded, no data is +returned. .Pp -All the bits returned by -.Fn random , -.Fn arc4rand , -.Fn read_random , -and -.Fn read_random_uio -are usable. -For example, -.Sq Li random()&01 -will produce a random binary value. -.Pp -The -.Fn arc4random -is a convenience function which calls -.Fn arc4rand -to return a 32 bit pseudo-random integer. +The legacy +.Fn random +function will produce a sequence of numbers that can be duplicated by calling +.Fn srandom +with some constant as the +.Fa seed . +The legacy +.Fn srandom +function may be called with any +.Fa seed +value. +It is strongly advised that the +.Fn random +function not be used to generate random numbers. +See +.Sx SECURITY CONSIDERATIONS . .Sh RETURN VALUES The -.Fn random -function uses -a non-linear additive feedback random number generator -employing a default table -of size 31 -containing long integers -to return successive pseudo-random -numbers in the range from 0 to -.if t 2\u\s731\s10\d\(mi1. -.if n (2**31)\(mi1. -The period of this random number generator -is very large, -approximately -.if t 16\(mu(2\u\s731\s10\d\(mi1). -.if n 16*((2**31)\(mi1). -.Pp -The .Fn arc4rand -function uses the RC4 algorithm -to generate successive pseudo-random bytes. +function uses the Chacha20 algorithm to generate a pseudo-random sequence of +bytes. The .Fn arc4random function uses @@ -191,6 +163,23 @@ .Fn read_random_uio returns zero when successful, otherwise an error code is returned. +.Pp +The legacy +.Fn random +function uses +a non-linear additive feedback random number generator +employing a default table +of size 31 +containing long integers +to return successive pseudo-random +numbers in the range from 0 to +.if t 2\u\s731\s10\d\(mi1. +.if n (2**31)\(mi1. +The period of this random number generator +is very large, +approximately +.if t 16\(mu(2\u\s731\s10\d\(mi1). +.if n 16*((2**31)\(mi1). .Sh ERRORS .Fn read_random_uio may fail if: @@ -210,3 +199,19 @@ .An Mark R V Murray wrote .Fn read_random . +.Sh SECURITY CONSIDERATIONS +Do not use +.Fn random +or +.Fn srandom +in new code. +.Pp +It is important to remember that the +.Fn random +function is entirely predictable. +It is easy for attackers to predict future output of +.Fn random +by recording some generated values. +We cannot emphasize strongly enough that +.Fn random +must not be used to generate values that are intended to be unpredictable. Index: head/sys/dev/random/fortuna.c =================================================================== --- head/sys/dev/random/fortuna.c +++ head/sys/dev/random/fortuna.c @@ -451,16 +451,22 @@ RANDOM_RESEED_UNLOCK(); } +#ifdef _KERNEL +static bool block_seeded_status = false; +SYSCTL_BOOL(_kern_random, OID_AUTO, block_seeded_status, CTLFLAG_RWTUN, + &block_seeded_status, 0, + "If non-zero, pretend Fortuna is in an unseeded state. By setting " + "this as a tunable, boot can be tested as if the random device is " + "unavailable."); +#endif + bool random_fortuna_seeded(void) { #ifdef _KERNEL - /* When set, act as if we are not seeded. */ - KFAIL_POINT_CODE(DEBUG_FP, random_fortuna_seeded, { - if (RETURN_VALUE != 0) - fortuna_state.fs_counter = UINT128_ZERO; - }); + if (block_seeded_status) + return (false); #endif return (!uint128_is_zero(fortuna_state.fs_counter)); Index: head/sys/dev/random/random_harvestq.c =================================================================== --- head/sys/dev/random/random_harvestq.c +++ head/sys/dev/random/random_harvestq.c @@ -421,11 +421,6 @@ if (keyfile != NULL) { data = preload_fetch_addr(keyfile); size = preload_fetch_size(keyfile); - /* skip the first bit of the stash so others like arc4 can also have some. */ - if (size > RANDOM_CACHED_SKIP_START) { - data += RANDOM_CACHED_SKIP_START; - size -= RANDOM_CACHED_SKIP_START; - } /* Trim the size. If the admin has a file with a funny size, we lose some. Tough. */ size -= (size % sizeof(event.he_entropy)); if (data != NULL && size != 0) { Index: head/sys/dev/random/random_infra.c =================================================================== --- head/sys/dev/random/random_infra.c +++ head/sys/dev/random/random_infra.c @@ -57,12 +57,18 @@ #if defined(RANDOM_LOADABLE) +static void +null_read_random(void *dummy __unused, u_int dummy2 __unused) +{ + panic("%s: no random module is loaded", __func__); +} + struct random_readers { int (*read_random_uio)(struct uio *, bool); - u_int (*read_random)(void *, u_int); + void (*read_random)(void *, u_int); } random_reader_context = { (int (*)(struct uio *, bool))nullop, - (u_int (*)(void *, u_int))nullop, + null_read_random, }; struct sx randomdev_config_lock; @@ -76,7 +82,7 @@ SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysinit, NULL); void -random_infra_init(int (*p_random_read_uio)(struct uio *, bool), u_int (*p_random_read)(void *, u_int)) +random_infra_init(int (*p_random_read_uio)(struct uio *, bool), void (*p_random_read)(void *, u_int)) { RANDOM_CONFIG_X_LOCK(); @@ -91,7 +97,7 @@ RANDOM_CONFIG_X_LOCK(); random_reader_context.read_random_uio = (int (*)(struct uio *, bool))nullop; - random_reader_context.read_random = (u_int (*)(void *, u_int))nullop; + random_reader_context.read_random = null_read_random; RANDOM_CONFIG_X_UNLOCK(); } @@ -114,15 +120,13 @@ return (retval); } -u_int +void read_random(void *buf, u_int len) { - u_int retval; RANDOM_CONFIG_S_LOCK(); - retval = random_reader_context.read_random(buf, len); + random_reader_context.read_random(buf, len); RANDOM_CONFIG_S_UNLOCK(); - return (retval); } #endif /* defined(RANDOM_LOADABLE) */ Index: head/sys/dev/random/randomdev.h =================================================================== --- head/sys/dev/random/randomdev.h +++ head/sys/dev/random/randomdev.h @@ -118,7 +118,7 @@ #define RANDOM_CONFIG_S_LOCK(x) sx_slock(&randomdev_config_lock) #define RANDOM_CONFIG_S_UNLOCK(x) sx_sunlock(&randomdev_config_lock) #define RANDOM_CONFIG_DEINIT_LOCK(x) sx_destroy(&randomdev_config_lock) -void random_infra_init(int (*)(struct uio *, bool), u_int (*)(void *, u_int)); +void random_infra_init(int (*)(struct uio *, bool), void (*)(void *, u_int)); void random_infra_uninit(void); #endif Index: head/sys/dev/random/randomdev.c =================================================================== --- head/sys/dev/random/randomdev.c +++ head/sys/dev/random/randomdev.c @@ -63,7 +63,7 @@ #define READ_RANDOM_UIO _read_random_uio #define READ_RANDOM _read_random static int READ_RANDOM_UIO(struct uio *, bool); -static u_int READ_RANDOM(void *, u_int); +static void READ_RANDOM(void *, u_int); #else #define READ_RANDOM_UIO read_random_uio #define READ_RANDOM read_random @@ -124,11 +124,53 @@ return (READ_RANDOM_UIO(uio, (flags & O_NONBLOCK) != 0)); } +/* + * If the random device is not seeded, blocks until it is seeded. + * + * Returns zero when the random device is seeded. + * + * If the 'interruptible' parameter is true, and the device is unseeded, this + * routine may be interrupted. If interrupted, it will return either ERESTART + * or EINTR. + */ +#define SEEDWAIT_INTERRUPTIBLE true +#define SEEDWAIT_UNINTERRUPTIBLE false +static int +randomdev_wait_until_seeded(bool interruptible) +{ + int error, spamcount, slpflags; + + slpflags = interruptible ? PCATCH : 0; + + error = 0; + spamcount = 0; + while (!p_random_alg_context->ra_seeded()) { + /* keep tapping away at the pre-read until we seed/unblock. */ + p_random_alg_context->ra_pre_read(); + /* Only bother the console every 10 seconds or so */ + if (spamcount == 0) + printf("random: %s unblock wait\n", __func__); + spamcount = (spamcount + 1) % 100; + error = tsleep(&random_alg_context, slpflags, "randseed", + hz / 10); + if (error == ERESTART || error == EINTR) { + KASSERT(interruptible, + ("unexpected wake of non-interruptible sleep")); + break; + } + /* Squash tsleep timeout condition */ + if (error == EWOULDBLOCK) + error = 0; + KASSERT(error == 0, ("unexpected tsleep error %d", error)); + } + return (error); +} + int READ_RANDOM_UIO(struct uio *uio, bool nonblock) { uint8_t *random_buf; - int error, spamcount; + int error; ssize_t read_len, total_read, c; /* 16 MiB takes about 0.08 s CPU time on my 2017 AMD Zen CPU */ #define SIGCHK_PERIOD (16 * 1024 * 1024) @@ -140,26 +182,13 @@ random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); p_random_alg_context->ra_pre_read(); error = 0; - spamcount = 0; /* (Un)Blocking logic */ - while (!p_random_alg_context->ra_seeded()) { - if (nonblock) { + if (!p_random_alg_context->ra_seeded()) { + if (nonblock) error = EWOULDBLOCK; - break; - } - /* keep tapping away at the pre-read until we seed/unblock. */ - p_random_alg_context->ra_pre_read(); - /* Only bother the console every 10 seconds or so */ - if (spamcount == 0) - printf("random: %s unblock wait\n", __func__); - spamcount = (spamcount + 1)%100; - error = tsleep(&random_alg_context, PCATCH, "randseed", hz/10); - if (error == ERESTART || error == EINTR) - break; - /* Squash tsleep timeout condition */ - if (error == EWOULDBLOCK) - error = 0; - KASSERT(error == 0, ("unexpected tsleep error %d", error)); + else + error = randomdev_wait_until_seeded( + SEEDWAIT_INTERRUPTIBLE); } if (error == 0) { read_rate_increment((uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t)); @@ -210,30 +239,36 @@ * It cannot assumed that random_buf is a multiple of * RANDOM_BLOCKSIZE bytes. */ -u_int +void READ_RANDOM(void *random_buf, u_int len) { - u_int read_len; - uint8_t local_buf[len + RANDOM_BLOCKSIZE]; + u_int read_directly_len; KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__)); p_random_alg_context->ra_pre_read(); - /* (Un)Blocking logic; if not seeded, return nothing. */ - if (p_random_alg_context->ra_seeded()) { - read_rate_increment((len + sizeof(uint32_t))/sizeof(uint32_t)); - if (len > 0) { - /* - * Belt-and-braces. - * Round up the read length to a crypto block size multiple, - * which is what the underlying generator is expecting. - */ - read_len = roundup(len, RANDOM_BLOCKSIZE); - p_random_alg_context->ra_read(local_buf, read_len); - memcpy(random_buf, local_buf, len); - } - } else - len = 0; - return (len); + /* (Un)Blocking logic */ + if (!p_random_alg_context->ra_seeded()) + (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. + */ + read_directly_len = rounddown(len, RANDOM_BLOCKSIZE); + if (read_directly_len > 0) + p_random_alg_context->ra_read(random_buf, read_directly_len); + if (read_directly_len < len) { + uint8_t remainder_buf[RANDOM_BLOCKSIZE]; + + p_random_alg_context->ra_read(remainder_buf, + sizeof(remainder_buf)); + memcpy((char *)random_buf + read_directly_len, remainder_buf, + len - read_directly_len); + + explicit_bzero(remainder_buf, sizeof(remainder_buf)); + } } static __inline void Index: head/sys/kern/kern_mib.c =================================================================== --- head/sys/kern/kern_mib.c +++ head/sys/kern/kern_mib.c @@ -159,15 +159,8 @@ char buf[256]; size_t len; - /*- - * This is one of the very few legitimate uses of read_random(9). - * Use of arc4random(9) is not recommended as that will ignore - * an unsafe (i.e. unseeded) random(4). - * - * If random(4) is not seeded, then this returns 0, so the - * sysctl will return a zero-length buffer. - */ - len = read_random(buf, MIN(req->oldlen, sizeof(buf))); + len = MIN(req->oldlen, sizeof(buf)); + read_random(buf, len); return (SYSCTL_OUT(req, buf, len)); } Index: head/sys/libkern/arc4random.c =================================================================== --- head/sys/libkern/arc4random.c +++ head/sys/libkern/arc4random.c @@ -56,7 +56,6 @@ struct chacha20_s { struct mtx mtx; int numbytes; - int first_time_done; time_t t_reseed; u_int8_t m_buffer[CHACHA20_BUFFER_SIZE]; struct chacha_ctx ctx; @@ -73,35 +72,17 @@ * Mix up the current context. */ static void -chacha20_randomstir(struct chacha20_s* chacha20) +chacha20_randomstir(struct chacha20_s *chacha20) { struct timeval tv_now; - size_t n, size; - u_int8_t key[CHACHA20_KEYBYTES], *data; - caddr_t keyfile; + u_int8_t key[CHACHA20_KEYBYTES]; /* - * This is making the best of what may be an insecure - * Situation. If the loader(8) did not have an entropy - * stash from the previous shutdown to load, then we will - * be improperly seeded. The answer is to make sure there - * is an entropy stash at shutdown time. + * 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. */ - (void)read_random(key, CHACHA20_KEYBYTES); - if (!chacha20->first_time_done) { - keyfile = preload_search_by_type(RANDOM_CACHED_BOOT_ENTROPY_MODULE); - if (keyfile != NULL) { - data = preload_fetch_addr(keyfile); - size = MIN(preload_fetch_size(keyfile), CHACHA20_KEYBYTES); - for (n = 0; n < size; n++) - key[n] ^= data[n]; - explicit_bzero(data, size); - if (bootverbose) - printf("arc4random: read %zu bytes from preloaded cache\n", size); - } else - printf("arc4random: no preloaded entropy cache\n"); - chacha20->first_time_done = 1; - } + read_random(key, CHACHA20_KEYBYTES); getmicrouptime(&tv_now); mtx_lock(&chacha20->mtx); chacha_keysetup(&chacha20->ctx, key, CHACHA20_KEYBYTES*8); @@ -128,7 +109,6 @@ mtx_init(&chacha20->mtx, "chacha20_mtx", NULL, MTX_DEF); chacha20->t_reseed = -1; chacha20->numbytes = 0; - chacha20->first_time_done = 0; explicit_bzero(chacha20->m_buffer, CHACHA20_BUFFER_SIZE); explicit_bzero(&chacha20->ctx, sizeof(chacha20->ctx)); } Index: head/sys/sys/random.h =================================================================== --- head/sys/sys/random.h +++ head/sys/sys/random.h @@ -38,7 +38,7 @@ struct uio; #if defined(DEV_RANDOM) -u_int read_random(void *, u_int); +void read_random(void *, u_int); int read_random_uio(struct uio *, bool); #else static __inline int @@ -46,10 +46,9 @@ { return (0); } -static __inline u_int +static __inline void read_random(void *a __unused, u_int b __unused) { - return (0); } #endif @@ -95,7 +94,6 @@ #define RANDOM_LEGACY_BOOT_ENTROPY_MODULE "/boot/entropy" #define RANDOM_CACHED_BOOT_ENTROPY_MODULE "boot_entropy_cache" -#define RANDOM_CACHED_SKIP_START 256 #if defined(DEV_RANDOM) extern u_int hc_source_mask;