diff --git a/share/man/man4/random.4 b/share/man/man4/random.4 index bd55e048ff40..0805be28c782 100644 --- a/share/man/man4/random.4 +++ b/share/man/man4/random.4 @@ -1,343 +1,238 @@ .\" Copyright (c) 2001-2015 Mark R V Murray. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd August 26, 2018 +.Dd April 15, 2019 .Dt RANDOM 4 .Os .Sh NAME .Nm random .Nd the entropy device .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. -.Pp -It is also possible -to read random bytes -by using the KERN_ARND sysctl. -On the command line -this could be done by -.Pp -.Dl "sysctl -x -B 16 kern.arandom" -.Pp -This sysctl will not return -random bytes unless -the -.Nm -device is seeded. +state, and will block reads until it is seeded for the first time. .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. +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 +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 +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 To see the current settings of the software .Nm device, use the command line: .Pp .Dl "sysctl kern.random" .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 .Pa kern.random.fortuna.minpoolsize sysctl is used to set the seed threshold. A smaller number gives a faster seed, but a less secure one. In practice, values between 64 and 256 are acceptable. .Pp The .Va kern.random.harvest.mask bitmask is used to select the possible entropy sources. A 0 (zero) value means the corresponding source is not considered as an entropy source. Set the bit to 1 (one) if you wish to use that source. The .Va kern.random.harvest.mask_bin and .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 until an "algorithm module" 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, and also must be indirect calls to allow for removal. .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 -.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 +When +.Cd "options RANDOM_ENABLE_ETHER" +is enabled, 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 -.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 +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. -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. diff --git a/share/man/man9/random.9 b/share/man/man9/random.9 index e2875e1798de..2e6189790412 100644 --- a/share/man/man9/random.9 +++ b/share/man/man9/random.9 @@ -1,212 +1,217 @@ .\" .\" Copyright (c) 2015 .\" Mark R V Murray .\" Copyright (c) 2000 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $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 , .Nm srandom .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 -.Fa buffer -is ignored -and zero is returned. -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 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 function behaves identically to .Xr read 2 on .Pa /dev/random . 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. -.Sh RETURN VALUES -The +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). -.Pp +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 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 .Fn arc4rand to generate pseudo-random numbers in the range from 0 to .if t 2\u\s732\s10\d\(mi1. .if n (2**32)\(mi1. .Pp The .Fn read_random function returns the number of bytes placed in .Fa buffer . .Pp .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: .Bl -tag -width Er .It Bq Er EFAULT .Fa uio points to an invalid memory region. .It Bq Er EWOULDBLOCK The random device is unseeded and .Fa nonblock is true. .El .Sh AUTHORS .An Dan Moschuk wrote .Fn arc4random . .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. diff --git a/sys/dev/random/fortuna.c b/sys/dev/random/fortuna.c index e8a407525138..a6cfccaa3a1a 100644 --- a/sys/dev/random/fortuna.c +++ b/sys/dev/random/fortuna.c @@ -1,467 +1,473 @@ /*- * Copyright (c) 2017 W. Dean Freeman * Copyright (c) 2013-2015 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* * This implementation of Fortuna is based on the descriptions found in * ISBN 978-0-470-47424-2 "Cryptography Engineering" by Ferguson, Schneier * and Kohno ("FS&K"). */ #include __FBSDID("$FreeBSD$"); #include #include #ifdef _KERNEL #include #include #include #include #include #include #include #include #include #include #else /* !_KERNEL */ #include #include #include #include #include #include #include "unit_test.h" #endif /* _KERNEL */ #include #include #include #include #ifdef _KERNEL #include #endif #include #include /* Defined in FS&K */ #define RANDOM_FORTUNA_NPOOLS 32 /* The number of accumulation pools */ #define RANDOM_FORTUNA_DEFPOOLSIZE 64 /* The default pool size/length for a (re)seed */ #define RANDOM_FORTUNA_MAX_READ (1 << 20) /* Max bytes in a single read */ /* * The allowable range of RANDOM_FORTUNA_DEFPOOLSIZE. The default value is above. * Making RANDOM_FORTUNA_DEFPOOLSIZE too large will mean a long time between reseeds, * and too small may compromise initial security but get faster reseeds. */ #define RANDOM_FORTUNA_MINPOOLSIZE 16 #define RANDOM_FORTUNA_MAXPOOLSIZE INT_MAX CTASSERT(RANDOM_FORTUNA_MINPOOLSIZE <= RANDOM_FORTUNA_DEFPOOLSIZE); CTASSERT(RANDOM_FORTUNA_DEFPOOLSIZE <= RANDOM_FORTUNA_MAXPOOLSIZE); /* This algorithm (and code) presumes that RANDOM_KEYSIZE is twice as large as RANDOM_BLOCKSIZE */ CTASSERT(RANDOM_BLOCKSIZE == sizeof(uint128_t)); CTASSERT(RANDOM_KEYSIZE == 2*RANDOM_BLOCKSIZE); /* Probes for dtrace(1) */ #ifdef _KERNEL SDT_PROVIDER_DECLARE(random); SDT_PROVIDER_DEFINE(random); SDT_PROBE_DEFINE2(random, fortuna, event_processor, debug, "u_int", "struct fs_pool *"); #endif /* _KERNEL */ /* * This is the beastie that needs protecting. It contains all of the * state that we are excited about. Exactly one is instantiated. */ static struct fortuna_state { struct fs_pool { /* P_i */ u_int fsp_length; /* Only the first one is used by Fortuna */ struct randomdev_hash fsp_hash; } fs_pool[RANDOM_FORTUNA_NPOOLS]; u_int fs_reseedcount; /* ReseedCnt */ uint128_t fs_counter; /* C */ union randomdev_key fs_key; /* K */ u_int fs_minpoolsize; /* Extras */ /* Extras for the OS */ #ifdef _KERNEL /* For use when 'pacing' the reseeds */ sbintime_t fs_lasttime; #endif /* Reseed lock */ mtx_t fs_mtx; } fortuna_state; #ifdef _KERNEL static struct sysctl_ctx_list random_clist; RANDOM_CHECK_UINT(fs_minpoolsize, RANDOM_FORTUNA_MINPOOLSIZE, RANDOM_FORTUNA_MAXPOOLSIZE); #else static uint8_t zero_region[RANDOM_ZERO_BLOCKSIZE]; #endif static void random_fortuna_pre_read(void); static void random_fortuna_read(uint8_t *, u_int); static bool random_fortuna_seeded(void); static void random_fortuna_process_event(struct harvest_event *); static void random_fortuna_init_alg(void *); static void random_fortuna_deinit_alg(void *); static void random_fortuna_reseed_internal(uint32_t *entropy_data, u_int blockcount); struct random_algorithm random_alg_context = { .ra_ident = "Fortuna", .ra_init_alg = random_fortuna_init_alg, .ra_deinit_alg = random_fortuna_deinit_alg, .ra_pre_read = random_fortuna_pre_read, .ra_read = random_fortuna_read, .ra_seeded = random_fortuna_seeded, .ra_event_processor = random_fortuna_process_event, .ra_poolcount = RANDOM_FORTUNA_NPOOLS, }; /* ARGSUSED */ static void random_fortuna_init_alg(void *unused __unused) { int i; #ifdef _KERNEL struct sysctl_oid *random_fortuna_o; #endif RANDOM_RESEED_INIT_LOCK(); /* * Fortuna parameters. Do not adjust these unless you have * have a very good clue about what they do! */ fortuna_state.fs_minpoolsize = RANDOM_FORTUNA_DEFPOOLSIZE; #ifdef _KERNEL fortuna_state.fs_lasttime = 0; random_fortuna_o = SYSCTL_ADD_NODE(&random_clist, SYSCTL_STATIC_CHILDREN(_kern_random), OID_AUTO, "fortuna", CTLFLAG_RW, 0, "Fortuna Parameters"); SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_fortuna_o), OID_AUTO, "minpoolsize", CTLTYPE_UINT | CTLFLAG_RWTUN, &fortuna_state.fs_minpoolsize, RANDOM_FORTUNA_DEFPOOLSIZE, random_check_uint_fs_minpoolsize, "IU", "Minimum pool size necessary to cause a reseed"); KASSERT(fortuna_state.fs_minpoolsize > 0, ("random: Fortuna threshold must be > 0 at startup")); #endif /*- * FS&K - InitializePRNG() * - P_i = \epsilon * - ReseedCNT = 0 */ for (i = 0; i < RANDOM_FORTUNA_NPOOLS; i++) { randomdev_hash_init(&fortuna_state.fs_pool[i].fsp_hash); fortuna_state.fs_pool[i].fsp_length = 0; } fortuna_state.fs_reseedcount = 0; /*- * FS&K - InitializeGenerator() * - C = 0 * - K = 0 */ fortuna_state.fs_counter = UINT128_ZERO; explicit_bzero(&fortuna_state.fs_key, sizeof(fortuna_state.fs_key)); } /* ARGSUSED */ static void random_fortuna_deinit_alg(void *unused __unused) { RANDOM_RESEED_DEINIT_LOCK(); explicit_bzero(&fortuna_state, sizeof(fortuna_state)); #ifdef _KERNEL sysctl_ctx_free(&random_clist); #endif } /*- * FS&K - AddRandomEvent() * Process a single stochastic event off the harvest queue */ static void random_fortuna_process_event(struct harvest_event *event) { u_int pl; RANDOM_RESEED_LOCK(); /*- * FS&K - P_i = P_i| * Accumulate the event into the appropriate pool * where each event carries the destination information. * * The hash_init() and hash_finish() calls are done in * random_fortuna_pre_read(). * * We must be locked against pool state modification which can happen * during accumulation/reseeding and reading/regating. */ pl = event->he_destination % RANDOM_FORTUNA_NPOOLS; /* * We ignore low entropy static/counter fields towards the end of the * he_event structure in order to increase measurable entropy when * conducting SP800-90B entropy analysis measurements of seed material * fed into PRNG. * -- wdf */ KASSERT(event->he_size <= sizeof(event->he_entropy), ("%s: event->he_size: %hhu > sizeof(event->he_entropy): %zu\n", __func__, event->he_size, sizeof(event->he_entropy))); randomdev_hash_iterate(&fortuna_state.fs_pool[pl].fsp_hash, &event->he_somecounter, sizeof(event->he_somecounter)); randomdev_hash_iterate(&fortuna_state.fs_pool[pl].fsp_hash, event->he_entropy, event->he_size); /*- * Don't wrap the length. This is a "saturating" add. * XXX: FIX!!: We don't actually need lengths for anything but fs_pool[0], * but it's been useful debugging to see them all. */ fortuna_state.fs_pool[pl].fsp_length = MIN(RANDOM_FORTUNA_MAXPOOLSIZE, fortuna_state.fs_pool[pl].fsp_length + sizeof(event->he_somecounter) + event->he_size); explicit_bzero(event, sizeof(*event)); RANDOM_RESEED_UNLOCK(); } /*- * FS&K - Reseed() * This introduces new key material into the output generator. * Additionally it increments the output generator's counter * variable C. When C > 0, the output generator is seeded and * will deliver output. * The entropy_data buffer passed is a very specific size; the * product of RANDOM_FORTUNA_NPOOLS and RANDOM_KEYSIZE. */ static void random_fortuna_reseed_internal(uint32_t *entropy_data, u_int blockcount) { struct randomdev_hash context; uint8_t hash[RANDOM_KEYSIZE]; const void *keymaterial; size_t keysz; bool seeded; RANDOM_RESEED_ASSERT_LOCK_OWNED(); seeded = random_fortuna_seeded(); if (seeded) { randomdev_getkey(&fortuna_state.fs_key, &keymaterial, &keysz); KASSERT(keysz == RANDOM_KEYSIZE, ("%s: key size %zu not %u", __func__, keysz, (unsigned)RANDOM_KEYSIZE)); } /*- * FS&K - K = Hd(K|s) where Hd(m) is H(H(0^512|m)) * - C = C + 1 */ randomdev_hash_init(&context); randomdev_hash_iterate(&context, zero_region, RANDOM_ZERO_BLOCKSIZE); if (seeded) randomdev_hash_iterate(&context, keymaterial, keysz); randomdev_hash_iterate(&context, entropy_data, RANDOM_KEYSIZE*blockcount); randomdev_hash_finish(&context, hash); randomdev_hash_init(&context); randomdev_hash_iterate(&context, hash, RANDOM_KEYSIZE); randomdev_hash_finish(&context, hash); randomdev_encrypt_init(&fortuna_state.fs_key, hash); explicit_bzero(hash, sizeof(hash)); /* Unblock the device if this is the first time we are reseeding. */ if (uint128_is_zero(fortuna_state.fs_counter)) randomdev_unblock(); uint128_increment(&fortuna_state.fs_counter); } /*- * FS&K - GenerateBlocks() * Generate a number of complete blocks of random output. */ static __inline void random_fortuna_genblocks(uint8_t *buf, u_int blockcount) { RANDOM_RESEED_ASSERT_LOCK_OWNED(); KASSERT(!uint128_is_zero(fortuna_state.fs_counter), ("FS&K: C != 0")); /* * Fills buf with RANDOM_BLOCKSIZE * blockcount bytes of keystream. * Increments fs_counter as it goes. */ randomdev_keystream(&fortuna_state.fs_key, &fortuna_state.fs_counter, buf, blockcount); } /*- * FS&K - PseudoRandomData() * This generates no more than 2^20 bytes of data, and cleans up its * internal state when finished. It is assumed that a whole number of * blocks are available for writing; any excess generated will be * ignored. */ static __inline void random_fortuna_genrandom(uint8_t *buf, u_int bytecount) { uint8_t temp[RANDOM_BLOCKSIZE * RANDOM_KEYS_PER_BLOCK]; u_int blockcount; RANDOM_RESEED_ASSERT_LOCK_OWNED(); /*- * FS&K - assert(n < 2^20 (== 1 MB) * - r = first-n-bytes(GenerateBlocks(ceil(n/16))) * - K = GenerateBlocks(2) */ KASSERT((bytecount <= RANDOM_FORTUNA_MAX_READ), ("invalid single read request to Fortuna of %d bytes", bytecount)); blockcount = howmany(bytecount, RANDOM_BLOCKSIZE); random_fortuna_genblocks(buf, blockcount); random_fortuna_genblocks(temp, RANDOM_KEYS_PER_BLOCK); randomdev_encrypt_init(&fortuna_state.fs_key, temp); explicit_bzero(temp, sizeof(temp)); } /*- * FS&K - RandomData() (Part 1) * Used to return processed entropy from the PRNG. There is a pre_read * required to be present (but it can be a stub) in order to allow * specific actions at the begin of the read. */ void random_fortuna_pre_read(void) { #ifdef _KERNEL sbintime_t now; #endif struct randomdev_hash context; uint32_t s[RANDOM_FORTUNA_NPOOLS*RANDOM_KEYSIZE_WORDS]; uint8_t temp[RANDOM_KEYSIZE]; u_int i; KASSERT(fortuna_state.fs_minpoolsize > 0, ("random: Fortuna threshold must be > 0")); RANDOM_RESEED_LOCK(); #ifdef _KERNEL /* FS&K - Use 'getsbinuptime()' to prevent reseed-spamming. */ now = getsbinuptime(); #endif 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) #endif ) { RANDOM_RESEED_UNLOCK(); return; } #ifdef _KERNEL /* * When set, pretend we do not have enough entropy to reseed yet. */ KFAIL_POINT_CODE(DEBUG_FP, random_fortuna_pre_read, { if (RETURN_VALUE != 0) { RANDOM_RESEED_UNLOCK(); return; } }); #endif #ifdef _KERNEL fortuna_state.fs_lasttime = now; #endif /* FS&K - ReseedCNT = ReseedCNT + 1 */ fortuna_state.fs_reseedcount++; /* s = \epsilon at start */ for (i = 0; i < RANDOM_FORTUNA_NPOOLS; i++) { /* FS&K - if Divides(ReseedCnt, 2^i) ... */ if ((fortuna_state.fs_reseedcount % (1 << i)) == 0) { /*- * FS&K - temp = (P_i) * - P_i = \epsilon * - s = s|H(temp) */ randomdev_hash_finish(&fortuna_state.fs_pool[i].fsp_hash, temp); randomdev_hash_init(&fortuna_state.fs_pool[i].fsp_hash); fortuna_state.fs_pool[i].fsp_length = 0; randomdev_hash_init(&context); randomdev_hash_iterate(&context, temp, RANDOM_KEYSIZE); randomdev_hash_finish(&context, s + i*RANDOM_KEYSIZE_WORDS); } else break; } #ifdef _KERNEL SDT_PROBE2(random, fortuna, event_processor, debug, fortuna_state.fs_reseedcount, fortuna_state.fs_pool); #endif /* FS&K */ random_fortuna_reseed_internal(s, i); RANDOM_RESEED_UNLOCK(); /* Clean up and secure */ explicit_bzero(s, sizeof(s)); explicit_bzero(temp, sizeof(temp)); } /*- * FS&K - RandomData() (Part 2) * Main read from Fortuna, continued. May be called multiple times after * the random_fortuna_pre_read() above. * The supplied buf MUST be a multiple of RANDOM_BLOCKSIZE in size. * Lots of code presumes this for efficiency, both here and in other * routines. You are NOT allowed to break this! */ void random_fortuna_read(uint8_t *buf, u_int bytecount) { KASSERT((bytecount % RANDOM_BLOCKSIZE) == 0, ("%s(): bytecount (= %d) must be a multiple of %d", __func__, bytecount, RANDOM_BLOCKSIZE )); RANDOM_RESEED_LOCK(); random_fortuna_genrandom(buf, bytecount); 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)); } diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c index c040649c17b2..3cd82571ebc0 100644 --- a/sys/dev/random/random_harvestq.c +++ b/sys/dev/random/random_harvestq.c @@ -1,542 +1,537 @@ /*- * Copyright (c) 2017 Oliver Pinter * Copyright (c) 2017 W. Dean Freeman * Copyright (c) 2000-2015 Mark R V Murray * Copyright (c) 2013 Arthur Mesh * Copyright (c) 2004 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(RANDOM_LOADABLE) #include #include #endif #include #include #include #include #include #include #include static void random_kthread(void); static void random_sources_feed(void); static u_int read_rate; /* List for the dynamic sysctls */ static struct sysctl_ctx_list random_clist; /* * How many events to queue up. We create this many items in * an 'empty' queue, then transfer them to the 'harvest' queue with * supplied junk. When used, they are transferred back to the * 'empty' queue. */ #define RANDOM_RING_MAX 1024 #define RANDOM_ACCUM_MAX 8 /* 1 to let the kernel thread run, 0 to terminate, -1 to mark completion */ volatile int random_kthread_control; /* Allow the sysadmin to select the broad category of * entropy types to harvest. */ __read_frequently u_int hc_source_mask; /* * Put all the harvest queue context stuff in one place. * this make is a bit easier to lock and protect. */ static struct harvest_context { /* The harvest mutex protects all of harvest_context and * the related data. */ struct mtx hc_mtx; /* Round-robin destination cache. */ u_int hc_destination[ENTROPYSOURCE]; /* The context of the kernel thread processing harvested entropy */ struct proc *hc_kthread_proc; /* * Lockless ring buffer holding entropy events * If ring.in == ring.out, * the buffer is empty. * If ring.in != ring.out, * the buffer contains harvested entropy. * If (ring.in + 1) == ring.out (mod RANDOM_RING_MAX), * the buffer is full. * * NOTE: ring.in points to the last added element, * and ring.out points to the last consumed element. * * The ring.in variable needs locking as there are multiple * sources to the ring. Only the sources may change ring.in, * but the consumer may examine it. * * The ring.out variable does not need locking as there is * only one consumer. Only the consumer may change ring.out, * but the sources may examine it. */ struct entropy_ring { struct harvest_event ring[RANDOM_RING_MAX]; volatile u_int in; volatile u_int out; } hc_entropy_ring; struct fast_entropy_accumulator { volatile u_int pos; uint32_t buf[RANDOM_ACCUM_MAX]; } hc_entropy_fast_accumulator; } harvest_context; static struct kproc_desc random_proc_kp = { "rand_harvestq", random_kthread, &harvest_context.hc_kthread_proc, }; /* Pass the given event straight through to Fortuna/Whatever. */ static __inline void random_harvestq_fast_process_event(struct harvest_event *event) { #if defined(RANDOM_LOADABLE) RANDOM_CONFIG_S_LOCK(); if (p_random_alg_context) #endif p_random_alg_context->ra_event_processor(event); #if defined(RANDOM_LOADABLE) RANDOM_CONFIG_S_UNLOCK(); #endif } static void random_kthread(void) { u_int maxloop, ring_out, i; /* * Locking is not needed as this is the only place we modify ring.out, and * we only examine ring.in without changing it. Both of these are volatile, * and this is a unique thread. */ for (random_kthread_control = 1; random_kthread_control;) { /* Deal with events, if any. Restrict the number we do in one go. */ maxloop = RANDOM_RING_MAX; while (harvest_context.hc_entropy_ring.out != harvest_context.hc_entropy_ring.in) { ring_out = (harvest_context.hc_entropy_ring.out + 1)%RANDOM_RING_MAX; random_harvestq_fast_process_event(harvest_context.hc_entropy_ring.ring + ring_out); harvest_context.hc_entropy_ring.out = ring_out; if (!--maxloop) break; } random_sources_feed(); /* XXX: FIX!! Increase the high-performance data rate? Need some measurements first. */ for (i = 0; i < RANDOM_ACCUM_MAX; i++) { if (harvest_context.hc_entropy_fast_accumulator.buf[i]) { random_harvest_direct(harvest_context.hc_entropy_fast_accumulator.buf + i, sizeof(harvest_context.hc_entropy_fast_accumulator.buf[0]), RANDOM_UMA); harvest_context.hc_entropy_fast_accumulator.buf[i] = 0; } } /* XXX: FIX!! This is a *great* place to pass hardware/live entropy to random(9) */ tsleep_sbt(&harvest_context.hc_kthread_proc, 0, "-", SBT_1S/10, 0, C_PREL(1)); } random_kthread_control = -1; wakeup(&harvest_context.hc_kthread_proc); kproc_exit(0); /* NOTREACHED */ } /* This happens well after SI_SUB_RANDOM */ SYSINIT(random_device_h_proc, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, kproc_start, &random_proc_kp); /* * Run through all fast sources reading entropy for the given * number of rounds, which should be a multiple of the number * of entropy accumulation pools in use; it is 32 for Fortuna. */ static void random_sources_feed(void) { uint32_t entropy[HARVESTSIZE]; struct random_sources *rrs; u_int i, n, local_read_rate; /* * Step over all of live entropy sources, and feed their output * to the system-wide RNG. */ #if defined(RANDOM_LOADABLE) RANDOM_CONFIG_S_LOCK(); if (p_random_alg_context) { /* It's an indenting error. Yeah, Yeah. */ #endif local_read_rate = atomic_readandclear_32(&read_rate); /* Perform at least one read per round */ local_read_rate = MAX(local_read_rate, 1); /* But not exceeding RANDOM_KEYSIZE_WORDS */ local_read_rate = MIN(local_read_rate, RANDOM_KEYSIZE_WORDS); LIST_FOREACH(rrs, &source_list, rrs_entries) { for (i = 0; i < p_random_alg_context->ra_poolcount*local_read_rate; i++) { n = rrs->rrs_source->rs_read(entropy, sizeof(entropy)); KASSERT((n <= sizeof(entropy)), ("%s: rs_read returned too much data (%u > %zu)", __func__, n, sizeof(entropy))); /* It would appear that in some circumstances (e.g. virtualisation), * the underlying hardware entropy source might not always return * random numbers. Accept this but make a noise. If too much happens, * can that source be trusted? */ if (n == 0) { printf("%s: rs_read for hardware device '%s' returned no entropy.\n", __func__, rrs->rrs_source->rs_ident); continue; } random_harvest_direct(entropy, n, rrs->rrs_source->rs_source); } } explicit_bzero(entropy, sizeof(entropy)); #if defined(RANDOM_LOADABLE) } RANDOM_CONFIG_S_UNLOCK(); #endif } void read_rate_increment(u_int chunk) { atomic_add_32(&read_rate, chunk); } /* ARGSUSED */ static int random_check_uint_harvestmask(SYSCTL_HANDLER_ARGS) { int error; u_int value, orig_value; orig_value = value = hc_source_mask; error = sysctl_handle_int(oidp, &value, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (flsl(value) > ENTROPYSOURCE) return (EINVAL); /* * Disallow userspace modification of pure entropy sources. */ hc_source_mask = (value & ~RANDOM_HARVEST_PURE_MASK) | (orig_value & RANDOM_HARVEST_PURE_MASK); return (0); } /* ARGSUSED */ static int random_print_harvestmask(SYSCTL_HANDLER_ARGS) { struct sbuf sbuf; int error, i; error = sysctl_wire_old_buffer(req, 0); if (error == 0) { sbuf_new_for_sysctl(&sbuf, NULL, 128, req); for (i = ENTROPYSOURCE - 1; i >= 0; i--) sbuf_cat(&sbuf, (hc_source_mask & (1 << i)) ? "1" : "0"); error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); } return (error); } static const char *random_source_descr[ENTROPYSOURCE] = { [RANDOM_CACHED] = "CACHED", [RANDOM_ATTACH] = "ATTACH", [RANDOM_KEYBOARD] = "KEYBOARD", [RANDOM_MOUSE] = "MOUSE", [RANDOM_NET_TUN] = "NET_TUN", [RANDOM_NET_ETHER] = "NET_ETHER", [RANDOM_NET_NG] = "NET_NG", [RANDOM_INTERRUPT] = "INTERRUPT", [RANDOM_SWI] = "SWI", [RANDOM_FS_ATIME] = "FS_ATIME", [RANDOM_UMA] = "UMA", /* ENVIRONMENTAL_END */ [RANDOM_PURE_OCTEON] = "PURE_OCTEON", /* PURE_START */ [RANDOM_PURE_SAFE] = "PURE_SAFE", [RANDOM_PURE_GLXSB] = "PURE_GLXSB", [RANDOM_PURE_UBSEC] = "PURE_UBSEC", [RANDOM_PURE_HIFN] = "PURE_HIFN", [RANDOM_PURE_RDRAND] = "PURE_RDRAND", [RANDOM_PURE_NEHEMIAH] = "PURE_NEHEMIAH", [RANDOM_PURE_RNDTEST] = "PURE_RNDTEST", [RANDOM_PURE_VIRTIO] = "PURE_VIRTIO", [RANDOM_PURE_BROADCOM] = "PURE_BROADCOM", [RANDOM_PURE_CCP] = "PURE_CCP", [RANDOM_PURE_DARN] = "PURE_DARN", [RANDOM_PURE_TPM] = "PURE_TPM", /* "ENTROPYSOURCE" */ }; /* ARGSUSED */ static int random_print_harvestmask_symbolic(SYSCTL_HANDLER_ARGS) { struct sbuf sbuf; int error, i; bool first; first = true; error = sysctl_wire_old_buffer(req, 0); if (error == 0) { sbuf_new_for_sysctl(&sbuf, NULL, 128, req); for (i = ENTROPYSOURCE - 1; i >= 0; i--) { if (i >= RANDOM_PURE_START && (hc_source_mask & (1 << i)) == 0) continue; if (!first) sbuf_cat(&sbuf, ","); sbuf_cat(&sbuf, !(hc_source_mask & (1 << i)) ? "[" : ""); sbuf_cat(&sbuf, random_source_descr[i]); sbuf_cat(&sbuf, !(hc_source_mask & (1 << i)) ? "]" : ""); first = false; } error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); } return (error); } /* ARGSUSED */ static void random_harvestq_init(void *unused __unused) { struct sysctl_oid *random_sys_o; random_sys_o = SYSCTL_ADD_NODE(&random_clist, SYSCTL_STATIC_CHILDREN(_kern_random), OID_AUTO, "harvest", CTLFLAG_RW, 0, "Entropy Device Parameters"); hc_source_mask = RANDOM_HARVEST_EVERYTHING_MASK; SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_o), OID_AUTO, "mask", CTLTYPE_UINT | CTLFLAG_RW, NULL, 0, random_check_uint_harvestmask, "IU", "Entropy harvesting mask"); SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_o), OID_AUTO, "mask_bin", CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, random_print_harvestmask, "A", "Entropy harvesting mask (printable)"); SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_o), OID_AUTO, "mask_symbolic", CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, random_print_harvestmask_symbolic, "A", "Entropy harvesting mask (symbolic)"); RANDOM_HARVEST_INIT_LOCK(); harvest_context.hc_entropy_ring.in = harvest_context.hc_entropy_ring.out = 0; } SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_init, NULL); /* * This is used to prime the RNG by grabbing any early random stuff * known to the kernel, and inserting it directly into the hashing * module, currently Fortuna. */ /* ARGSUSED */ static void random_harvestq_prime(void *unused __unused) { struct harvest_event event; size_t count, size, i; uint8_t *keyfile, *data; /* * Get entropy that may have been preloaded by loader(8) * and use it to pre-charge the entropy harvest queue. */ keyfile = preload_search_by_type(RANDOM_CACHED_BOOT_ENTROPY_MODULE); #ifndef NO_BACKWARD_COMPATIBILITY if (keyfile == NULL) keyfile = preload_search_by_type(RANDOM_LEGACY_BOOT_ENTROPY_MODULE); #endif 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) { for (i = 0; i < size; i += sizeof(event.he_entropy)) { count = sizeof(event.he_entropy); event.he_somecounter = (uint32_t)get_cyclecount(); event.he_size = count; event.he_source = RANDOM_CACHED; event.he_destination = harvest_context.hc_destination[RANDOM_CACHED]++; memcpy(event.he_entropy, data + i, sizeof(event.he_entropy)); random_harvestq_fast_process_event(&event); explicit_bzero(&event, sizeof(event)); } explicit_bzero(data, size); if (bootverbose) printf("random: read %zu bytes from preloaded cache\n", size); } else if (bootverbose) printf("random: no preloaded entropy cache\n"); } } SYSINIT(random_device_prime, SI_SUB_RANDOM, SI_ORDER_FOURTH, random_harvestq_prime, NULL); /* ARGSUSED */ static void random_harvestq_deinit(void *unused __unused) { /* Command the hash/reseed thread to end and wait for it to finish */ random_kthread_control = 0; while (random_kthread_control >= 0) tsleep(&harvest_context.hc_kthread_proc, 0, "harvqterm", hz/5); sysctl_ctx_free(&random_clist); } SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_deinit, NULL); /*- * Entropy harvesting queue routine. * * This is supposed to be fast; do not do anything slow in here! * It is also illegal (and morally reprehensible) to insert any * high-rate data here. "High-rate" is defined as a data source * that will usually cause lots of failures of the "Lockless read" * check a few lines below. This includes the "always-on" sources * like the Intel "rdrand" or the VIA Nehamiah "xstore" sources. */ /* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle * counters are built in, but on older hardware it will do a real time clock * read which can be quite expensive. */ void random_harvest_queue_(const void *entropy, u_int size, enum random_entropy_source origin) { struct harvest_event *event; u_int ring_in; KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin)); RANDOM_HARVEST_LOCK(); ring_in = (harvest_context.hc_entropy_ring.in + 1)%RANDOM_RING_MAX; if (ring_in != harvest_context.hc_entropy_ring.out) { /* The ring is not full */ event = harvest_context.hc_entropy_ring.ring + ring_in; event->he_somecounter = (uint32_t)get_cyclecount(); event->he_source = origin; event->he_destination = harvest_context.hc_destination[origin]++; if (size <= sizeof(event->he_entropy)) { event->he_size = size; memcpy(event->he_entropy, entropy, size); } else { /* Big event, so squash it */ event->he_size = sizeof(event->he_entropy[0]); event->he_entropy[0] = jenkins_hash(entropy, size, (uint32_t)(uintptr_t)event); } harvest_context.hc_entropy_ring.in = ring_in; } RANDOM_HARVEST_UNLOCK(); } /*- * Entropy harvesting fast routine. * * This is supposed to be very fast; do not do anything slow in here! * This is the right place for high-rate harvested data. */ void random_harvest_fast_(const void *entropy, u_int size) { u_int pos; pos = harvest_context.hc_entropy_fast_accumulator.pos; harvest_context.hc_entropy_fast_accumulator.buf[pos] ^= jenkins_hash(entropy, size, (uint32_t)get_cyclecount()); harvest_context.hc_entropy_fast_accumulator.pos = (pos + 1)%RANDOM_ACCUM_MAX; } /*- * Entropy harvesting direct routine. * * This is not supposed to be fast, but will only be used during * (e.g.) booting when initial entropy is being gathered. */ void random_harvest_direct_(const void *entropy, u_int size, enum random_entropy_source origin) { struct harvest_event event; KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin)); size = MIN(size, sizeof(event.he_entropy)); event.he_somecounter = (uint32_t)get_cyclecount(); event.he_size = size; event.he_source = origin; event.he_destination = harvest_context.hc_destination[origin]++; memcpy(event.he_entropy, entropy, size); random_harvestq_fast_process_event(&event); explicit_bzero(&event, sizeof(event)); } void random_harvest_register_source(enum random_entropy_source source) { hc_source_mask |= (1 << source); } void random_harvest_deregister_source(enum random_entropy_source source) { hc_source_mask &= ~(1 << source); } MODULE_VERSION(random_harvestq, 1); diff --git a/sys/dev/random/random_infra.c b/sys/dev/random/random_infra.c index d31b84b24582..324c40dcecd4 100644 --- a/sys/dev/random/random_infra.c +++ b/sys/dev/random/random_infra.c @@ -1,128 +1,132 @@ /*- * Copyright (c) 2015 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #if defined(RANDOM_LOADABLE) #include #include #endif #include /* Set up the sysctl root node for the entropy device */ SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator"); MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list); #if defined(RANDOM_LOADABLE) struct random_algorithm *p_random_alg_context = NULL; #else /* !defined(RANDOM_LOADABLE) */ struct random_algorithm *p_random_alg_context = &random_alg_context; #endif /* defined(RANDOM_LOADABLE) */ #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; static void random_infra_sysinit(void *dummy __unused) { RANDOM_CONFIG_INIT_LOCK(); } 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(); random_reader_context.read_random_uio = p_random_read_uio; random_reader_context.read_random = p_random_read; RANDOM_CONFIG_X_UNLOCK(); } void random_infra_uninit(void) { 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(); } static void random_infra_sysuninit(void *dummy __unused) { RANDOM_CONFIG_DEINIT_LOCK(); } SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysuninit, NULL); int read_random_uio(struct uio *uio, bool nonblock) { int retval; RANDOM_CONFIG_S_LOCK(); retval = random_reader_context.read_random_uio(uio, nonblock); RANDOM_CONFIG_S_UNLOCK(); 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) */ diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index 94bd2f1a4147..19a73b28151a 100644 --- a/sys/dev/random/randomdev.c +++ b/sys/dev/random/randomdev.c @@ -1,429 +1,464 @@ /*- * Copyright (c) 2017 Oliver Pinter * Copyright (c) 2000-2015 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define RANDOM_UNIT 0 #if defined(RANDOM_LOADABLE) #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 #endif static d_read_t randomdev_read; static d_write_t randomdev_write; static d_poll_t randomdev_poll; static d_ioctl_t randomdev_ioctl; static struct cdevsw random_cdevsw = { .d_name = "random", .d_version = D_VERSION, .d_read = randomdev_read, .d_write = randomdev_write, .d_poll = randomdev_poll, .d_ioctl = randomdev_ioctl, }; /* For use with make_dev(9)/destroy_dev(9). */ static struct cdev *random_dev; static void random_alg_context_ra_init_alg(void *data) { p_random_alg_context = &random_alg_context; p_random_alg_context->ra_init_alg(data); #if defined(RANDOM_LOADABLE) random_infra_init(READ_RANDOM_UIO, READ_RANDOM); #endif } static void random_alg_context_ra_deinit_alg(void *data) { #if defined(RANDOM_LOADABLE) random_infra_uninit(); #endif p_random_alg_context->ra_deinit_alg(data); p_random_alg_context = NULL; } SYSINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_init_alg, NULL); SYSUNINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_deinit_alg, NULL); static struct selinfo rsel; /* * This is the read uio(9) interface for random(4). */ /* ARGSUSED */ static int randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags) { 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) const size_t sigchk_period = SIGCHK_PERIOD; CTASSERT(SIGCHK_PERIOD % PAGE_SIZE == 0); #undef SIGCHK_PERIOD 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)); total_read = 0; while (uio->uio_resid && !error) { read_len = uio->uio_resid; /* * Belt-and-braces. * Round up the read length to a crypto block size multiple, * which is what the underlying generator is expecting. * See the random_buf size requirements in the Fortuna code. */ read_len = roundup(read_len, RANDOM_BLOCKSIZE); /* Work in chunks page-sized or less */ read_len = MIN(read_len, PAGE_SIZE); p_random_alg_context->ra_read(random_buf, read_len); c = MIN(uio->uio_resid, read_len); /* * uiomove() may yield the CPU before each 'c' bytes * (up to PAGE_SIZE) are copied out. */ error = uiomove(random_buf, c, uio); total_read += c; /* * Poll for signals every few MBs to avoid very long * uninterruptible syscalls. */ if (error == 0 && uio->uio_resid != 0 && total_read % sigchk_period == 0) { error = tsleep_sbt(&random_alg_context, PCATCH, "randrd", SBT_1NS, 0, C_HARDCLOCK); /* Squash tsleep timeout condition */ if (error == EWOULDBLOCK) error = 0; } } if (error == ERESTART || error == EINTR) error = 0; } free(random_buf, M_ENTROPY); return (error); } /*- * Kernel API version of read_random(). * This is similar to random_alg_read(), * except it doesn't interface with uio(9). * 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 randomdev_accumulate(uint8_t *buf, u_int count) { static u_int destination = 0; static struct harvest_event event; static struct randomdev_hash hash; static uint32_t entropy_data[RANDOM_KEYSIZE_WORDS]; uint32_t timestamp; int i; /* Extra timing here is helpful to scrape scheduler jitter entropy */ randomdev_hash_init(&hash); timestamp = (uint32_t)get_cyclecount(); randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); randomdev_hash_iterate(&hash, buf, count); timestamp = (uint32_t)get_cyclecount(); randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); randomdev_hash_finish(&hash, entropy_data); explicit_bzero(&hash, sizeof(hash)); for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) { event.he_somecounter = (uint32_t)get_cyclecount(); event.he_size = sizeof(event.he_entropy); event.he_source = RANDOM_CACHED; event.he_destination = destination++; /* Harmless cheating */ memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy)); p_random_alg_context->ra_event_processor(&event); } explicit_bzero(entropy_data, sizeof(entropy_data)); } /* ARGSUSED */ static int randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused) { uint8_t *random_buf; int c, error = 0; ssize_t nbytes; random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); nbytes = uio->uio_resid; while (uio->uio_resid > 0 && error == 0) { c = MIN(uio->uio_resid, PAGE_SIZE); error = uiomove(random_buf, c, uio); if (error) break; randomdev_accumulate(random_buf, c); tsleep(&random_alg_context, 0, "randwr", hz/10); } if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR)) /* Partial write, not error. */ error = 0; free(random_buf, M_ENTROPY); return (error); } /* ARGSUSED */ static int randomdev_poll(struct cdev *dev __unused, int events, struct thread *td __unused) { if (events & (POLLIN | POLLRDNORM)) { if (p_random_alg_context->ra_seeded()) events &= (POLLIN | POLLRDNORM); else selrecord(td, &rsel); } return (events); } /* This will be called by the entropy processor when it seeds itself and becomes secure */ void randomdev_unblock(void) { selwakeuppri(&rsel, PUSER); wakeup(&random_alg_context); printf("random: unblocking device.\n"); /* Do random(9) a favour while we are about it. */ (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE); } /* ARGSUSED */ static int randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, int flags __unused, struct thread *td __unused) { int error = 0; switch (cmd) { /* Really handled in upper layer */ case FIOASYNC: case FIONBIO: break; default: error = ENOTTY; } return (error); } void random_source_register(struct random_source *rsource) { struct random_sources *rrs; KASSERT(rsource != NULL, ("invalid input to %s", __func__)); rrs = malloc(sizeof(*rrs), M_ENTROPY, M_WAITOK); rrs->rrs_source = rsource; random_harvest_register_source(rsource->rs_source); printf("random: registering fast source %s\n", rsource->rs_ident); LIST_INSERT_HEAD(&source_list, rrs, rrs_entries); } void random_source_deregister(struct random_source *rsource) { struct random_sources *rrs = NULL; KASSERT(rsource != NULL, ("invalid input to %s", __func__)); random_harvest_deregister_source(rsource->rs_source); LIST_FOREACH(rrs, &source_list, rrs_entries) if (rrs->rrs_source == rsource) { LIST_REMOVE(rrs, rrs_entries); break; } if (rrs != NULL) free(rrs, M_ENTROPY); } static int random_source_handler(SYSCTL_HANDLER_ARGS) { struct random_sources *rrs; struct sbuf sbuf; int error, count; sbuf_new_for_sysctl(&sbuf, NULL, 64, req); count = 0; LIST_FOREACH(rrs, &source_list, rrs_entries) { sbuf_cat(&sbuf, (count++ ? ",'" : "'")); sbuf_cat(&sbuf, rrs->rrs_source->rs_ident); sbuf_cat(&sbuf, "'"); } error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); return (error); } SYSCTL_PROC(_kern_random, OID_AUTO, random_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, random_source_handler, "A", "List of active fast entropy sources."); /* ARGSUSED */ static int randomdev_modevent(module_t mod __unused, int type, void *data __unused) { int error = 0; switch (type) { case MOD_LOAD: printf("random: entropy device external interface\n"); random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw, RANDOM_UNIT, NULL, UID_ROOT, GID_WHEEL, 0644, "random"); make_dev_alias(random_dev, "urandom"); /* compatibility */ break; case MOD_UNLOAD: destroy_dev(random_dev); break; case MOD_SHUTDOWN: break; default: error = EOPNOTSUPP; break; } return (error); } static moduledata_t randomdev_mod = { "random_device", randomdev_modevent, 0 }; DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); MODULE_VERSION(random_device, 1); MODULE_DEPEND(random_device, crypto, 1, 1, 1); MODULE_DEPEND(random_device, random_harvestq, 1, 1, 1); diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h index 0f3b359d1f1f..41300f237aaf 100644 --- a/sys/dev/random/randomdev.h +++ b/sys/dev/random/randomdev.h @@ -1,129 +1,129 @@ /*- * Copyright (c) 2000-2015 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED #define SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED #ifdef _KERNEL /* This header contains only those definitions that are global * and non algorithm-specific for the entropy processor */ #ifdef SYSCTL_DECL /* from sysctl.h */ SYSCTL_DECL(_kern_random); #define RANDOM_CHECK_UINT(name, min, max) \ static int \ random_check_uint_##name(SYSCTL_HANDLER_ARGS) \ { \ if (oidp->oid_arg1 != NULL) { \ if (*(u_int *)(oidp->oid_arg1) <= (min)) \ *(u_int *)(oidp->oid_arg1) = (min); \ else if (*(u_int *)(oidp->oid_arg1) > (max)) \ *(u_int *)(oidp->oid_arg1) = (max); \ } \ return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \ req)); \ } #endif /* SYSCTL_DECL */ MALLOC_DECLARE(M_ENTROPY); #endif /* _KERNEL */ struct harvest_event; typedef void random_alg_init_t(void *); typedef void random_alg_deinit_t(void *); typedef void random_alg_pre_read_t(void); typedef void random_alg_read_t(uint8_t *, u_int); typedef bool random_alg_seeded_t(void); typedef void random_alg_reseed_t(void); typedef void random_alg_eventprocessor_t(struct harvest_event *); typedef u_int random_source_read_t(void *, u_int); /* * Random Algorithm is a processor of randomness for the kernel * and for userland. */ struct random_algorithm { const char *ra_ident; u_int ra_poolcount; void (*ra_init_alg)(void *); void (*ra_deinit_alg)(void *); random_alg_pre_read_t *ra_pre_read; random_alg_read_t *ra_read; random_alg_seeded_t *ra_seeded; random_alg_eventprocessor_t *ra_event_processor; }; extern struct random_algorithm random_alg_context, *p_random_alg_context; #ifdef _KERNEL /* * Random Source is a source of entropy that can provide * specified or approximate amount of entropy immediately * upon request. */ struct random_source { const char *rs_ident; enum random_entropy_source rs_source; random_source_read_t *rs_read; }; struct random_sources { LIST_ENTRY(random_sources) rrs_entries; struct random_source *rrs_source; }; LIST_HEAD(sources_head, random_sources); extern struct sources_head source_list; void random_source_register(struct random_source *); void random_source_deregister(struct random_source *); #if defined(RANDOM_LOADABLE) extern struct sx randomdev_config_lock; #define RANDOM_CONFIG_INIT_LOCK(x) sx_init(&randomdev_config_lock, "configuration change lock") #define RANDOM_CONFIG_X_LOCK(x) sx_xlock(&randomdev_config_lock) #define RANDOM_CONFIG_X_UNLOCK(x) sx_xunlock(&randomdev_config_lock) #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 #endif /* _KERNEL */ void randomdev_unblock(void); #endif /* SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED */ diff --git a/sys/kern/kern_mib.c b/sys/kern/kern_mib.c index ed44645246d4..fd46419ba8a0 100644 --- a/sys/kern/kern_mib.c +++ b/sys/kern/kern_mib.c @@ -1,675 +1,668 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Mike Karels at Berkeley Software Design, Inc. * * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD * project, to make these variables more userfriendly. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 */ #include __FBSDID("$FreeBSD$"); #include "opt_posix.h" #include "opt_config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SYSCTL_ROOT_NODE(0, sysctl, CTLFLAG_RW, 0, "Sysctl internal magic"); SYSCTL_ROOT_NODE(CTL_KERN, kern, CTLFLAG_RW|CTLFLAG_CAPRD, 0, "High kernel, proc, limits &c"); SYSCTL_ROOT_NODE(CTL_VM, vm, CTLFLAG_RW, 0, "Virtual memory"); SYSCTL_ROOT_NODE(CTL_VFS, vfs, CTLFLAG_RW, 0, "File system"); SYSCTL_ROOT_NODE(CTL_NET, net, CTLFLAG_RW, 0, "Network, (see socket.h)"); SYSCTL_ROOT_NODE(CTL_DEBUG, debug, CTLFLAG_RW, 0, "Debugging"); SYSCTL_NODE(_debug, OID_AUTO, sizeof, CTLFLAG_RW, 0, "Sizeof various things"); SYSCTL_ROOT_NODE(CTL_HW, hw, CTLFLAG_RW, 0, "hardware"); SYSCTL_ROOT_NODE(CTL_MACHDEP, machdep, CTLFLAG_RW, 0, "machine dependent"); SYSCTL_NODE(_machdep, OID_AUTO, mitigations, CTLFLAG_RW, 0, "Machine dependent platform mitigations."); SYSCTL_ROOT_NODE(CTL_USER, user, CTLFLAG_RW, 0, "user-level"); SYSCTL_ROOT_NODE(CTL_P1003_1B, p1003_1b, CTLFLAG_RW, 0, "p1003_1b, (see p1003_1b.h)"); SYSCTL_ROOT_NODE(OID_AUTO, compat, CTLFLAG_RW, 0, "Compatibility code"); SYSCTL_ROOT_NODE(OID_AUTO, security, CTLFLAG_RW, 0, "Security"); #ifdef REGRESSION SYSCTL_ROOT_NODE(OID_AUTO, regression, CTLFLAG_RW, 0, "Regression test MIB"); #endif SYSCTL_STRING(_kern, OID_AUTO, ident, CTLFLAG_RD|CTLFLAG_MPSAFE, kern_ident, 0, "Kernel identifier"); SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD|CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, BSD, "Operating system revision"); SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD|CTLFLAG_MPSAFE, version, 0, "Kernel version"); SYSCTL_STRING(_kern, OID_AUTO, compiler_version, CTLFLAG_RD|CTLFLAG_MPSAFE, compiler_version, 0, "Version of compiler used to compile kernel"); SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD|CTLFLAG_MPSAFE| CTLFLAG_CAPRD, ostype, 0, "Operating system type"); SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &maxproc, 0, "Maximum number of processes"); SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, CTLFLAG_RW, &maxprocperuid, 0, "Maximum processes allowed per userid"); SYSCTL_INT(_kern, OID_AUTO, maxusers, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &maxusers, 0, "Hint for kernel tuning"); SYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD|CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, ARG_MAX, "Maximum bytes of argument to execve(2)"); SYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD|CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, _POSIX_VERSION, "Version of POSIX attempting to comply to"); SYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RDTUN | CTLFLAG_NOFETCH | CTLFLAG_CAPRD, &ngroups_max, 0, "Maximum number of supplemental groups a user can belong to"); SYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD|CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, 1, "Whether job control is available"); #ifdef _POSIX_SAVED_IDS SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD|CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, 1, "Whether saved set-group/user ID is available"); #else SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD|CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, 0, "Whether saved set-group/user ID is available"); #endif char kernelname[MAXPATHLEN] = PATH_KERNEL; /* XXX bloat */ SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW | CTLFLAG_MPSAFE, kernelname, sizeof kernelname, "Name of kernel file booted"); SYSCTL_INT(_kern, KERN_MAXPHYS, maxphys, CTLFLAG_RD | CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, MAXPHYS, "Maximum block I/O access size"); SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD|CTLFLAG_CAPRD, &mp_ncpus, 0, "Number of active CPUs"); SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD|CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, BYTE_ORDER, "System byte order"); SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD|CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, PAGE_SIZE, "System memory page size"); static int sysctl_kern_arnd(SYSCTL_HANDLER_ARGS) { 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)); } SYSCTL_PROC(_kern, KERN_ARND, arandom, CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE | CTLFLAG_CAPRD, NULL, 0, sysctl_kern_arnd, "", "arc4rand"); static int sysctl_hw_physmem(SYSCTL_HANDLER_ARGS) { u_long val, p; p = SIZE_T_MAX >> PAGE_SHIFT; if (physmem < p) p = physmem; val = ctob(p); return (sysctl_handle_long(oidp, &val, 0, req)); } SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_ULONG | CTLFLAG_RD, 0, 0, sysctl_hw_physmem, "LU", "Amount of physical memory (in bytes)"); static int sysctl_hw_realmem(SYSCTL_HANDLER_ARGS) { u_long val, p; p = SIZE_T_MAX >> PAGE_SHIFT; if (realmem < p) p = realmem; val = ctob(p); return (sysctl_handle_long(oidp, &val, 0, req)); } SYSCTL_PROC(_hw, HW_REALMEM, realmem, CTLTYPE_ULONG | CTLFLAG_RD, 0, 0, sysctl_hw_realmem, "LU", "Amount of memory (in bytes) reported by the firmware"); static int sysctl_hw_usermem(SYSCTL_HANDLER_ARGS) { u_long val, p, p1; p1 = physmem - vm_wire_count(); p = SIZE_T_MAX >> PAGE_SHIFT; if (p1 < p) p = p1; val = ctob(p); return (sysctl_handle_long(oidp, &val, 0, req)); } SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_ULONG | CTLFLAG_RD, 0, 0, sysctl_hw_usermem, "LU", "Amount of memory (in bytes) which is not wired"); SYSCTL_LONG(_hw, OID_AUTO, availpages, CTLFLAG_RD, &physmem, 0, "Amount of physical memory (in pages)"); u_long pagesizes[MAXPAGESIZES] = { PAGE_SIZE }; static int sysctl_hw_pagesizes(SYSCTL_HANDLER_ARGS) { int error; size_t len; #ifdef SCTL_MASK32 int i; uint32_t pagesizes32[MAXPAGESIZES]; if (req->flags & SCTL_MASK32) { /* * Recreate the "pagesizes" array with 32-bit elements. * Truncate any page size greater than UINT32_MAX to zero, * which assumes that page sizes are powers of two. */ for (i = 0; i < MAXPAGESIZES; i++) pagesizes32[i] = (uint32_t)pagesizes[i]; len = sizeof(pagesizes32); if (len > req->oldlen) len = req->oldlen; error = SYSCTL_OUT(req, pagesizes32, len); } else #endif { len = sizeof(pagesizes); if (len > req->oldlen) len = req->oldlen; error = SYSCTL_OUT(req, pagesizes, len); } return (error); } SYSCTL_PROC(_hw, OID_AUTO, pagesizes, CTLTYPE_ULONG | CTLFLAG_RD, NULL, 0, sysctl_hw_pagesizes, "LU", "Supported page sizes"); #ifdef SCTL_MASK32 int adaptive_machine_arch = 1; SYSCTL_INT(_debug, OID_AUTO, adaptive_machine_arch, CTLFLAG_RW, &adaptive_machine_arch, 1, "Adapt reported machine architecture to the ABI of the binary"); #endif static int sysctl_hw_machine_arch(SYSCTL_HANDLER_ARGS) { int error; static const char machine_arch[] = MACHINE_ARCH; #ifdef SCTL_MASK32 static const char machine_arch32[] = MACHINE_ARCH32; if ((req->flags & SCTL_MASK32) != 0 && adaptive_machine_arch) error = SYSCTL_OUT(req, machine_arch32, sizeof(machine_arch32)); else #endif error = SYSCTL_OUT(req, machine_arch, sizeof(machine_arch)); return (error); } SYSCTL_PROC(_hw, HW_MACHINE_ARCH, machine_arch, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, sysctl_hw_machine_arch, "A", "System architecture"); SYSCTL_STRING(_kern, OID_AUTO, supported_archs, CTLFLAG_RD | CTLFLAG_MPSAFE, #ifdef COMPAT_FREEBSD32 MACHINE_ARCH " " MACHINE_ARCH32, 0, "Supported architectures for binaries"); #else MACHINE_ARCH, 0, "Supported architectures for binaries"); #endif static int sysctl_hostname(SYSCTL_HANDLER_ARGS) { struct prison *pr, *cpr; size_t pr_offset; char tmpname[MAXHOSTNAMELEN]; int descend, error, len; /* * This function can set: hostname domainname hostuuid. * Keep that in mind when comments say "hostname". */ pr_offset = (size_t)arg1; len = arg2; KASSERT(len <= sizeof(tmpname), ("length %d too long for %s", len, __func__)); pr = req->td->td_ucred->cr_prison; if (!(pr->pr_allow & PR_ALLOW_SET_HOSTNAME) && req->newptr) return (EPERM); /* * Make a local copy of hostname to get/set so we don't have to hold * the jail mutex during the sysctl copyin/copyout activities. */ mtx_lock(&pr->pr_mtx); bcopy((char *)pr + pr_offset, tmpname, len); mtx_unlock(&pr->pr_mtx); error = sysctl_handle_string(oidp, tmpname, len, req); if (req->newptr != NULL && error == 0) { /* * Copy the locally set hostname to all jails that share * this host info. */ sx_slock(&allprison_lock); while (!(pr->pr_flags & PR_HOST)) pr = pr->pr_parent; mtx_lock(&pr->pr_mtx); bcopy(tmpname, (char *)pr + pr_offset, len); FOREACH_PRISON_DESCENDANT_LOCKED(pr, cpr, descend) if (cpr->pr_flags & PR_HOST) descend = 0; else bcopy(tmpname, (char *)cpr + pr_offset, len); mtx_unlock(&pr->pr_mtx); sx_sunlock(&allprison_lock); } return (error); } SYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_CAPRD | CTLFLAG_MPSAFE, (void *)(offsetof(struct prison, pr_hostname)), MAXHOSTNAMELEN, sysctl_hostname, "A", "Hostname"); SYSCTL_PROC(_kern, KERN_NISDOMAINNAME, domainname, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_CAPRD | CTLFLAG_MPSAFE, (void *)(offsetof(struct prison, pr_domainname)), MAXHOSTNAMELEN, sysctl_hostname, "A", "Name of the current YP/NIS domain"); SYSCTL_PROC(_kern, KERN_HOSTUUID, hostuuid, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_CAPRD | CTLFLAG_MPSAFE, (void *)(offsetof(struct prison, pr_hostuuid)), HOSTUUIDLEN, sysctl_hostname, "A", "Host UUID"); static int regression_securelevel_nonmonotonic = 0; #ifdef REGRESSION SYSCTL_INT(_regression, OID_AUTO, securelevel_nonmonotonic, CTLFLAG_RW, ®ression_securelevel_nonmonotonic, 0, "securelevel may be lowered"); #endif static int sysctl_kern_securelvl(SYSCTL_HANDLER_ARGS) { struct prison *pr, *cpr; int descend, error, level; pr = req->td->td_ucred->cr_prison; /* * Reading the securelevel is easy, since the current jail's level * is known to be at least as secure as any higher levels. Perform * a lockless read since the securelevel is an integer. */ level = pr->pr_securelevel; error = sysctl_handle_int(oidp, &level, 0, req); if (error || !req->newptr) return (error); /* Permit update only if the new securelevel exceeds the old. */ sx_slock(&allprison_lock); mtx_lock(&pr->pr_mtx); if (!regression_securelevel_nonmonotonic && level < pr->pr_securelevel) { mtx_unlock(&pr->pr_mtx); sx_sunlock(&allprison_lock); return (EPERM); } pr->pr_securelevel = level; /* * Set all child jails to be at least this level, but do not lower * them (even if regression_securelevel_nonmonotonic). */ FOREACH_PRISON_DESCENDANT_LOCKED(pr, cpr, descend) { if (cpr->pr_securelevel < level) cpr->pr_securelevel = level; } mtx_unlock(&pr->pr_mtx); sx_sunlock(&allprison_lock); return (error); } SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel, CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_PRISON, 0, 0, sysctl_kern_securelvl, "I", "Current secure level"); #ifdef INCLUDE_CONFIG_FILE /* Actual kernel configuration options. */ extern char kernconfstring[]; SYSCTL_STRING(_kern, OID_AUTO, conftxt, CTLFLAG_RD | CTLFLAG_MPSAFE, kernconfstring, 0, "Kernel configuration file"); #endif static int sysctl_hostid(SYSCTL_HANDLER_ARGS) { struct prison *pr, *cpr; u_long tmpid; int descend, error; /* * Like sysctl_hostname, except it operates on a u_long * instead of a string, and is used only for hostid. */ pr = req->td->td_ucred->cr_prison; if (!(pr->pr_allow & PR_ALLOW_SET_HOSTNAME) && req->newptr) return (EPERM); tmpid = pr->pr_hostid; error = sysctl_handle_long(oidp, &tmpid, 0, req); if (req->newptr != NULL && error == 0) { sx_slock(&allprison_lock); while (!(pr->pr_flags & PR_HOST)) pr = pr->pr_parent; mtx_lock(&pr->pr_mtx); pr->pr_hostid = tmpid; FOREACH_PRISON_DESCENDANT_LOCKED(pr, cpr, descend) if (cpr->pr_flags & PR_HOST) descend = 0; else cpr->pr_hostid = tmpid; mtx_unlock(&pr->pr_mtx); sx_sunlock(&allprison_lock); } return (error); } SYSCTL_PROC(_kern, KERN_HOSTID, hostid, CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE | CTLFLAG_CAPRD, NULL, 0, sysctl_hostid, "LU", "Host ID"); /* * The osrelease string is copied from the global (osrelease in vers.c) into * prison0 by a sysinit and is inherited by child jails if not changed at jail * creation, so we always return the copy from the current prison data. */ static int sysctl_osrelease(SYSCTL_HANDLER_ARGS) { struct prison *pr; pr = req->td->td_ucred->cr_prison; return (SYSCTL_OUT(req, pr->pr_osrelease, strlen(pr->pr_osrelease) + 1)); } SYSCTL_PROC(_kern, KERN_OSRELEASE, osrelease, CTLTYPE_STRING | CTLFLAG_CAPRD | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, sysctl_osrelease, "A", "Operating system release"); /* * The osreldate number is copied from the global (osreldate in vers.c) into * prison0 by a sysinit and is inherited by child jails if not changed at jail * creation, so we always return the value from the current prison data. */ static int sysctl_osreldate(SYSCTL_HANDLER_ARGS) { struct prison *pr; pr = req->td->td_ucred->cr_prison; return (SYSCTL_OUT(req, &pr->pr_osreldate, sizeof(pr->pr_osreldate))); } /* * NOTICE: The *userland* release date is available in * /usr/include/osreldate.h */ SYSCTL_PROC(_kern, KERN_OSRELDATE, osreldate, CTLTYPE_INT | CTLFLAG_CAPRD | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, sysctl_osreldate, "I", "Kernel release date"); /* * The build-id is copied from the ELF section .note.gnu.build-id. The linker * script defines two variables to expose the beginning and end. LLVM * currently uses a SHA-1 hash, but other formats can be supported by checking * the length of the section. */ extern char __build_id_start[]; extern char __build_id_end[]; #define BUILD_ID_HEADER_LEN 0x10 #define BUILD_ID_HASH_MAXLEN 0x14 static int sysctl_build_id(SYSCTL_HANDLER_ARGS) { uintptr_t sectionlen = (uintptr_t)(__build_id_end - __build_id_start); int hashlen; char buf[2*BUILD_ID_HASH_MAXLEN+1]; /* * The ELF note section has a four byte length for the vendor name, * four byte length for the value, and a four byte vendor specific * type. The name for the build id is "GNU\0". We skip the first 16 * bytes to read the build hash. We will return the remaining bytes up * to 20 (SHA-1) hash size. If the hash happens to be a custom number * of bytes we will pad the value with zeros, as the section should be * four byte aligned. */ if (sectionlen <= BUILD_ID_HEADER_LEN || sectionlen > (BUILD_ID_HEADER_LEN + BUILD_ID_HASH_MAXLEN)) { return (ENOENT); } hashlen = sectionlen - BUILD_ID_HEADER_LEN; for (int i = 0; i < hashlen; i++) { uint8_t c = __build_id_start[i+BUILD_ID_HEADER_LEN]; snprintf(&buf[2*i], 3, "%02x", c); } return (SYSCTL_OUT(req, buf, strlen(buf) + 1)); } SYSCTL_PROC(_kern, OID_AUTO, build_id, CTLTYPE_STRING | CTLFLAG_CAPRD | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, sysctl_build_id, "A", "Operating system build-id"); SYSCTL_NODE(_kern, OID_AUTO, features, CTLFLAG_RD, 0, "Kernel Features"); #ifdef COMPAT_FREEBSD4 FEATURE(compat_freebsd4, "Compatible with FreeBSD 4"); #endif #ifdef COMPAT_FREEBSD5 FEATURE(compat_freebsd5, "Compatible with FreeBSD 5"); #endif #ifdef COMPAT_FREEBSD6 FEATURE(compat_freebsd6, "Compatible with FreeBSD 6"); #endif #ifdef COMPAT_FREEBSD7 FEATURE(compat_freebsd7, "Compatible with FreeBSD 7"); #endif /* * This is really cheating. These actually live in the libc, something * which I'm not quite sure is a good idea anyway, but in order for * getnext and friends to actually work, we define dummies here. * * XXXRW: These probably should be CTLFLAG_CAPRD. */ SYSCTL_STRING(_user, USER_CS_PATH, cs_path, CTLFLAG_RD, "", 0, "PATH that finds all the standard utilities"); SYSCTL_INT(_user, USER_BC_BASE_MAX, bc_base_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Max ibase/obase values in bc(1)"); SYSCTL_INT(_user, USER_BC_DIM_MAX, bc_dim_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Max array size in bc(1)"); SYSCTL_INT(_user, USER_BC_SCALE_MAX, bc_scale_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Max scale value in bc(1)"); SYSCTL_INT(_user, USER_BC_STRING_MAX, bc_string_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Max string length in bc(1)"); SYSCTL_INT(_user, USER_COLL_WEIGHTS_MAX, coll_weights_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Maximum number of weights assigned to an LC_COLLATE locale entry"); SYSCTL_INT(_user, USER_EXPR_NEST_MAX, expr_nest_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, ""); SYSCTL_INT(_user, USER_LINE_MAX, line_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Max length (bytes) of a text-processing utility's input line"); SYSCTL_INT(_user, USER_RE_DUP_MAX, re_dup_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Maximum number of repeats of a regexp permitted"); SYSCTL_INT(_user, USER_POSIX2_VERSION, posix2_version, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "The version of POSIX 1003.2 with which the system attempts to comply"); SYSCTL_INT(_user, USER_POSIX2_C_BIND, posix2_c_bind, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Whether C development supports the C bindings option"); SYSCTL_INT(_user, USER_POSIX2_C_DEV, posix2_c_dev, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Whether system supports the C development utilities option"); SYSCTL_INT(_user, USER_POSIX2_CHAR_TERM, posix2_char_term, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, ""); SYSCTL_INT(_user, USER_POSIX2_FORT_DEV, posix2_fort_dev, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Whether system supports FORTRAN development utilities"); SYSCTL_INT(_user, USER_POSIX2_FORT_RUN, posix2_fort_run, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Whether system supports FORTRAN runtime utilities"); SYSCTL_INT(_user, USER_POSIX2_LOCALEDEF, posix2_localedef, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Whether system supports creation of locales"); SYSCTL_INT(_user, USER_POSIX2_SW_DEV, posix2_sw_dev, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Whether system supports software development utilities"); SYSCTL_INT(_user, USER_POSIX2_UPE, posix2_upe, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Whether system supports the user portability utilities"); SYSCTL_INT(_user, USER_STREAM_MAX, stream_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Min Maximum number of streams a process may have open at one time"); SYSCTL_INT(_user, USER_TZNAME_MAX, tzname_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 0, "Min Maximum number of types supported for timezone names"); #include SYSCTL_INT(_debug_sizeof, OID_AUTO, vnode, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, sizeof(struct vnode), "sizeof(struct vnode)"); SYSCTL_INT(_debug_sizeof, OID_AUTO, proc, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, sizeof(struct proc), "sizeof(struct proc)"); static int sysctl_kern_pid_max(SYSCTL_HANDLER_ARGS) { int error, pm; pm = pid_max; error = sysctl_handle_int(oidp, &pm, 0, req); if (error || !req->newptr) return (error); sx_xlock(&proctree_lock); sx_xlock(&allproc_lock); /* * Only permit the values less then PID_MAX. * As a safety measure, do not allow to limit the pid_max too much. */ if (pm < 300 || pm > PID_MAX) error = EINVAL; else pid_max = pm; sx_xunlock(&allproc_lock); sx_xunlock(&proctree_lock); return (error); } SYSCTL_PROC(_kern, OID_AUTO, pid_max, CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NOFETCH | CTLFLAG_MPSAFE, 0, 0, sysctl_kern_pid_max, "I", "Maximum allowed pid"); #include #include SYSCTL_INT(_debug_sizeof, OID_AUTO, bio, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, sizeof(struct bio), "sizeof(struct bio)"); SYSCTL_INT(_debug_sizeof, OID_AUTO, buf, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, sizeof(struct buf), "sizeof(struct buf)"); #include SYSCTL_INT(_debug_sizeof, OID_AUTO, kinfo_proc, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, sizeof(struct kinfo_proc), "sizeof(struct kinfo_proc)"); /* Used by kernel debuggers. */ const int pcb_size = sizeof(struct pcb); SYSCTL_INT(_debug_sizeof, OID_AUTO, pcb, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, sizeof(struct pcb), "sizeof(struct pcb)"); /* XXX compatibility, remove for 6.0 */ #include #include SYSCTL_INT(_kern, OID_AUTO, fallback_elf_brand, CTLFLAG_RW, &__elfN(fallback_brand), sizeof(__elfN(fallback_brand)), "compatibility for kern.fallback_elf_brand"); diff --git a/sys/libkern/arc4random.c b/sys/libkern/arc4random.c index ad4c6b057e4a..cdc303e9d309 100644 --- a/sys/libkern/arc4random.c +++ b/sys/libkern/arc4random.c @@ -1,203 +1,183 @@ /*- * Copyright (c) 2017 The FreeBSD Foundation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #define CHACHA20_RESEED_BYTES 65536 #define CHACHA20_RESEED_SECONDS 300 #define CHACHA20_KEYBYTES 32 #define CHACHA20_BUFFER_SIZE 64 CTASSERT(CHACHA20_KEYBYTES*8 >= CHACHA_MINKEYLEN); int arc4rand_iniseed_state = ARC4_ENTR_NONE; MALLOC_DEFINE(M_CHACHA20RANDOM, "chacha20random", "chacha20random structures"); 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; } __aligned(CACHE_LINE_SIZE); static struct chacha20_s *chacha20inst = NULL; #define CHACHA20_FOREACH(_chacha20) \ for (_chacha20 = &chacha20inst[0]; \ _chacha20 <= &chacha20inst[mp_maxid]; \ _chacha20++) /* * 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); chacha_ivsetup(&chacha20->ctx, (u_char *)&tv_now.tv_sec, (u_char *)&tv_now.tv_usec); /* Reset for next reseed cycle. */ chacha20->t_reseed = tv_now.tv_sec + CHACHA20_RESEED_SECONDS; chacha20->numbytes = 0; mtx_unlock(&chacha20->mtx); } /* * Initialize the contexts. */ static void chacha20_init(void) { struct chacha20_s *chacha20; chacha20inst = malloc((mp_maxid + 1) * sizeof(struct chacha20_s), M_CHACHA20RANDOM, M_NOWAIT | M_ZERO); KASSERT(chacha20inst != NULL, ("chacha20_init: memory allocation error")); CHACHA20_FOREACH(chacha20) { 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)); } } SYSINIT(chacha20, SI_SUB_LOCK, SI_ORDER_ANY, chacha20_init, NULL); static void chacha20_uninit(void) { struct chacha20_s *chacha20; CHACHA20_FOREACH(chacha20) mtx_destroy(&chacha20->mtx); free(chacha20inst, M_CHACHA20RANDOM); } SYSUNINIT(chacha20, SI_SUB_LOCK, SI_ORDER_ANY, chacha20_uninit, NULL); /* * MPSAFE */ void arc4rand(void *ptr, u_int len, int reseed) { struct chacha20_s *chacha20; struct timeval tv; u_int length; u_int8_t *p; if (reseed || atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_HAVE, ARC4_ENTR_SEED)) CHACHA20_FOREACH(chacha20) chacha20_randomstir(chacha20); chacha20 = &chacha20inst[curcpu]; getmicrouptime(&tv); /* We may get unlucky and be migrated off this CPU, but that is expected to be infrequent */ if ((chacha20->numbytes > CHACHA20_RESEED_BYTES) || (tv.tv_sec > chacha20->t_reseed)) chacha20_randomstir(chacha20); mtx_lock(&chacha20->mtx); p = ptr; while (len) { length = MIN(CHACHA20_BUFFER_SIZE, len); chacha_encrypt_bytes(&chacha20->ctx, chacha20->m_buffer, p, length); p += length; len -= length; chacha20->numbytes += length; if (chacha20->numbytes > CHACHA20_RESEED_BYTES) { mtx_unlock(&chacha20->mtx); chacha20_randomstir(chacha20); mtx_lock(&chacha20->mtx); } } mtx_unlock(&chacha20->mtx); } uint32_t arc4random(void) { uint32_t ret; arc4rand(&ret, sizeof(ret), 0); return ret; } void arc4random_buf(void *ptr, size_t len) { arc4rand(ptr, len, 0); } diff --git a/sys/sys/random.h b/sys/sys/random.h index a94d3f378a28..f64728e79b8d 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -1,166 +1,164 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2000-2015, 2017 Mark R. V. Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SYS_RANDOM_H_ #define _SYS_RANDOM_H_ #include #ifdef _KERNEL 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 read_random_uio(void *a __unused, u_int b __unused) { return (0); } -static __inline u_int +static __inline void read_random(void *a __unused, u_int b __unused) { - return (0); } #endif /* * Note: if you add or remove members of random_entropy_source, remember to * also update the strings in the static array random_source_descr[] in * random_harvestq.c. * * NOTE: complain loudly to markm@ or on the lists if this enum gets more than 32 * distinct values (0-31)! ENTROPYSOURCE may be == 32, but not > 32. */ enum random_entropy_source { RANDOM_START = 0, RANDOM_CACHED = 0, /* Environmental sources */ RANDOM_ATTACH, RANDOM_KEYBOARD, RANDOM_MOUSE, RANDOM_NET_TUN, RANDOM_NET_ETHER, RANDOM_NET_NG, RANDOM_INTERRUPT, RANDOM_SWI, RANDOM_FS_ATIME, RANDOM_UMA, /* Special!! UMA/SLAB Allocator */ RANDOM_ENVIRONMENTAL_END = RANDOM_UMA, /* Fast hardware random-number sources from here on. */ RANDOM_PURE_START, RANDOM_PURE_OCTEON = RANDOM_PURE_START, RANDOM_PURE_SAFE, RANDOM_PURE_GLXSB, RANDOM_PURE_UBSEC, RANDOM_PURE_HIFN, RANDOM_PURE_RDRAND, RANDOM_PURE_NEHEMIAH, RANDOM_PURE_RNDTEST, RANDOM_PURE_VIRTIO, RANDOM_PURE_BROADCOM, RANDOM_PURE_CCP, RANDOM_PURE_DARN, RANDOM_PURE_TPM, ENTROPYSOURCE }; #define RANDOM_HARVEST_EVERYTHING_MASK ((1 << (RANDOM_ENVIRONMENTAL_END + 1)) - 1) #define RANDOM_HARVEST_PURE_MASK (((1 << ENTROPYSOURCE) - 1) & (-1UL << RANDOM_PURE_START)) #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; void random_harvest_queue_(const void *, u_int, enum random_entropy_source); void random_harvest_fast_(const void *, u_int); void random_harvest_direct_(const void *, u_int, enum random_entropy_source); static __inline void random_harvest_queue(const void *entropy, u_int size, enum random_entropy_source origin) { if (hc_source_mask & (1 << origin)) random_harvest_queue_(entropy, size, origin); } static __inline void random_harvest_fast(const void *entropy, u_int size, enum random_entropy_source origin) { if (hc_source_mask & (1 << origin)) random_harvest_fast_(entropy, size); } static __inline void random_harvest_direct(const void *entropy, u_int size, enum random_entropy_source origin) { if (hc_source_mask & (1 << origin)) random_harvest_direct_(entropy, size, origin); } void random_harvest_register_source(enum random_entropy_source); void random_harvest_deregister_source(enum random_entropy_source); #else #define random_harvest_queue(a, b, c) do {} while (0) #define random_harvest_fast(a, b, c) do {} while (0) #define random_harvest_direct(a, b, c) do {} while (0) #define random_harvest_register_source(a) do {} while (0) #define random_harvest_deregister_source(a) do {} while (0) #endif #if defined(RANDOM_ENABLE_UMA) #define random_harvest_fast_uma(a, b, c) random_harvest_fast(a, b, c) #else /* !defined(RANDOM_ENABLE_UMA) */ #define random_harvest_fast_uma(a, b, c) do {} while (0) #endif /* defined(RANDOM_ENABLE_UMA) */ #if defined(RANDOM_ENABLE_ETHER) #define random_harvest_queue_ether(a, b) random_harvest_queue(a, b, RANDOM_NET_ETHER) #else /* !defined(RANDOM_ENABLE_ETHER) */ #define random_harvest_queue_ether(a, b) do {} while (0) #endif /* defined(RANDOM_ENABLE_ETHER) */ #endif /* _KERNEL */ #define GRND_NONBLOCK 0x1 #define GRND_RANDOM 0x2 __BEGIN_DECLS ssize_t getrandom(void *buf, size_t buflen, unsigned int flags); __END_DECLS #endif /* _SYS_RANDOM_H_ */