From 85a1f77716cf546d9b9c42e2848b5712f51ba1ee Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 21 Sep 2013 18:06:02 -0400 Subject: random: mix in architectural randomness earlier in extract_buf() Previously if CPU chip had a built-in random number generator (i.e., RDRAND on newer x86 chips), we mixed it in at the very end of extract_buf() using an XOR operation. We now mix it in right after the calculate a hash across the entire pool. This has the advantage that any contribution of entropy from the CPU's HWRNG will get mixed back into the pool. In addition, it means that if the HWRNG has any defects (either accidentally or maliciously introduced), this will be mitigated via the non-linear transform of the SHA-1 hash function before we hand out generated output. Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 2d5daf9b58e9..54d020815b4e 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -904,7 +904,7 @@ static void extract_buf(struct entropy_store *r, __u8 *out) int i; union { __u32 w[5]; - unsigned long l[LONGS(EXTRACT_SIZE)]; + unsigned long l[LONGS(20)]; } hash; __u32 workspace[SHA_WORKSPACE_WORDS]; __u8 extract[64]; @@ -916,6 +916,17 @@ static void extract_buf(struct entropy_store *r, __u8 *out) for (i = 0; i < r->poolinfo->poolwords; i += 16) sha_transform(hash.w, (__u8 *)(r->pool + i), workspace); + /* + * If we have a architectural hardware random number + * generator, mix that in, too. + */ + for (i = 0; i < LONGS(20); i++) { + unsigned long v; + if (!arch_get_random_long(&v)) + break; + hash.l[i] ^= v; + } + /* * We mix the hash back into the pool to prevent backtracking * attacks (where the attacker knows the state of the pool @@ -945,17 +956,6 @@ static void extract_buf(struct entropy_store *r, __u8 *out) hash.w[1] ^= hash.w[4]; hash.w[2] ^= rol32(hash.w[2], 16); - /* - * If we have a architectural hardware random number - * generator, mix that in, too. - */ - for (i = 0; i < LONGS(EXTRACT_SIZE); i++) { - unsigned long v; - if (!arch_get_random_long(&v)) - break; - hash.l[i] ^= v; - } - memcpy(out, &hash, EXTRACT_SIZE); memset(&hash, 0, sizeof(hash)); } -- cgit v1.2.3-58-ga151 From 9ed17b70b409dc48c134a80b5a6df582ba759de2 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 10 Sep 2013 23:16:17 -0400 Subject: random: statically compute poolbitshift, poolbytes, poolbits Use a macro to statically compute poolbitshift (will be used in a subsequent patch), poolbytes, and poolbits. On virtually all architectures the cost of a memory load with an offset is the same as the one of a memory load. It is still possible for this to generate worse code since the C compiler doesn't know the fixed relationship between these fields, but that is somewhat unlikely. Signed-off-by: H. Peter Anvin Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 54d020815b4e..20651a2fd8a7 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -309,46 +309,45 @@ static DEFINE_PER_CPU(int, trickle_count); * scaled squared error sum) except for the last tap, which is 1 to * get the twisting happening as fast as possible. */ + static struct poolinfo { - int poolwords; + int poolbitshift, poolwords, poolbytes, poolbits; +#define S(x) ilog2(x)+5, (x), (x)*4, (x)*32 int tap1, tap2, tap3, tap4, tap5; } poolinfo_table[] = { /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ - { 128, 103, 76, 51, 25, 1 }, + { S(128), 103, 76, 51, 25, 1 }, /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */ - { 32, 26, 20, 14, 7, 1 }, + { S(32), 26, 20, 14, 7, 1 }, #if 0 /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ - { 2048, 1638, 1231, 819, 411, 1 }, + { S(2048), 1638, 1231, 819, 411, 1 }, /* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */ - { 1024, 817, 615, 412, 204, 1 }, + { S(1024), 817, 615, 412, 204, 1 }, /* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */ - { 1024, 819, 616, 410, 207, 2 }, + { S(1024), 819, 616, 410, 207, 2 }, /* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */ - { 512, 411, 308, 208, 104, 1 }, + { S(512), 411, 308, 208, 104, 1 }, /* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */ - { 512, 409, 307, 206, 102, 2 }, + { S(512), 409, 307, 206, 102, 2 }, /* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */ - { 512, 409, 309, 205, 103, 2 }, + { S(512), 409, 309, 205, 103, 2 }, /* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */ - { 256, 205, 155, 101, 52, 1 }, + { S(256), 205, 155, 101, 52, 1 }, /* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */ - { 128, 103, 78, 51, 27, 2 }, + { S(128), 103, 78, 51, 27, 2 }, /* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */ - { 64, 52, 39, 26, 14, 1 }, + { S(64), 52, 39, 26, 14, 1 }, #endif }; -#define POOLBITS poolwords*32 -#define POOLBYTES poolwords*4 - /* * For the purposes of better mixing, we use the CRC-32 polynomial as * well to make a twisted Generalized Feedback Shift Reigster @@ -599,8 +598,8 @@ retry: if (entropy_count < 0) { DEBUG_ENT("negative entropy/overflow\n"); entropy_count = 0; - } else if (entropy_count > r->poolinfo->POOLBITS) - entropy_count = r->poolinfo->POOLBITS; + } else if (entropy_count > r->poolinfo->poolbits) + entropy_count = r->poolinfo->poolbits; if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) goto retry; @@ -815,7 +814,7 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) __u32 tmp[OUTPUT_POOL_WORDS]; if (r->pull && r->entropy_count < nbytes * 8 && - r->entropy_count < r->poolinfo->POOLBITS) { + r->entropy_count < r->poolinfo->poolbits) { /* If we're limited, always leave two wakeup worth's BITS */ int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; int bytes = nbytes; @@ -857,7 +856,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, /* Hold lock while accounting */ spin_lock_irqsave(&r->lock, flags); - BUG_ON(r->entropy_count > r->poolinfo->POOLBITS); + BUG_ON(r->entropy_count > r->poolinfo->poolbits); DEBUG_ENT("trying to extract %zu bits from %s\n", nbytes * 8, r->name); @@ -1112,7 +1111,7 @@ static void init_std_data(struct entropy_store *r) r->entropy_total = 0; r->last_data_init = false; mix_pool_bytes(r, &now, sizeof(now), NULL); - for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof(rv)) { + for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) { if (!arch_get_random_long(&rv)) break; mix_pool_bytes(r, &rv, sizeof(rv), NULL); -- cgit v1.2.3-58-ga151 From a283b5c459784f9762a74c312b134e9a524f5a5f Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 10 Sep 2013 23:16:17 -0400 Subject: random: allow fractional bits to be tracked Allow fractional bits of entropy to be tracked by scaling the entropy counter (fixed point). This will be used in a subsequent patch that accounts for entropy lost due to overwrites. [ Modified by tytso to fix up a few missing places where the entropy_count wasn't properly converted from fractional bits to bits. ] Signed-off-by: H. Peter Anvin Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 138 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 46 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 20651a2fd8a7..c2957656c5bc 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -279,6 +279,15 @@ #define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long)) +/* + * To allow fractional bits to be tracked, the following fields contain + * this many fractional bits: + * + * entropy_count, trickle_thresh + */ +#define ENTROPY_SHIFT 3 +#define ENTROPY_BITS(r) ((r)->entropy_count >> ENTROPY_SHIFT) + /* * The minimum number of bits of entropy before we wake up a read on * /dev/random. Should be enough to do a significant reseed. @@ -296,8 +305,7 @@ static int random_write_wakeup_thresh = 128; * When the input pool goes over trickle_thresh, start dropping most * samples to avoid wasting CPU time and reduce lock contention. */ - -static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; +static const int trickle_thresh = (INPUT_POOL_WORDS * 28) << ENTROPY_SHIFT; static DEFINE_PER_CPU(int, trickle_count); @@ -311,8 +319,8 @@ static DEFINE_PER_CPU(int, trickle_count); */ static struct poolinfo { - int poolbitshift, poolwords, poolbytes, poolbits; -#define S(x) ilog2(x)+5, (x), (x)*4, (x)*32 + int poolbitshift, poolwords, poolbytes, poolbits, poolfracbits; +#define S(x) ilog2(x)+5, (x), (x)*4, (x)*32, (x) << (ENTROPY_SHIFT+5) int tap1, tap2, tap3, tap4, tap5; } poolinfo_table[] = { /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ @@ -581,7 +589,9 @@ static void fast_mix(struct fast_pool *f, const void *in, int nbytes) } /* - * Credit (or debit) the entropy store with n bits of entropy + * Credit (or debit) the entropy store with n bits of entropy. + * Use credit_entropy_bits_safe() if the value comes from userspace + * or otherwise should be checked for extreme values. */ static void credit_entropy_bits(struct entropy_store *r, int nbits) { @@ -593,13 +603,13 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); retry: entropy_count = orig = ACCESS_ONCE(r->entropy_count); - entropy_count += nbits; + entropy_count += nbits << ENTROPY_SHIFT; if (entropy_count < 0) { DEBUG_ENT("negative entropy/overflow\n"); entropy_count = 0; - } else if (entropy_count > r->poolinfo->poolbits) - entropy_count = r->poolinfo->poolbits; + } else if (entropy_count > r->poolinfo->poolfracbits) + entropy_count = r->poolinfo->poolfracbits; if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) goto retry; @@ -609,16 +619,29 @@ retry: r->initialized = 1; } - trace_credit_entropy_bits(r->name, nbits, entropy_count, + trace_credit_entropy_bits(r->name, nbits, + entropy_count >> ENTROPY_SHIFT, r->entropy_total, _RET_IP_); /* should we wake readers? */ - if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) { + if (r == &input_pool && + (entropy_count >> ENTROPY_SHIFT) >= random_read_wakeup_thresh) { wake_up_interruptible(&random_read_wait); kill_fasync(&fasync, SIGIO, POLL_IN); } } +static void credit_entropy_bits_safe(struct entropy_store *r, int nbits) +{ + const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1)); + + /* Cap the value to avoid overflows */ + nbits = min(nbits, nbits_max); + nbits = max(nbits, -nbits_max); + + credit_entropy_bits(r, nbits); +} + /********************************************************************* * * Entropy input management @@ -674,7 +697,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) preempt_disable(); /* if over the trickle threshold, use only 1 in 4096 samples */ - if (input_pool.entropy_count > trickle_thresh && + if (ENTROPY_BITS(&input_pool) > trickle_thresh && ((__this_cpu_inc_return(trickle_count) - 1) & 0xfff)) goto out; @@ -813,8 +836,9 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) { __u32 tmp[OUTPUT_POOL_WORDS]; - if (r->pull && r->entropy_count < nbytes * 8 && - r->entropy_count < r->poolinfo->poolbits) { + if (r->pull && + r->entropy_count < (nbytes << (ENTROPY_SHIFT + 3)) && + r->entropy_count < r->poolinfo->poolfracbits) { /* If we're limited, always leave two wakeup worth's BITS */ int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; int bytes = nbytes; @@ -826,7 +850,8 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) DEBUG_ENT("going to reseed %s with %d bits " "(%zu of %d requested)\n", - r->name, bytes * 8, nbytes * 8, r->entropy_count); + r->name, bytes * 8, nbytes * 8, + r->entropy_count >> ENTROPY_SHIFT); bytes = extract_entropy(r->pull, tmp, bytes, random_read_wakeup_thresh / 8, rsvd); @@ -852,41 +877,44 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, { unsigned long flags; int wakeup_write = 0; + int have_bytes; + int entropy_count, orig; + size_t ibytes; /* Hold lock while accounting */ spin_lock_irqsave(&r->lock, flags); - BUG_ON(r->entropy_count > r->poolinfo->poolbits); + BUG_ON(r->entropy_count > r->poolinfo->poolfracbits); DEBUG_ENT("trying to extract %zu bits from %s\n", nbytes * 8, r->name); /* Can we pull enough? */ - if (r->entropy_count / 8 < min + reserved) { - nbytes = 0; - } else { - int entropy_count, orig; retry: - entropy_count = orig = ACCESS_ONCE(r->entropy_count); + entropy_count = orig = ACCESS_ONCE(r->entropy_count); + have_bytes = entropy_count >> (ENTROPY_SHIFT + 3); + ibytes = nbytes; + if (have_bytes < min + reserved) { + ibytes = 0; + } else { /* If limited, never pull more than available */ - if (r->limit && nbytes + reserved >= entropy_count / 8) - nbytes = entropy_count/8 - reserved; - - if (entropy_count / 8 >= nbytes + reserved) { - entropy_count -= nbytes*8; - if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) - goto retry; - } else { - entropy_count = reserved; - if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) - goto retry; - } + if (r->limit && ibytes + reserved >= have_bytes) + ibytes = have_bytes - reserved; + + if (have_bytes >= ibytes + reserved) + entropy_count -= ibytes << (ENTROPY_SHIFT + 3); + else + entropy_count = reserved << (ENTROPY_SHIFT + 3); - if (entropy_count < random_write_wakeup_thresh) + if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) + goto retry; + + if ((r->entropy_count >> ENTROPY_SHIFT) + < random_write_wakeup_thresh) wakeup_write = 1; } DEBUG_ENT("debiting %zu entropy credits from %s%s\n", - nbytes * 8, r->name, r->limit ? "" : " (unlimited)"); + ibytes * 8, r->name, r->limit ? "" : " (unlimited)"); spin_unlock_irqrestore(&r->lock, flags); @@ -895,7 +923,7 @@ retry: kill_fasync(&fasync, SIGIO, POLL_OUT); } - return nbytes; + return ibytes; } static void extract_buf(struct entropy_store *r, __u8 *out) @@ -973,7 +1001,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, r->last_data_init = true; spin_unlock_irqrestore(&r->lock, flags); trace_extract_entropy(r->name, EXTRACT_SIZE, - r->entropy_count, _RET_IP_); + ENTROPY_BITS(r), _RET_IP_); xfer_secondary_pool(r, EXTRACT_SIZE); extract_buf(r, tmp); spin_lock_irqsave(&r->lock, flags); @@ -982,7 +1010,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, spin_unlock_irqrestore(&r->lock, flags); } - trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_); + trace_extract_entropy(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_); xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, min, reserved); @@ -1015,7 +1043,7 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, ssize_t ret = 0, i; __u8 tmp[EXTRACT_SIZE]; - trace_extract_entropy_user(r->name, nbytes, r->entropy_count, _RET_IP_); + trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_); xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, 0, 0); @@ -1187,8 +1215,8 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) DEBUG_ENT("sleeping?\n"); wait_event_interruptible(random_read_wait, - input_pool.entropy_count >= - random_read_wakeup_thresh); + ENTROPY_BITS(&input_pool) >= + random_read_wakeup_thresh); DEBUG_ENT("awake\n"); @@ -1224,9 +1252,9 @@ random_poll(struct file *file, poll_table * wait) poll_wait(file, &random_read_wait, wait); poll_wait(file, &random_write_wait, wait); mask = 0; - if (input_pool.entropy_count >= random_read_wakeup_thresh) + if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_thresh) mask |= POLLIN | POLLRDNORM; - if (input_pool.entropy_count < random_write_wakeup_thresh) + if (ENTROPY_BITS(&input_pool) < random_write_wakeup_thresh) mask |= POLLOUT | POLLWRNORM; return mask; } @@ -1277,7 +1305,8 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) switch (cmd) { case RNDGETENTCNT: /* inherently racy, no point locking */ - if (put_user(input_pool.entropy_count, p)) + ent_count = ENTROPY_BITS(&input_pool); + if (put_user(ent_count, p)) return -EFAULT; return 0; case RNDADDTOENTCNT: @@ -1285,7 +1314,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) return -EPERM; if (get_user(ent_count, p)) return -EFAULT; - credit_entropy_bits(&input_pool, ent_count); + credit_entropy_bits_safe(&input_pool, ent_count); return 0; case RNDADDENTROPY: if (!capable(CAP_SYS_ADMIN)) @@ -1300,7 +1329,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) size); if (retval < 0) return retval; - credit_entropy_bits(&input_pool, ent_count); + credit_entropy_bits_safe(&input_pool, ent_count); return 0; case RNDZAPENTCNT: case RNDCLEARPOOL: @@ -1407,6 +1436,23 @@ static int proc_do_uuid(struct ctl_table *table, int write, return proc_dostring(&fake_table, write, buffer, lenp, ppos); } +/* + * Return entropy available scaled to integral bits + */ +static int proc_do_entropy(ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + ctl_table fake_table; + int entropy_count; + + entropy_count = *(int *)table->data >> ENTROPY_SHIFT; + + fake_table.data = &entropy_count; + fake_table.maxlen = sizeof(entropy_count); + + return proc_dointvec(&fake_table, write, buffer, lenp, ppos); +} + static int sysctl_poolsize = INPUT_POOL_WORDS * 32; extern struct ctl_table random_table[]; struct ctl_table random_table[] = { @@ -1421,7 +1467,7 @@ struct ctl_table random_table[] = { .procname = "entropy_avail", .maxlen = sizeof(int), .mode = 0444, - .proc_handler = proc_dointvec, + .proc_handler = proc_do_entropy, .data = &input_pool.entropy_count, }, { -- cgit v1.2.3-58-ga151 From 30e37ec516ae5a6957596de7661673c615c82ea4 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 10 Sep 2013 23:16:17 -0400 Subject: random: account for entropy loss due to overwrites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we write entropy into a non-empty pool, we currently don't account at all for the fact that we will probabilistically overwrite some of the entropy in that pool. This means that unless the pool is fully empty, we are currently *guaranteed* to overestimate the amount of entropy in the pool! Assuming Shannon entropy with zero correlations we end up with an exponentally decaying value of new entropy added: entropy <- entropy + (pool_size - entropy) * (1 - exp(-add_entropy/pool_size)) However, calculations involving fractional exponentials are not practical in the kernel, so apply a piecewise linearization: For add_entropy <= pool_size/2 then (1 - exp(-add_entropy/pool_size)) >= (add_entropy/pool_size)*0.7869... ... so we can approximate the exponential with 3/4*add_entropy/pool_size and still be on the safe side by adding at most pool_size/2 at a time. In order for the loop not to take arbitrary amounts of time if a bad ioctl is received, terminate if we are within one bit of full. This way the loop is guaranteed to terminate after no more than log2(poolsize) iterations, no matter what the input value is. The vast majority of the time the loop will be executed exactly once. The piecewise linearization is very conservative, approaching 3/4 of the usable input value for small inputs, however, our entropy estimation is pretty weak at best, especially for small values; we have no handle on correlation; and the Shannon entropy measure (Rényi entropy of order 1) is not the correct one to use in the first place, but rather the correct entropy measure is the min-entropy, the Rényi entropy of infinite order. As such, this conservatism seems more than justified. This does introduce fractional bit values. I have left it to have 3 bits of fraction, so that with a pool of 2^12 bits the multiply in credit_entropy_bits() can still fit into an int, as 2*(3+12) < 31. It is definitely possible to allow for more fractional accounting, but that multiply then would have to be turned into a 32*32 -> 64 multiply. Signed-off-by: H. Peter Anvin Signed-off-by: Theodore Ts'o Cc: DJ Johnston --- drivers/char/random.c | 60 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index c2957656c5bc..867b823e7fea 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -272,10 +272,12 @@ /* * Configuration information */ -#define INPUT_POOL_WORDS 128 -#define OUTPUT_POOL_WORDS 32 -#define SEC_XFER_SIZE 512 -#define EXTRACT_SIZE 10 +#define INPUT_POOL_SHIFT 12 +#define INPUT_POOL_WORDS (1 << (INPUT_POOL_SHIFT-5)) +#define OUTPUT_POOL_SHIFT 10 +#define OUTPUT_POOL_WORDS (1 << (OUTPUT_POOL_SHIFT-5)) +#define SEC_XFER_SIZE 512 +#define EXTRACT_SIZE 10 #define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long)) @@ -284,6 +286,9 @@ * this many fractional bits: * * entropy_count, trickle_thresh + * + * 2*(ENTROPY_SHIFT + log2(poolbits)) must <= 31, or the multiply in + * credit_entropy_bits() needs to be 64 bits wide. */ #define ENTROPY_SHIFT 3 #define ENTROPY_BITS(r) ((r)->entropy_count >> ENTROPY_SHIFT) @@ -427,7 +432,7 @@ module_param(debug, bool, 0644); struct entropy_store; struct entropy_store { /* read-only data: */ - struct poolinfo *poolinfo; + const struct poolinfo *poolinfo; __u32 *pool; const char *name; struct entropy_store *pull; @@ -596,6 +601,8 @@ static void fast_mix(struct fast_pool *f, const void *in, int nbytes) static void credit_entropy_bits(struct entropy_store *r, int nbits) { int entropy_count, orig; + const int pool_size = r->poolinfo->poolfracbits; + int nfrac = nbits << ENTROPY_SHIFT; if (!nbits) return; @@ -603,13 +610,50 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); retry: entropy_count = orig = ACCESS_ONCE(r->entropy_count); - entropy_count += nbits << ENTROPY_SHIFT; + if (nfrac < 0) { + /* Debit */ + entropy_count += nfrac; + } else { + /* + * Credit: we have to account for the possibility of + * overwriting already present entropy. Even in the + * ideal case of pure Shannon entropy, new contributions + * approach the full value asymptotically: + * + * entropy <- entropy + (pool_size - entropy) * + * (1 - exp(-add_entropy/pool_size)) + * + * For add_entropy <= pool_size/2 then + * (1 - exp(-add_entropy/pool_size)) >= + * (add_entropy/pool_size)*0.7869... + * so we can approximate the exponential with + * 3/4*add_entropy/pool_size and still be on the + * safe side by adding at most pool_size/2 at a time. + * + * The use of pool_size-2 in the while statement is to + * prevent rounding artifacts from making the loop + * arbitrarily long; this limits the loop to log2(pool_size)*2 + * turns no matter how large nbits is. + */ + int pnfrac = nfrac; + const int s = r->poolinfo->poolbitshift + ENTROPY_SHIFT + 2; + /* The +2 corresponds to the /4 in the denominator */ + + do { + unsigned int anfrac = min(pnfrac, pool_size/2); + unsigned int add = + ((pool_size - entropy_count)*anfrac*3) >> s; + + entropy_count += add; + pnfrac -= anfrac; + } while (unlikely(entropy_count < pool_size-2 && pnfrac)); + } if (entropy_count < 0) { DEBUG_ENT("negative entropy/overflow\n"); entropy_count = 0; - } else if (entropy_count > r->poolinfo->poolfracbits) - entropy_count = r->poolinfo->poolfracbits; + } else if (entropy_count > pool_size) + entropy_count = pool_size; if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) goto retry; -- cgit v1.2.3-58-ga151 From 5910895f0e868d4f70303922ed00ccdc328b3c30 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 12 Sep 2013 14:10:25 -0400 Subject: random: fix the tracepoint for get_random_bytes(_arch) Fix a problem where get_random_bytes_arch() was calling the tracepoint get_random_bytes(). So add a new tracepoint for get_random_bytes_arch(), and make get_random_bytes() and get_random_bytes_arch() call their correct tracepoint. Also, add a new tracepoint for add_device_randomness() Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 4 +++- include/trace/events/random.h | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 867b823e7fea..80b58774e891 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -711,6 +711,7 @@ void add_device_randomness(const void *buf, unsigned int size) { unsigned long time = random_get_entropy() ^ jiffies; + trace_add_device_randomness(size, _RET_IP_); 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); @@ -1127,6 +1128,7 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, */ void get_random_bytes(void *buf, int nbytes) { + trace_get_random_bytes(nbytes, _RET_IP_); extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0); } EXPORT_SYMBOL(get_random_bytes); @@ -1145,7 +1147,7 @@ void get_random_bytes_arch(void *buf, int nbytes) { char *p = buf; - trace_get_random_bytes(nbytes, _RET_IP_); + trace_get_random_bytes_arch(nbytes, _RET_IP_); while (nbytes) { unsigned long v; int chunk = min(nbytes, (int)sizeof(unsigned long)); diff --git a/include/trace/events/random.h b/include/trace/events/random.h index 422df19de732..2ffcaec5860a 100644 --- a/include/trace/events/random.h +++ b/include/trace/events/random.h @@ -7,6 +7,25 @@ #include #include +TRACE_EVENT(add_device_randomness, + TP_PROTO(int bytes, unsigned long IP), + + TP_ARGS(bytes, IP), + + TP_STRUCT__entry( + __field( int, bytes ) + __field(unsigned long, IP ) + ), + + TP_fast_assign( + __entry->bytes = bytes; + __entry->IP = IP; + ), + + TP_printk("bytes %d caller %pF", + __entry->bytes, (void *)__entry->IP) +); + DECLARE_EVENT_CLASS(random__mix_pool_bytes, TP_PROTO(const char *pool_name, int bytes, unsigned long IP), @@ -68,7 +87,7 @@ TRACE_EVENT(credit_entropy_bits, (void *)__entry->IP) ); -TRACE_EVENT(get_random_bytes, +DECLARE_EVENT_CLASS(random__get_random_bytes, TP_PROTO(int nbytes, unsigned long IP), TP_ARGS(nbytes, IP), @@ -86,6 +105,18 @@ TRACE_EVENT(get_random_bytes, TP_printk("nbytes %d caller %pF", __entry->nbytes, (void *)__entry->IP) ); +DEFINE_EVENT(random__get_random_bytes, get_random_bytes, + TP_PROTO(int nbytes, unsigned long IP), + + TP_ARGS(nbytes, IP) +); + +DEFINE_EVENT(random__get_random_bytes, get_random_bytes_arch, + TP_PROTO(int nbytes, unsigned long IP), + + TP_ARGS(nbytes, IP) +); + DECLARE_EVENT_CLASS(random__extract_entropy, TP_PROTO(const char *pool_name, int nbytes, int entropy_count, unsigned long IP), -- cgit v1.2.3-58-ga151 From 3ef4cb2d65ee13d84140cbede8e1980c6ae49ffd Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 12 Sep 2013 14:27:22 -0400 Subject: random: optimize spinlock use in add_device_randomness() The add_device_randomness() function calls mix_pool_bytes() twice for the input pool and the non-blocking pool, for a total of four times. By using _mix_pool_byte() and taking the spinlock in add_device_randomness(), we can halve the number of times we need take each pool's spinlock. Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 80b58774e891..89eb5a8dec82 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -710,12 +710,18 @@ struct timer_rand_state { void add_device_randomness(const void *buf, unsigned int size) { unsigned long time = random_get_entropy() ^ jiffies; + unsigned long flags; trace_add_device_randomness(size, _RET_IP_); - 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); + spin_lock_irqsave(&input_pool.lock, flags); + _mix_pool_bytes(&input_pool, buf, size, NULL); + _mix_pool_bytes(&input_pool, &time, sizeof(time), NULL); + spin_unlock_irqrestore(&input_pool.lock, flags); + + spin_lock_irqsave(&nonblocking_pool.lock, flags); + _mix_pool_bytes(&nonblocking_pool, buf, size, NULL); + _mix_pool_bytes(&nonblocking_pool, &time, sizeof(time), NULL); + spin_unlock_irqrestore(&nonblocking_pool.lock, flags); } EXPORT_SYMBOL(add_device_randomness); -- cgit v1.2.3-58-ga151 From c59974aea43fd292a0784dbf7b3d7347e2caf4e9 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 21 Sep 2013 19:42:41 -0400 Subject: random: optimize the entropy_store structure Use smaller types to slightly shrink the size of the entropy store structure. Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 89eb5a8dec82..b8809d4ae186 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -436,16 +436,16 @@ struct entropy_store { __u32 *pool; const char *name; struct entropy_store *pull; - int limit; /* read-write data: */ spinlock_t lock; - unsigned add_ptr; - unsigned input_rotate; + unsigned short add_ptr; + unsigned short input_rotate; int entropy_count; int entropy_total; unsigned int initialized:1; - bool last_data_init; + unsigned int limit:1; + unsigned int last_data_init:1; __u8 last_data[EXTRACT_SIZE]; }; @@ -513,7 +513,7 @@ static void _mix_pool_bytes(struct entropy_store *r, const void *in, /* mix one byte at a time to simplify size handling and churn faster */ while (nbytes--) { - w = rol32(*bytes++, input_rotate & 31); + w = rol32(*bytes++, input_rotate); i = (i - 1) & wordmask; /* XOR in the various taps */ @@ -533,7 +533,7 @@ static void _mix_pool_bytes(struct entropy_store *r, const void *in, * rotation, so that successive passes spread the * input bits across the pool evenly. */ - input_rotate += i ? 7 : 14; + input_rotate = (input_rotate + (i ? 7 : 14)) & 31; } ACCESS_ONCE(r->input_rotate) = input_rotate; @@ -1049,7 +1049,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, if (fips_enabled) { spin_lock_irqsave(&r->lock, flags); if (!r->last_data_init) { - r->last_data_init = true; + r->last_data_init = 1; spin_unlock_irqrestore(&r->lock, flags); trace_extract_entropy(r->name, EXTRACT_SIZE, ENTROPY_BITS(r), _RET_IP_); @@ -1189,7 +1189,7 @@ static void init_std_data(struct entropy_store *r) r->entropy_count = 0; r->entropy_total = 0; - r->last_data_init = false; + r->last_data_init = 0; mix_pool_bytes(r, &now, sizeof(now), NULL); for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) { if (!arch_get_random_long(&rv)) -- cgit v1.2.3-58-ga151 From f5c2742c23886e707f062881c5f206c1fc704782 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 22 Sep 2013 15:14:32 -0400 Subject: random: cap the rate which the /dev/urandom pool gets reseeded In order to avoid draining the input pool of its entropy at too high of a rate, enforce a minimum time interval between reseedings of the urandom pool. This is set to 60 seconds by default. Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/char/random.c b/drivers/char/random.c index b8809d4ae186..a68b4a093272 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -306,6 +306,13 @@ static int random_read_wakeup_thresh = 64; */ static int random_write_wakeup_thresh = 128; +/* + * The minimum number of seconds between urandom pool resending. We + * do this to limit the amount of entropy that can be drained from the + * input pool even if there are heavy demands on /dev/urandom. + */ +static int random_min_urandom_seed = 60; + /* * When the input pool goes over trickle_thresh, start dropping most * samples to avoid wasting CPU time and reduce lock contention. @@ -438,6 +445,7 @@ struct entropy_store { struct entropy_store *pull; /* read-write data: */ + unsigned long last_pulled; spinlock_t lock; unsigned short add_ptr; unsigned short input_rotate; @@ -887,6 +895,14 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) { __u32 tmp[OUTPUT_POOL_WORDS]; + if (r->limit == 0 && random_min_urandom_seed) { + unsigned long now = jiffies; + + if (time_before(now, + r->last_pulled + random_min_urandom_seed * HZ)) + return; + r->last_pulled = now; + } if (r->pull && r->entropy_count < (nbytes << (ENTROPY_SHIFT + 3)) && r->entropy_count < r->poolinfo->poolfracbits) { @@ -1190,6 +1206,7 @@ static void init_std_data(struct entropy_store *r) r->entropy_count = 0; r->entropy_total = 0; r->last_data_init = 0; + r->last_pulled = jiffies; mix_pool_bytes(r, &now, sizeof(now), NULL); for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) { if (!arch_get_random_long(&rv)) @@ -1540,6 +1557,13 @@ struct ctl_table random_table[] = { .extra1 = &min_write_thresh, .extra2 = &max_write_thresh, }, + { + .procname = "urandom_min_reseed_secs", + .data = &random_min_urandom_seed, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, { .procname = "boot_id", .data = &sysctl_bootid, -- cgit v1.2.3-58-ga151 From 655b226470b229552ad95b21323864df9bd9fc74 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 22 Sep 2013 15:24:02 -0400 Subject: random: speed up the fast_mix function by a factor of four MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By mixing the entropy in chunks of 32-bit words instead of byte by byte, we can speed up the fast_mix function significantly. Since it is called on every single interrupt, on systems with a very heavy interrupt load, this can make a noticeable difference. Also fix a compilation warning in add_interrupt_randomness() and avoid xor'ing cycles and jiffies together just in case we have an architecture which tries to define random_get_entropy() by returning jiffies. Signed-off-by: "Theodore Ts'o" Reported-by: Jörn Engel --- drivers/char/random.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index a68b4a093272..74eeec58e779 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -584,21 +584,26 @@ struct fast_pool { * collector. It's hardcoded for an 128 bit pool and assumes that any * locks that might be needed are taken by the caller. */ -static void fast_mix(struct fast_pool *f, const void *in, int nbytes) +static void fast_mix(struct fast_pool *f, __u32 input[4]) { - const char *bytes = in; __u32 w; - unsigned i = f->count; unsigned input_rotate = f->rotate; - while (nbytes--) { - w = rol32(*bytes++, input_rotate & 31) ^ f->pool[i & 3] ^ - f->pool[(i + 1) & 3]; - f->pool[i & 3] = (w >> 3) ^ twist_table[w & 7]; - input_rotate += (i++ & 3) ? 7 : 14; - } - f->count = i; + w = rol32(input[0], input_rotate) ^ f->pool[0] ^ f->pool[3]; + f->pool[0] = (w >> 3) ^ twist_table[w & 7]; + input_rotate = (input_rotate + 14) & 31; + w = rol32(input[1], input_rotate) ^ f->pool[1] ^ f->pool[0]; + f->pool[1] = (w >> 3) ^ twist_table[w & 7]; + input_rotate = (input_rotate + 7) & 31; + w = rol32(input[2], input_rotate) ^ f->pool[2] ^ f->pool[1]; + f->pool[2] = (w >> 3) ^ twist_table[w & 7]; + input_rotate = (input_rotate + 7) & 31; + w = rol32(input[3], input_rotate) ^ f->pool[3] ^ f->pool[2]; + f->pool[3] = (w >> 3) ^ twist_table[w & 7]; + input_rotate = (input_rotate + 7) & 31; + f->rotate = input_rotate; + f->count++; } /* @@ -828,20 +833,21 @@ void add_interrupt_randomness(int irq, int irq_flags) struct fast_pool *fast_pool = &__get_cpu_var(irq_randomness); struct pt_regs *regs = get_irq_regs(); unsigned long now = jiffies; - __u32 input[4], cycles = random_get_entropy(); - - input[0] = cycles ^ jiffies; - input[1] = irq; - if (regs) { - __u64 ip = instruction_pointer(regs); - input[2] = ip; - input[3] = ip >> 32; - } + cycles_t cycles = random_get_entropy(); + __u32 input[4], c_high, j_high; + __u64 ip; + + c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0; + j_high = (sizeof(now) > 4) ? now >> 32 : 0; + input[0] = cycles ^ j_high ^ irq; + input[1] = now ^ c_high; + ip = regs ? instruction_pointer(regs) : _RET_IP_; + input[2] = ip; + input[3] = ip >> 32; - fast_mix(fast_pool, input, sizeof(input)); + fast_mix(fast_pool, input); - if ((fast_pool->count & 1023) && - !time_after(now, fast_pool->last + HZ)) + if ((fast_pool->count & 63) && !time_after(now, fast_pool->last + HZ)) return; fast_pool->last = now; -- cgit v1.2.3-58-ga151 From 6e9fa2c8a630e6d0882828012431038abce285b9 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 22 Sep 2013 16:04:19 -0400 Subject: random: adjust the generator polynomials in the mixing function slightly Our mixing functions were analyzed by Lacharme, Roeck, Strubel, and Videau in their paper, "The Linux Pseudorandom Number Generator Revisited" (see: http://eprint.iacr.org/2012/251.pdf). They suggested a slight change to improve our mixing functions slightly. I also adjusted the comments to better explain what is going on, and to document why the polynomials were changed. Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 103 ++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 54 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 74eeec58e779..7ae7ea65da68 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -322,23 +322,61 @@ static const int trickle_thresh = (INPUT_POOL_WORDS * 28) << ENTROPY_SHIFT; static DEFINE_PER_CPU(int, trickle_count); /* - * A pool of size .poolwords is stirred with a primitive polynomial - * of degree .poolwords over GF(2). The taps for various sizes are - * defined below. They are chosen to be evenly spaced (minimum RMS - * distance from evenly spaced; the numbers in the comments are a - * scaled squared error sum) except for the last tap, which is 1 to - * get the twisting happening as fast as possible. + * Originally, we used a primitive polynomial of degree .poolwords + * over GF(2). The taps for various sizes are defined below. They + * were chosen to be evenly spaced except for the last tap, which is 1 + * to get the twisting happening as fast as possible. + * + * For the purposes of better mixing, we use the CRC-32 polynomial as + * well to make a (modified) twisted Generalized Feedback Shift + * Register. (See M. Matsumoto & Y. Kurita, 1992. Twisted GFSR + * generators. ACM Transactions on Modeling and Computer Simulation + * 2(3):179-194. Also see M. Matsumoto & Y. Kurita, 1994. Twisted + * GFSR generators II. ACM Transactions on Mdeling and Computer + * Simulation 4:254-266) + * + * Thanks to Colin Plumb for suggesting this. + * + * The mixing operation is much less sensitive than the output hash, + * where we use SHA-1. All that we want of mixing operation 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 + * decrease the uncertainty). + * + * Our mixing functions were analyzed by Lacharme, Roeck, Strubel, and + * Videau in their paper, "The Linux Pseudorandom Number Generator + * Revisited" (see: http://eprint.iacr.org/2012/251.pdf). In their + * paper, they point out that we are not using a true Twisted GFSR, + * since Matsumoto & Kurita used a trinomial feedback polynomial (that + * is, with only three taps, instead of the six that we are using). + * As a result, the resulting polynomial is neither primitive nor + * irreducible, and hence does not have a maximal period over + * GF(2**32). They suggest a slight change to the generator + * polynomial which improves the resulting TGFSR polynomial to be + * irreducible, which we have made here. */ - static struct poolinfo { int poolbitshift, poolwords, poolbytes, poolbits, poolfracbits; #define S(x) ilog2(x)+5, (x), (x)*4, (x)*32, (x) << (ENTROPY_SHIFT+5) int tap1, tap2, tap3, tap4, tap5; } poolinfo_table[] = { - /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ - { S(128), 103, 76, 51, 25, 1 }, - /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */ - { S(32), 26, 20, 14, 7, 1 }, + /* was: x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 */ + /* x^128 + x^104 + x^76 + x^51 +x^25 + x + 1 */ + { S(128), 104, 76, 51, 25, 1 }, + /* was: x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 */ + /* x^32 + x^26 + x^19 + x^14 + x^7 + x + 1 */ + { S(32), 26, 19, 14, 7, 1 }, #if 0 /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ { S(2048), 1638, 1231, 819, 411, 1 }, @@ -368,49 +406,6 @@ static struct poolinfo { #endif }; -/* - * For the purposes of better mixing, we use the CRC-32 polynomial as - * well to make a twisted Generalized Feedback Shift Reigster - * - * (See M. Matsumoto & Y. Kurita, 1992. Twisted GFSR generators. ACM - * Transactions on Modeling and Computer Simulation 2(3):179-194. - * Also see M. Matsumoto & Y. Kurita, 1994. Twisted GFSR generators - * II. ACM Transactions on Mdeling and Computer Simulation 4:254-266) - * - * Thanks to Colin Plumb for suggesting this. - * - * We have not analyzed the resultant polynomial to prove it primitive; - * 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 - * 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 - * 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 - * hash; hash collisions will occur no more often than chance. - */ - /* * Static global variables */ -- cgit v1.2.3-58-ga151 From 95b709b6be49e4ff3933ef6a5b5e623de2713a71 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 2 Oct 2013 21:10:35 -0400 Subject: random: drop trickle mode The add_timer_randomness() used to drop into trickle mode when entropy pool was estimated to be 87.5% full. This was important when add_timer_randomness() was used to sample interrupts. It's not used for this any more --- add_interrupt_randomness() now uses fast_mix() instead. By elimitating trickle mode, it allows us to fully utilize entropy provided by add_input_randomness() and add_disk_randomness() even when the input pool is above the old trickle threshold of 87.5%. This helps to answer the criticism in [1] in their hypothetical scenario where our entropy estimator was inaccurate, even though the measurements in [2] seem to indicate that our entropy estimator given real-life entropy collection is actually pretty good, albeit on the conservative side (which was as it was designed). [1] http://eprint.iacr.org/2013/338.pdf [2] http://eprint.iacr.org/2012/251.pdf Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 7ae7ea65da68..6da3f250804c 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -282,10 +282,8 @@ #define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long)) /* - * To allow fractional bits to be tracked, the following fields contain - * this many fractional bits: - * - * entropy_count, trickle_thresh + * To allow fractional bits to be tracked, the entropy_count field is + * denominated in units of 1/8th bits. * * 2*(ENTROPY_SHIFT + log2(poolbits)) must <= 31, or the multiply in * credit_entropy_bits() needs to be 64 bits wide. @@ -313,14 +311,6 @@ static int random_write_wakeup_thresh = 128; */ static int random_min_urandom_seed = 60; -/* - * When the input pool goes over trickle_thresh, start dropping most - * samples to avoid wasting CPU time and reduce lock contention. - */ -static const int trickle_thresh = (INPUT_POOL_WORDS * 28) << ENTROPY_SHIFT; - -static DEFINE_PER_CPU(int, trickle_count); - /* * Originally, we used a primitive polynomial of degree .poolwords * over GF(2). The taps for various sizes are defined below. They @@ -755,10 +745,6 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) long delta, delta2, delta3; preempt_disable(); - /* if over the trickle threshold, use only 1 in 4096 samples */ - if (ENTROPY_BITS(&input_pool) > trickle_thresh && - ((__this_cpu_inc_return(trickle_count) - 1) & 0xfff)) - goto out; sample.jiffies = jiffies; sample.cycles = random_get_entropy(); @@ -800,7 +786,6 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) credit_entropy_bits(&input_pool, min_t(int, fls(delta>>1), 11)); } -out: preempt_enable(); } -- cgit v1.2.3-58-ga151 From 6265e169cd313d6f3aad3c33d0a5b0d9624f69f5 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 3 Oct 2013 01:08:15 -0400 Subject: random: push extra entropy to the output pools As the input pool gets filled, start transfering entropy to the output pools until they get filled. This allows us to use the output pools to store more system entropy. Waste not, want not.... Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 118 ++++++++++++++++++++++++++++++------------ include/trace/events/random.h | 22 ++++++++ 2 files changed, 108 insertions(+), 32 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 6da3f250804c..84c576ec20e9 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -255,6 +255,7 @@ #include #include #include +#include #ifdef CONFIG_GENERIC_HARDIRQS # include @@ -302,7 +303,7 @@ static int random_read_wakeup_thresh = 64; * should wake up processes which are selecting or polling on write * access to /dev/random. */ -static int random_write_wakeup_thresh = 128; +static int random_write_wakeup_thresh = 28 * OUTPUT_POOL_WORDS; /* * The minimum number of seconds between urandom pool resending. We @@ -428,6 +429,7 @@ struct entropy_store { __u32 *pool; const char *name; struct entropy_store *pull; + struct work_struct push_work; /* read-write data: */ unsigned long last_pulled; @@ -442,6 +444,7 @@ struct entropy_store { __u8 last_data[EXTRACT_SIZE]; }; +static void push_to_pool(struct work_struct *work); static __u32 input_pool_data[INPUT_POOL_WORDS]; static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; @@ -460,7 +463,9 @@ static struct entropy_store blocking_pool = { .limit = 1, .pull = &input_pool, .lock = __SPIN_LOCK_UNLOCKED(blocking_pool.lock), - .pool = blocking_pool_data + .pool = blocking_pool_data, + .push_work = __WORK_INITIALIZER(blocking_pool.push_work, + push_to_pool), }; static struct entropy_store nonblocking_pool = { @@ -468,7 +473,9 @@ static struct entropy_store nonblocking_pool = { .name = "nonblocking", .pull = &input_pool, .lock = __SPIN_LOCK_UNLOCKED(nonblocking_pool.lock), - .pool = nonblocking_pool_data + .pool = nonblocking_pool_data, + .push_work = __WORK_INITIALIZER(nonblocking_pool.push_work, + push_to_pool), }; static __u32 const twist_table[8] = { @@ -655,21 +662,48 @@ retry: if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) goto retry; + r->entropy_total += nbits; if (!r->initialized && nbits > 0) { - r->entropy_total += nbits; - if (r->entropy_total > 128) + if (r->entropy_total > 128) { r->initialized = 1; + r->entropy_total = 0; + } } trace_credit_entropy_bits(r->name, nbits, entropy_count >> ENTROPY_SHIFT, r->entropy_total, _RET_IP_); - /* should we wake readers? */ - if (r == &input_pool && - (entropy_count >> ENTROPY_SHIFT) >= random_read_wakeup_thresh) { - wake_up_interruptible(&random_read_wait); - kill_fasync(&fasync, SIGIO, POLL_IN); + if (r == &input_pool) { + int entropy_bytes = entropy_count >> ENTROPY_SHIFT; + + /* should we wake readers? */ + if (entropy_bytes >= random_read_wakeup_thresh) { + wake_up_interruptible(&random_read_wait); + kill_fasync(&fasync, SIGIO, POLL_IN); + } + /* If the input pool is getting full, send some + * entropy to the two output pools, flipping back and + * forth between them, until the output pools are 75% + * full. + */ + if (entropy_bytes > random_write_wakeup_thresh && + r->initialized && + r->entropy_total >= 2*random_read_wakeup_thresh) { + static struct entropy_store *last = &blocking_pool; + struct entropy_store *other = &blocking_pool; + + if (last == &blocking_pool) + other = &nonblocking_pool; + if (other->entropy_count <= + 3 * other->poolinfo->poolfracbits / 4) + last = other; + if (last->entropy_count <= + 3 * last->poolinfo->poolfracbits / 4) { + schedule_work(&last->push_work); + r->entropy_total = 0; + } + } } } @@ -877,10 +911,9 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, * from the primary pool to the secondary extraction pool. We make * sure we pull enough for a 'catastrophic reseed'. */ +static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes); static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) { - __u32 tmp[OUTPUT_POOL_WORDS]; - if (r->limit == 0 && random_min_urandom_seed) { unsigned long now = jiffies; @@ -891,26 +924,47 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) } if (r->pull && r->entropy_count < (nbytes << (ENTROPY_SHIFT + 3)) && - r->entropy_count < r->poolinfo->poolfracbits) { - /* If we're limited, always leave two wakeup worth's BITS */ - int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; - int bytes = nbytes; - - /* pull at least as many as BYTES as wakeup BITS */ - bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); - /* but never more than the buffer size */ - bytes = min_t(int, bytes, sizeof(tmp)); - - DEBUG_ENT("going to reseed %s with %d bits " - "(%zu of %d requested)\n", - r->name, bytes * 8, nbytes * 8, - r->entropy_count >> ENTROPY_SHIFT); - - bytes = extract_entropy(r->pull, tmp, bytes, - random_read_wakeup_thresh / 8, rsvd); - mix_pool_bytes(r, tmp, bytes, NULL); - credit_entropy_bits(r, bytes*8); - } + r->entropy_count < r->poolinfo->poolfracbits) + _xfer_secondary_pool(r, nbytes); +} + +static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes) +{ + __u32 tmp[OUTPUT_POOL_WORDS]; + + /* For /dev/random's pool, always leave two wakeup worth's BITS */ + int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; + int bytes = nbytes; + + /* pull at least as many as BYTES as wakeup BITS */ + bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); + /* but never more than the buffer size */ + bytes = min_t(int, bytes, sizeof(tmp)); + + DEBUG_ENT("going to reseed %s with %d bits (%zu of %d requested)\n", + r->name, bytes * 8, nbytes * 8, + r->entropy_count >> ENTROPY_SHIFT); + + bytes = extract_entropy(r->pull, tmp, bytes, + random_read_wakeup_thresh / 8, rsvd); + mix_pool_bytes(r, tmp, bytes, NULL); + credit_entropy_bits(r, bytes*8); +} + +/* + * Used as a workqueue function so that when the input pool is getting + * full, we can "spill over" some entropy to the output pools. That + * way the output pools can store some of the excess entropy instead + * of letting it go to waste. + */ +static void push_to_pool(struct work_struct *work) +{ + struct entropy_store *r = container_of(work, struct entropy_store, + push_work); + BUG_ON(!r); + _xfer_secondary_pool(r, random_read_wakeup_thresh/8); + trace_push_to_pool(r->name, r->entropy_count >> ENTROPY_SHIFT, + r->pull->entropy_count >> ENTROPY_SHIFT); } /* diff --git a/include/trace/events/random.h b/include/trace/events/random.h index 2ffcaec5860a..527b5dc1b416 100644 --- a/include/trace/events/random.h +++ b/include/trace/events/random.h @@ -87,6 +87,28 @@ TRACE_EVENT(credit_entropy_bits, (void *)__entry->IP) ); +TRACE_EVENT(push_to_pool, + TP_PROTO(const char *pool_name, int pool_bits, int input_bits), + + TP_ARGS(pool_name, pool_bits, input_bits), + + TP_STRUCT__entry( + __field( const char *, pool_name ) + __field( int, pool_bits ) + __field( int, input_bits ) + ), + + TP_fast_assign( + __entry->pool_name = pool_name; + __entry->pool_bits = pool_bits; + __entry->input_bits = input_bits; + ), + + TP_printk("%s: pool_bits %d input_pool_bits %d", + __entry->pool_name, __entry->pool_bits, + __entry->input_bits) +); + DECLARE_EVENT_CLASS(random__get_random_bytes, TP_PROTO(int nbytes, unsigned long IP), -- cgit v1.2.3-58-ga151 From f80bbd8b92987f55f26691cd53785c4a54622eb0 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 3 Oct 2013 12:02:37 -0400 Subject: random: convert DEBUG_ENT to tracepoints Instead of using the random driver's ad-hoc DEBUG_ENT() mechanism, use tracepoints instead. This allows for a much more fine-grained control of which debugging mechanism which a developer might need, and unifies the debugging messages with all of the existing tracepoints. Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 52 ++++++----------- include/trace/events/random.h | 128 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 36 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 84c576ec20e9..f126bd2f69fe 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -404,17 +404,6 @@ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); static struct fasync_struct *fasync; -static bool debug; -module_param(debug, bool, 0644); -#define DEBUG_ENT(fmt, arg...) do { \ - if (debug) \ - printk(KERN_DEBUG "random %04d %04d %04d: " \ - fmt,\ - input_pool.entropy_count,\ - blocking_pool.entropy_count,\ - nonblocking_pool.entropy_count,\ - ## arg); } while (0) - /********************************************************************** * * OS independent entropy store. Here are the functions which handle @@ -612,7 +601,6 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) if (!nbits) return; - DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); retry: entropy_count = orig = ACCESS_ONCE(r->entropy_count); if (nfrac < 0) { @@ -655,7 +643,9 @@ retry: } if (entropy_count < 0) { - DEBUG_ENT("negative entropy/overflow\n"); + pr_warn("random: negative entropy/overflow: pool %s count %d\n", + r->name, entropy_count); + WARN_ON(1); entropy_count = 0; } else if (entropy_count > pool_size) entropy_count = pool_size; @@ -832,10 +822,10 @@ void add_input_randomness(unsigned int type, unsigned int code, if (value == last_value) return; - DEBUG_ENT("input event\n"); last_value = value; add_timer_randomness(&input_timer_state, (type << 4) ^ code ^ (code >> 4) ^ value); + trace_add_input_randomness(ENTROPY_BITS(&input_pool)); } EXPORT_SYMBOL_GPL(add_input_randomness); @@ -890,10 +880,8 @@ void add_disk_randomness(struct gendisk *disk) if (!disk || !disk->random) return; /* first major is 1, so we get >= 0x200 here */ - DEBUG_ENT("disk event %d:%d\n", - MAJOR(disk_devt(disk)), MINOR(disk_devt(disk))); - add_timer_randomness(disk->random, 0x100 + disk_devt(disk)); + trace_add_disk_randomness(disk_devt(disk), ENTROPY_BITS(&input_pool)); } #endif @@ -941,10 +929,8 @@ static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes) /* but never more than the buffer size */ bytes = min_t(int, bytes, sizeof(tmp)); - DEBUG_ENT("going to reseed %s with %d bits (%zu of %d requested)\n", - r->name, bytes * 8, nbytes * 8, - r->entropy_count >> ENTROPY_SHIFT); - + trace_xfer_secondary_pool(r->name, bytes * 8, nbytes * 8, + ENTROPY_BITS(r), ENTROPY_BITS(r->pull)); bytes = extract_entropy(r->pull, tmp, bytes, random_read_wakeup_thresh / 8, rsvd); mix_pool_bytes(r, tmp, bytes, NULL); @@ -992,8 +978,6 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, spin_lock_irqsave(&r->lock, flags); BUG_ON(r->entropy_count > r->poolinfo->poolfracbits); - DEBUG_ENT("trying to extract %zu bits from %s\n", - nbytes * 8, r->name); /* Can we pull enough? */ retry: @@ -1019,12 +1003,9 @@ retry: < random_write_wakeup_thresh) wakeup_write = 1; } - - DEBUG_ENT("debiting %zu entropy credits from %s%s\n", - ibytes * 8, r->name, r->limit ? "" : " (unlimited)"); - spin_unlock_irqrestore(&r->lock, flags); + trace_debit_entropy(r->name, 8 * ibytes); if (wakeup_write) { wake_up_interruptible(&random_write_wait); kill_fasync(&fasync, SIGIO, POLL_OUT); @@ -1303,8 +1284,6 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) if (n > SEC_XFER_SIZE) n = SEC_XFER_SIZE; - DEBUG_ENT("reading %zu bits\n", n*8); - n = extract_entropy_user(&blocking_pool, buf, n); if (n < 0) { @@ -1312,8 +1291,9 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) break; } - DEBUG_ENT("read got %zd bits (%zd still needed)\n", - n*8, (nbytes-n)*8); + trace_random_read(n*8, (nbytes-n)*8, + ENTROPY_BITS(&blocking_pool), + ENTROPY_BITS(&input_pool)); if (n == 0) { if (file->f_flags & O_NONBLOCK) { @@ -1321,14 +1301,10 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) break; } - DEBUG_ENT("sleeping?\n"); - wait_event_interruptible(random_read_wait, ENTROPY_BITS(&input_pool) >= random_read_wakeup_thresh); - DEBUG_ENT("awake\n"); - if (signal_pending(current)) { retval = -ERESTARTSYS; break; @@ -1350,7 +1326,11 @@ 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_entropy_user(&nonblocking_pool, buf, nbytes); + int ret = extract_entropy_user(&nonblocking_pool, buf, nbytes); + + trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool), + ENTROPY_BITS(&input_pool)); + return ret; } static unsigned int diff --git a/include/trace/events/random.h b/include/trace/events/random.h index 527b5dc1b416..805af6db41cc 100644 --- a/include/trace/events/random.h +++ b/include/trace/events/random.h @@ -109,6 +109,89 @@ TRACE_EVENT(push_to_pool, __entry->input_bits) ); +TRACE_EVENT(debit_entropy, + TP_PROTO(const char *pool_name, int debit_bits), + + TP_ARGS(pool_name, debit_bits), + + TP_STRUCT__entry( + __field( const char *, pool_name ) + __field( int, debit_bits ) + ), + + TP_fast_assign( + __entry->pool_name = pool_name; + __entry->debit_bits = debit_bits; + ), + + TP_printk("%s: debit_bits %d", __entry->pool_name, + __entry->debit_bits) +); + +TRACE_EVENT(add_input_randomness, + TP_PROTO(int input_bits), + + TP_ARGS(input_bits), + + TP_STRUCT__entry( + __field( int, input_bits ) + ), + + TP_fast_assign( + __entry->input_bits = input_bits; + ), + + TP_printk("input_pool_bits %d", __entry->input_bits) +); + +TRACE_EVENT(add_disk_randomness, + TP_PROTO(dev_t dev, int input_bits), + + TP_ARGS(dev, input_bits), + + TP_STRUCT__entry( + __field( dev_t, dev ) + __field( int, input_bits ) + ), + + TP_fast_assign( + __entry->dev = dev; + __entry->input_bits = input_bits; + ), + + TP_printk("dev %d,%d input_pool_bits %d", MAJOR(__entry->dev), + MINOR(__entry->dev), __entry->input_bits) +); + +TRACE_EVENT(xfer_secondary_pool, + TP_PROTO(const char *pool_name, int xfer_bits, int request_bits, + int pool_entropy, int input_entropy), + + TP_ARGS(pool_name, xfer_bits, request_bits, pool_entropy, + input_entropy), + + TP_STRUCT__entry( + __field( const char *, pool_name ) + __field( int, xfer_bits ) + __field( int, request_bits ) + __field( int, pool_entropy ) + __field( int, input_entropy ) + ), + + TP_fast_assign( + __entry->pool_name = pool_name; + __entry->xfer_bits = xfer_bits; + __entry->request_bits = request_bits; + __entry->pool_entropy = pool_entropy; + __entry->input_entropy = input_entropy; + ), + + TP_printk("pool %s xfer_bits %d request_bits %d pool_entropy %d " + "input_entropy %d", __entry->pool_name, __entry->xfer_bits, + __entry->request_bits, __entry->pool_entropy, + __entry->input_entropy) +); + DECLARE_EVENT_CLASS(random__get_random_bytes, TP_PROTO(int nbytes, unsigned long IP), @@ -179,7 +262,52 @@ DEFINE_EVENT(random__extract_entropy, extract_entropy_user, TP_ARGS(pool_name, nbytes, entropy_count, IP) ); +TRACE_EVENT(random_read, + TP_PROTO(int got_bits, int need_bits, int pool_left, int input_left), + TP_ARGS(got_bits, need_bits, pool_left, input_left), + + TP_STRUCT__entry( + __field( int, got_bits ) + __field( int, need_bits ) + __field( int, pool_left ) + __field( int, input_left ) + ), + + TP_fast_assign( + __entry->got_bits = got_bits; + __entry->need_bits = need_bits; + __entry->pool_left = pool_left; + __entry->input_left = input_left; + ), + + TP_printk("got_bits %d still_needed_bits %d " + "blocking_pool_entropy_left %d input_entropy_left %d", + __entry->got_bits, __entry->got_bits, __entry->pool_left, + __entry->input_left) +); + +TRACE_EVENT(urandom_read, + TP_PROTO(int got_bits, int pool_left, int input_left), + + TP_ARGS(got_bits, pool_left, input_left), + + TP_STRUCT__entry( + __field( int, got_bits ) + __field( int, pool_left ) + __field( int, input_left ) + ), + + TP_fast_assign( + __entry->got_bits = got_bits; + __entry->pool_left = pool_left; + __entry->input_left = input_left; + ), + + TP_printk("got_bits %d nonblocking_pool_entropy_left %d " + "input_entropy_left %d", __entry->got_bits, + __entry->pool_left, __entry->input_left) +); #endif /* _TRACE_RANDOM_H */ -- cgit v1.2.3-58-ga151 From 40db23e5337d99fda05ee6cd18034b516f8f123d Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 3 Nov 2013 00:15:05 -0400 Subject: random: make add_timer_randomness() fill the nonblocking pool first Change add_timer_randomness() so that it directs incoming entropy to the nonblocking pool first if it hasn't been fully initialized yet. This matches the strategy we use in add_interrupt_randomness(), which allows us to push the randomness where we need it the most during when the system is first booting up, so that get_random_bytes() and /dev/urandom become safe to use as soon as possible. Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index f126bd2f69fe..62923138e77a 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -761,6 +761,7 @@ static struct timer_rand_state input_timer_state; */ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) { + struct entropy_store *r; struct { long jiffies; unsigned cycles; @@ -773,7 +774,8 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) sample.jiffies = jiffies; sample.cycles = random_get_entropy(); sample.num = num; - mix_pool_bytes(&input_pool, &sample, sizeof(sample), NULL); + r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool; + mix_pool_bytes(r, &sample, sizeof(sample), NULL); /* * Calculate number of bits of randomness we probably added. @@ -807,8 +809,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) * Round down by 1 bit on general principles, * and limit entropy entimate to 12 bits. */ - credit_entropy_bits(&input_pool, - min_t(int, fls(delta>>1), 11)); + credit_entropy_bits(r, min_t(int, fls(delta>>1), 11)); } preempt_enable(); } -- cgit v1.2.3-58-ga151 From 301f0595c0e788edacc3521c4caa90b4e56ffee1 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 3 Nov 2013 06:54:51 -0500 Subject: random: printk notifications for urandom pool initialization Print a notification to the console when the nonblocking pool is initialized. Also printk a warning when a process tries reading from /dev/urandom before it is fully initialized. Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 62923138e77a..a19a7a63ec35 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -655,6 +655,9 @@ retry: r->entropy_total += nbits; if (!r->initialized && nbits > 0) { if (r->entropy_total > 128) { + if (r == &nonblocking_pool) + pr_notice("random: %s pool is initialized\n", + r->name); r->initialized = 1; r->entropy_total = 0; } @@ -1327,7 +1330,14 @@ 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) { - int ret = extract_entropy_user(&nonblocking_pool, buf, nbytes); + int ret; + + if (unlikely(nonblocking_pool.initialized == 0)) + printk_once(KERN_NOTICE "random: %s urandom read " + "with %d bits of entropy available\n", + current->comm, nonblocking_pool.entropy_total); + + ret = extract_entropy_user(&nonblocking_pool, buf, nbytes); trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool), ENTROPY_BITS(&input_pool)); -- cgit v1.2.3-58-ga151 From ae9ecd92ddabc250817baa7eb401df3cfbd4c2da Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 3 Nov 2013 07:56:17 -0500 Subject: random: don't zap entropy count in rand_initialize() The rand_initialize() function was being run fairly late in the kernel boot sequence. This was unfortunate, since it zero'ed the entropy counters, thus throwing away credit that was accumulated earlier in the boot sequence, and it also meant that initcall functions run before rand_initialize were using a minimally initialized pool. To fix this, fix init_std_data() to no longer zap the entropy counter; it wasn't necessary, and move rand_initialize() to be an early initcall. Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index a19a7a63ec35..a38d97a21455 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1228,14 +1228,11 @@ static void init_std_data(struct entropy_store *r) ktime_t now = ktime_get_real(); unsigned long rv; - r->entropy_count = 0; - r->entropy_total = 0; - r->last_data_init = 0; r->last_pulled = jiffies; mix_pool_bytes(r, &now, sizeof(now), NULL); for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) { if (!arch_get_random_long(&rv)) - break; + rv = random_get_entropy(); mix_pool_bytes(r, &rv, sizeof(rv), NULL); } mix_pool_bytes(r, utsname(), sizeof(*(utsname())), NULL); @@ -1258,7 +1255,7 @@ static int rand_initialize(void) init_std_data(&nonblocking_pool); return 0; } -module_init(rand_initialize); +early_initcall(rand_initialize); #ifdef CONFIG_BLOCK void rand_initialize_disk(struct gendisk *disk) @@ -1433,10 +1430,15 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) return 0; case RNDZAPENTCNT: case RNDCLEARPOOL: - /* Clear the entropy pool counters. */ + /* + * Clear the entropy pool counters. We no longer clear + * the entropy pool, as that's silly. + */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - rand_initialize(); + input_pool.entropy_count = 0; + nonblocking_pool.entropy_count = 0; + blocking_pool.entropy_count = 0; return 0; default: return -EINVAL; -- cgit v1.2.3-58-ga151 From 644008df899ec252e78db28c1b6d6b86779aada8 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 3 Nov 2013 16:40:53 -0500 Subject: random: initialize the last_time field in struct timer_rand_state Since we initialize jiffies to wrap five minutes before boot (see INITIAL_JIFFIES defined in include/linux/jiffies.h) it's important to make sure the last_time field is initialized to INITIAL_JIFFIES. Otherwise, the entropy estimator will overestimate the amount of entropy resulting from the first call to add_timer_randomness(), generally by about 8 bits. Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index a38d97a21455..0894d86253fd 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -724,6 +724,8 @@ struct timer_rand_state { unsigned dont_count_entropy:1; }; +#define INIT_TIMER_RAND_STATE { INITIAL_JIFFIES, }; + /* * Add device- or boot-specific data to the input and nonblocking * pools to help initialize them to unique values. @@ -750,7 +752,7 @@ void add_device_randomness(const void *buf, unsigned int size) } EXPORT_SYMBOL(add_device_randomness); -static struct timer_rand_state input_timer_state; +static struct timer_rand_state input_timer_state = INIT_TIMER_RAND_STATE; /* * This function adds entropy to the entropy "pool" by using timing @@ -1267,8 +1269,10 @@ void rand_initialize_disk(struct gendisk *disk) * source. */ state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) + if (state) { + state->last_time = INITIAL_JIFFIES; disk->random = state; + } } #endif -- cgit v1.2.3-58-ga151 From 392a546dc8368d1745f9891ef3f8f7c380de8650 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 3 Nov 2013 18:24:08 -0500 Subject: random: add debugging code to detect early use of get_random_bytes() Signed-off-by: "Theodore Ts'o" --- drivers/char/random.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/char/random.c b/drivers/char/random.c index 0894d86253fd..cdf4cfb2da4d 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -280,6 +280,8 @@ #define SEC_XFER_SIZE 512 #define EXTRACT_SIZE 10 +#define DEBUG_RANDOM_BOOT 0 + #define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long)) /* @@ -1177,6 +1179,13 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, */ void get_random_bytes(void *buf, int nbytes) { +#if DEBUG_RANDOM_BOOT > 0 + if (unlikely(nonblocking_pool.initialized == 0)) + printk(KERN_NOTICE "random: %pF get_random_bytes called " + "with %d bits of entropy available\n", + (void *) _RET_IP_, + nonblocking_pool.entropy_total); +#endif trace_get_random_bytes(nbytes, _RET_IP_); extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0); } -- cgit v1.2.3-58-ga151