From 3c7f459211c744e91e02d7a73c3deffe76f41987 Mon Sep 17 00:00:00 2001 From: John Denker Date: Wed, 16 Oct 2013 16:14:22 -0700 Subject: make devrand pool the same as input pool; better comments --- drivers/char/random.c | 284 +++++++++++++++++++++++++++----------------------- 1 file changed, 152 insertions(+), 132 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/random.c b/drivers/char/random.c index 13d5164..4a2487c 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -41,46 +41,46 @@ /* * (now, with legal B.S. out of the way.....) - * + * This routine gathers environmental noise from device drivers, etc., - * and returns good random numbers, suitable for cryptographic use. - * Besides the obvious cryptographic uses, these numbers are also good - * for seeding TCP sequence numbers, and other places where it is - * desirable to have numbers which are not only random, but hard to - * predict by an attacker. - * + * and returns good randomly distributed numbers, suitable for + * cryptographic use. Besides the obvious cryptographic uses, these + * numbers are also good for seeding TCP sequence numbers, and other + * places where it is desirable to have numbers which are not only + * random, but hard to predict by an attacker. + * Theory of operation * =================== - * + * Computers are very predictable devices. Hence it is extremely hard - * to produce truly random numbers on a computer --- as opposed to - * pseudo-random numbers, which can easily generated by using a - * algorithm. Unfortunately, it is very easy for attackers to guess - * the sequence of pseudo-random number generators, and for some - * applications this is not acceptable. So instead, we must try to - * gather "environmental noise" from the computer's environment, which - * must be hard for outside attackers to observe, and use that to - * generate random numbers. In a Unix environment, this is best done - * from inside the kernel. - - * Sources of true randomness from the environment include + * to implement a truly random distribution on a computer --- as + * opposed to a pseudo-random distribution, which can easily + * implemented by an algorithm. Unfortunately, it is sometimes + * possible for attackers to guess the output sequence of + * pseudo-random generators, and for some applications this is not + * acceptable. So instead, we must try to gather "noise" from the + * computer's environment, i.e. signals that contain an element of + * actual entropy, and that are hard for outside attackers to observe, + * and use that to generate randomly-distributed numbers. + + * Environmental sources that are available to the kernel include * inter-keyboard timings, inter-interrupt timings from some - * interrupts, and other events which are both (a) non-deterministic - * and (b) hard for an outside observer to measure. + * interrupts, and similar events. Again, these must be both (a) + * non-deterministic and (b) hard for an outside observer to measure. * Operation of this device is centered on four "pools". The four * pools are similar in structure but serve different purposes. * Here is a block diagram: * - * fast data --> fast pool --\ /--> blocking pool - * --> input pool -- - * slower, larger data ------/ \--> nonblocking pool + * fast events --> fast pool --\ /--> blocking pool + * --> input pool -- + * slower, larger events ------/ \--> nonblocking pool * The fast pool is similar in function to the input pool, as * described below. It handles events that occur frequently but * contain little entropy. It is fast enough that the overhead of - * doing it on every interrupt is very reasonable. It is similar in + * doing it on every interrupt is affordable. It is similar in * structure to the input pool, but much smaller. After accumulating * a modest amount of entropy, it passes the entropy on to the input * pool. @@ -90,21 +90,21 @@ * pool commonly has an entropy density of much less than 8 bits per * byte. This is mixed into the input pool, which is mixed using a * CRC-like function. The mixing is not cryptographically strong, but - * it is adequate assuming the randomness is not chosen maliciously. - * As random bytes are mixed into this pool, the routines keep an - * *estimate* of how many bits of entropy are contained in the pool. - - * When random bytes are desired, they can be extracted from the input - * pool by taking the SHA hash of the pool contents. This avoids - * exposing the internal state of the pool. It is believed to be - * computationally infeasible to derive any useful information about - * the input of SHA from its output. Even if it is possible to - * analyze SHA in some clever way, as long as the amount of data - * extracted in this way is less than the entropy content of the the - * input pool, the extracted data is totally unpredictable. For this - * reason, the routine decreases its internal estimate of how many - * bits of "true randomness" (aka entropy) are contained in the input - * pool whenever data is extracted. + * should be adequate if the randomness is not chosen maliciously. As + * bytes are mixed into this pool, the routines keep an *estimate* of + * how many bits of entropy are contained in the pool. + + * When randomly-distributed bytes are desired, they can be extracted + * from the input pool by taking the SHA hash of the pool contents. + * This avoids exposing the internal state of the pool. It is + * believed to be computationally infeasible to derive any useful + * information about the input of SHA from its output. Even if it is + * possible to analyze SHA in some clever way, as long as the amount + * of data extracted in this way is less than the entropy content of + * the the input pool, the extracted data is totally unpredictable. + * For this reason, the routine decreases its internal estimate of how + * many bits of "true randomness" (aka entropy) are contained in the + * input pool whenever data is extracted. * The blocking pool is associated with /dev/random. It is similar in * structure to the input pool, but its purpose is different. It @@ -136,8 +136,8 @@ * * void get_random_bytes(void *buf, int nbytes); * - * This interface will return the requested number of random bytes, - * and place it in the requested buffer. + * This interface will return the requested number of bytes, and place + * it them the requested buffer. * The two other interfaces are two character devices /dev/random and * /dev/urandom. /dev/random is suitable for use when very high @@ -216,6 +216,11 @@ * start-ups. To do this, put the following lines an appropriate * script which is run during the boot sequence: + * The byte count of 512 is overkill at present, since we + * only use it to reseed pools that are 4x smaller than that, + * but we preserve it because (a) it is traditional, and (b) + * we might put it to good use in future versions. + * echo "Initializing random number generator..." * random_seed=/var/run/random-seed * # Carry a random seed from start-up to start-up @@ -226,7 +231,7 @@ * touch $random_seed * fi * chmod 600 $random_seed - * dd if=/dev/urandom of=$random_seed count=1 bs=128 + * dd if=/dev/urandom of=$random_seed count=1 bs=512 * * and the following lines in an appropriate script which is run as * the system is shutdown: @@ -237,8 +242,8 @@ * random_seed=/var/run/random-seed * touch $random_seed * chmod 600 $random_seed - * dd if=/dev/urandom of=$random_seed count=1 bs=128 - * + * dd if=/dev/urandom of=$random_seed count=1 bs=512 + * For example, on most modern systems using the System V init * scripts, such code fragments would be found in * /etc/rc.d/init.d/random. On older Linux systems, the correct script @@ -325,7 +330,8 @@ #include /* - * Configuration information + * Configuration information. + * Here, a "word" is of type __u32 */ #define INPUT_POOL_WORDS 128 #define OUTPUT_POOL_WORDS 32 @@ -334,20 +340,16 @@ /* Choose 160 bits. Seems reasonable. Recommended in the Yarrow paper. */ #define RESEED_BATCH 160 /* bits */ - -/* - * The nonblocking output pool will not drag the input pool below this - * fill fraction: - */ -#define FILL_FRAC(X) ((X)*3/4) +/* Saturation point of extraction subttl counters; large round number: */ +#define SUBTTL_SAT 1000000000000000000LL typedef unsigned long long int ulonglong; #if defined __SIZEOF_LONG_LONG__ && __SIZEOF_LONG_LONG__ == 8 -/* This is how it should be using gcc - * on Intel x86_32 and also Intel 64 architectures. +/* This is how we expect things to be when using gcc + * on both Intel x86_32 and Intel 64 architectures. * I don't know how to extrapolate to other architectures * or other compilers ... - * but at least we are being properly defensive. + * but at least we are being clear about the assumptions being made. */ #else #error Broken assumption: __SIZEOF_LONG_LONG__ should be defined and equal to 8 @@ -446,28 +448,29 @@ static struct poolinfo { * in fact it almost certainly isn't. Nonetheless, the irreducible factors * of a random large-degree polynomial over GF(2) are more than large enough * that periodicity is not a concern. - * + * The input hash is much less sensitive than the output hash. All - * that we want of it is that it be a good non-cryptographic hash; - * i.e. it not produce collisions when fed "random" data of the sort - * we expect to see. As long as the pool state differs for different - * inputs, we have preserved the input entropy and done a good job. - * The fact that an intelligent attacker can construct inputs that - * will produce controlled alterations to the pool's state is not - * important because we don't consider such inputs to contribute any - * randomness. The only property we need with respect to them is that - * the attacker can't increase his/her knowledge of the pool's state. - * Since all additions are reversible (knowing the final state and the - * input, you can reconstruct the initial state), if an attacker has - * any uncertainty about the initial state, he/she can only shuffle - * that uncertainty about, but never cause any collisions (which would + * that we want of it is that it be a good hash in the sense that it + * not produce collisions when fed "random" data of the sort we expect + * to see. It need not be a cryptographically-strong hash. As long + * as the pool state differs for different inputs, we have preserved + * the input entropy and done a good job. The fact that an + * intelligent attacker can construct inputs that will produce + * controlled alterations to the pool's state is not important because + * we don't consider such inputs to contribute any randomness. The + * only property we need with respect to them is that the attacker + * can't increase his/her knowledge of the pool's state. Since all + * additions are reversible (knowing the final state and the input, + * you can reconstruct the initial state), if an attacker has any + * uncertainty about the initial state, he/she can only shuffle that + * uncertainty about, but never cause any collisions (which would * decrease the uncertainty). - * + * The chosen system lets the state of the pool be (essentially) the input * modulo the generator polymnomial. Now, for random primitive polynomials, * this is a universal class of hash functions, meaning that the chance * of a collision is limited by the attacker's knowledge of the generator - * polynomail, so if it is chosen at random, an attacker can never force + * polynomial, so if it is chosen at random, an attacker can never force * a collision. Here, we use a fixed polynomial, but we *can* assume that * ###--> it is unknown to the processes generating the input entropy. <-### * Because of this important property, this is a good, collision-resistant @@ -488,8 +491,8 @@ module_param(debug, bool, 0644); printk(KERN_DEBUG "random %04d %04d %04d: " \ fmt,\ input_pool.entropy_count,\ - blocking_pool.entropy_count,\ - nonblocking_pool.entropy_count,\ + devrand_pool.entropy_count,\ + prng_pool.entropy_count,\ ## arg); } while (0) /********************************************************************** @@ -506,7 +509,7 @@ struct Pool { __u32 *pooldata; const char *name; struct Pool *pull; - int limit; + int blockable; /* read-write data: */ spinlock_t lock; @@ -522,32 +525,38 @@ struct Pool { }; static __u32 input_pool_data[INPUT_POOL_WORDS]; -static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; -static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; +#ifdef OVERCOMPLICATED +static __u32 devrand_pool_data[OUTPUT_POOL_WORDS]; +#endif +static __u32 prng_pool_data[OUTPUT_POOL_WORDS]; static struct Pool input_pool = { .poolinfo = &poolinfo_table[0], .name = "input", - .limit = 1, + .blockable = 1, .lock = __SPIN_LOCK_UNLOCKED(input_pool.lock), .pooldata = input_pool_data }; -static struct Pool blocking_pool = { +#ifdef OVERCOMPLICATED +static struct Pool devrand_pool = { .poolinfo = &poolinfo_table[1], .name = "blocking", - .limit = 1, + .blockable = 1, .pull = &input_pool, - .lock = __SPIN_LOCK_UNLOCKED(blocking_pool.lock), - .pooldata = blocking_pool_data + .lock = __SPIN_LOCK_UNLOCKED(devrand_pool.lock), + .pooldata = devrand_pool_data }; +#else +#define devrand_pool input_pool +#endif -static struct Pool nonblocking_pool = { +static struct Pool prng_pool = { .poolinfo = &poolinfo_table[1], .name = "nonblocking", .pull = &input_pool, - .lock = __SPIN_LOCK_UNLOCKED(nonblocking_pool.lock), - .pooldata = nonblocking_pool_data + .lock = __SPIN_LOCK_UNLOCKED(prng_pool.lock), + .pooldata = prng_pool_data }; static __u32 const twist_table[8] = { @@ -666,7 +675,7 @@ static void fast_mix(struct fast_pool *f, const void *in, int nbytes) } /* - * Credit the entropy store with n bits of entropy. + * Credit the pool with n bits of entropy. * Normally n is positive. * Sufficiently large n will wake up a blocked reader. * Negative n values are allowed, but the resulting behavior @@ -735,15 +744,15 @@ void add_device_randomness(const void *buf, unsigned int size) mix_pool_bytes(&input_pool, buf, size, NULL); mix_pool_bytes(&input_pool, &time, sizeof(time), NULL); - mix_pool_bytes(&nonblocking_pool, buf, size, NULL); - mix_pool_bytes(&nonblocking_pool, &time, sizeof(time), NULL); + mix_pool_bytes(&prng_pool, buf, size, NULL); + mix_pool_bytes(&prng_pool, &time, sizeof(time), NULL); } EXPORT_SYMBOL(add_device_randomness); static struct timer_rand_state input_timer_state; /* - * This function adds entropy to the entropy "pool" by using timing + * This function adds entropy to the input pool by using timing * delays. It uses the timer_rand_state structure to make an estimate * of how many bits of entropy this call has added to the pool. * @@ -853,7 +862,7 @@ void add_interrupt_randomness(int irq, int irq_flags) fast_pool->last = now; - r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool; + r = prng_pool.initialized ? &input_pool : &prng_pool; __mix_pool_bytes(r, &fast_pool->pooldata, sizeof(fast_pool->pooldata), NULL); /* * If we don't have a valid cycle counter, and we see @@ -887,16 +896,17 @@ void add_disk_randomness(struct gendisk *disk) /********************************************************************* * * Extraction routines. - * - * These routines extract bytes that are "random" in some unspecified - * sense, but may _or may not_ contain any appreciable amount of - * entropy. Therefore, please do not call them "entropy" extraction - * routines. - * + + * These routines extract bytes from the pools. The extracted bytes + * exhibit a random distribution, possibly "random" in the sense of + * pseudorandom, or possibly "random" in the sense of actual entropy. + * Since the latter is not guaranteed, please do not call them + * "entropy" extraction routines. + * Specifically, in the case of the PRNG, i.e. the nonblocking pool, * the extracted bytes may have an entropy density that is vastly less * than 8 bits per byte, orders of magnitude less. - * + * ********************************************************************/ /* Forward reference */ @@ -930,8 +940,8 @@ static void fill_pool( int actual; /* measured in BYTES */ int headspace = r->poolinfo->POOLBITS - r->entropy_count; if (!r->pull) return; /* no upstream pool to pull from */ - if (r->limit) { -/* Here if we are limited i.e. blocking i.e. /dev/random i.e. TRNG. */ + if (r->blockable) { +/* Here if we are blockable i.e. /dev/random i.e. TRNG. */ int pullhead = r->pull->poolinfo->POOLBITS - r->pull->entropy_count; /* Only the top 500 bits are free for extraloading: */ int extraload = 500 - pullhead; @@ -944,7 +954,7 @@ static void fill_pool( mybatch = rsvd = 0; } else { /* - * Here if we are non-limited i.e. non-blocking i.e. urandom i.e. PRNG. + * Here if we are non-blocking i.e. urandom i.e. PRNG. * Reserve a suitable amount of entropy in the input pool, on a * sliding scale based on how desperately we need to be reseeded. * @@ -961,7 +971,10 @@ static void fill_pool( /* When the appetite gets to 20, rsvd goes to zero: */ rsvd = rsvd - appetite*rsvd/20; if (rsvd < 0) rsvd = 0; -/* For the PRNG, make the request big enough to be "significant" to any attacker: */ +/* + * For the PRNG, make the request big enough to be + * "significant" to any attacker: + */ mybatch = txbits = RESEED_BATCH; } @@ -1027,8 +1040,8 @@ static size_t debit(struct Pool *r, size_t nbytes, int min, int entropy_count, orig; retry: entropy_count = orig = ACCESS_ONCE(r->entropy_count); - /* If limited, never pull more than available */ - if (r->limit && nbytes + reserved >= entropy_count / 8) + /* If blockable, never pull more than available */ + if (r->blockable && nbytes + reserved >= entropy_count / 8) nbytes = entropy_count/8 - reserved; if (entropy_count / 8 >= nbytes + reserved) { @@ -1046,7 +1059,7 @@ retry: } DEBUG_ENT("debiting %zu entropy credits from %s%s\n", - nbytes * 8, r->name, r->limit ? "" : " (unlimited)"); + nbytes * 8, r->name, r->blockable ? "" : " (nonblocking)"); spin_unlock_irqrestore(&r->lock, flags); @@ -1144,6 +1157,8 @@ static ssize_t extract_rnd(struct Pool *r, void *buf, trace_extract_rnd(r->name, EXTRACT_SIZE, r->entropy_count, _RET_IP_); fill_pool(r, EXTRACT_SIZE); +/* FIXME: */ +/* why is there no debit() associated with this extract_buf()? */ extract_buf(r, tmp); spin_lock_irqsave(&r->lock, flags); memcpy(r->last_data, tmp, EXTRACT_SIZE); @@ -1185,7 +1200,8 @@ static ssize_t extract_rnd(struct Pool *r, void *buf, if (ret > 0) { /* Subttl does not overflow; it saturates at a user-friendly round number: */ r->extracted_subttl += BYTE2BIT(ret); - if (r->extracted_subttl > 1000000000000000000LL) r->extracted_subttl = 1000000000000000000LL; + if (r->extracted_subttl > SUBTTL_SAT) + r->extracted_subttl = SUBTTL_SAT; /* Total does not saturate; it just overflows and wraps around. */ r->extracted_total += BYTE2BIT(ret); } @@ -1238,13 +1254,14 @@ static ssize_t extract_rnd_user(struct Pool *r, void __user *buf, /* * This function is the exported kernel interface. It returns some - * number of good random numbers, suitable for key generation, seeding - * TCP sequence numbers, etc. It does not use the hw random number - * generator, if available; use get_random_bytes_arch() for that. + * number of good pseudorandomly distributed numbers, suitable for key + * generation, seeding TCP sequence numbers, etc. It does not use the + * hw random number generator, if available; use + * get_random_bytes_arch() for that. */ void get_random_bytes(void *buf, int nbytes) { - extract_rnd(&nonblocking_pool, buf, nbytes, 0, 0); + extract_rnd(&prng_pool, buf, nbytes, 0, 0); } EXPORT_SYMBOL(get_random_bytes); @@ -1276,7 +1293,7 @@ void get_random_bytes_arch(void *buf, int nbytes) } if (nbytes) - extract_rnd(&nonblocking_pool, p, nbytes, 0, 0); + extract_rnd(&prng_pool, p, nbytes, 0, 0); } EXPORT_SYMBOL(get_random_bytes_arch); @@ -1323,8 +1340,8 @@ static void init_std_data(struct Pool *r) static int rand_initialize(void) { init_std_data(&input_pool); - init_std_data(&blocking_pool); - init_std_data(&nonblocking_pool); + init_std_data(&devrand_pool); + init_std_data(&prng_pool); return 0; } module_init(rand_initialize); @@ -1359,7 +1376,7 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) * Kludge: zero-byte read: Fill the pool from upstream sources. */ if (nbytes == 0){ - fill_pool(&blocking_pool, 0); + fill_pool(&devrand_pool, 0); return 0; } @@ -1370,7 +1387,7 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) DEBUG_ENT("reading %zu bits\n", n*8); - n = extract_rnd_user(&blocking_pool, buf, n); + n = extract_rnd_user(&devrand_pool, buf, n); if (n < 0) { retval = n; @@ -1415,7 +1432,7 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) static ssize_t urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { - return extract_rnd_user(&nonblocking_pool, buf, nbytes); + return extract_rnd_user(&prng_pool, buf, nbytes); } static unsigned int @@ -1460,10 +1477,10 @@ static ssize_t random_write(struct file *file, const char __user *buffer, { size_t ret; - ret = write_pool(&blocking_pool, buffer, count); + ret = write_pool(&devrand_pool, buffer, count); if (ret) return ret; /* some error */ - ret = write_pool(&nonblocking_pool, buffer, count); + ret = write_pool(&prng_pool, buffer, count); if (ret) return ret; /* some error */ @@ -1480,8 +1497,8 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) case RNDGETENTCNT: /* inherently racy, no point locking */ if (put_user(input_pool.entropy_count - + blocking_pool.entropy_count - + nonblocking_pool.entropy_count, p)) + + devrand_pool.entropy_count + + prng_pool.entropy_count, p)) return -EFAULT; return 0; case RNDADDTOENTCNT: @@ -1548,7 +1565,7 @@ const struct file_operations urandom_fops = { ***************************************************************/ /* - * Generate random UUID + * Generate randomly-distributed UUID */ void generate_random_uuid(unsigned char uuid_out[16]) { @@ -1616,8 +1633,10 @@ static int total_entropy_count; static int sum_entropy_count(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos){ total_entropy_count = input_pool.entropy_count - + blocking_pool.entropy_count - + nonblocking_pool.entropy_count; +#ifdef OVERCOMPLICATED + + devrand_pool.entropy_count +#endif + + prng_pool.entropy_count; return proc_dointvec(table, write, buffer, lenp, ppos); } @@ -1650,14 +1669,14 @@ struct ctl_table random_table[] = { .maxlen = sizeof(int), .mode = 0444, .proc_handler = proc_dointvec, - .data = &blocking_pool.entropy_count, + .data = &devrand_pool.entropy_count, }, { .procname = "entropy_avail_ur", .maxlen = sizeof(int), .mode = 0444, .proc_handler = proc_dointvec, - .data = &nonblocking_pool.entropy_count, + .data = &prng_pool.entropy_count, }, { .procname = "extracted_total_inp", @@ -1671,14 +1690,14 @@ struct ctl_table random_table[] = { .maxlen = sizeof(ulonglong), .mode = 0644, .proc_handler = proc_doulonglongvec_minmax, - .data = &blocking_pool.extracted_total, + .data = &devrand_pool.extracted_total, }, { .procname = "extracted_total_ur", .maxlen = sizeof(ulonglong), .mode = 0644, .proc_handler = proc_doulonglongvec_minmax, - .data = &nonblocking_pool.extracted_total, + .data = &prng_pool.extracted_total, }, { .procname = "extracted_subttl_inp", @@ -1692,14 +1711,14 @@ struct ctl_table random_table[] = { .maxlen = sizeof(ulonglong), .mode = 0644, .proc_handler = proc_doulonglongvec_minmax, - .data = &blocking_pool.extracted_subttl, + .data = &devrand_pool.extracted_subttl, }, { .procname = "extracted_subttl_ur", .maxlen = sizeof(ulonglong), .mode = 0644, .proc_handler = proc_doulonglongvec_minmax, - .data = &nonblocking_pool.extracted_subttl, + .data = &prng_pool.extracted_subttl, }, { .procname = "read_wakeup_threshold", @@ -1746,11 +1765,12 @@ static int __init random_int_secret_init(void) late_initcall(random_int_secret_init); /* - * Get a random word for internal kernel use only. Similar to urandom but - * with the goal of minimal consumption of entropy. As a result, the random - * value is not cryptographically secure but for several uses the cost of - * depleting entropy is too high. - * + * Get a word from a random distribution, for internal kernel use + * only. Similar to urandom but with the goal of minimal consumption + * of entropy. As a result, the random distribution is not + * cryptographically secure but for several uses the cost of depleting + * entropy is too high. + * Presumably no longer needed, now that /dev/urandom * no longer consumes entropy so rapaciously. */ -- cgit v1.2.3