diff options
-rw-r--r-- | drivers/char/random.c | 60 |
1 files 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 @@ | |||
272 | /* | 272 | /* |
273 | * Configuration information | 273 | * Configuration information |
274 | */ | 274 | */ |
275 | #define INPUT_POOL_WORDS 128 | 275 | #define INPUT_POOL_SHIFT 12 |
276 | #define OUTPUT_POOL_WORDS 32 | 276 | #define INPUT_POOL_WORDS (1 << (INPUT_POOL_SHIFT-5)) |
277 | #define SEC_XFER_SIZE 512 | 277 | #define OUTPUT_POOL_SHIFT 10 |
278 | #define EXTRACT_SIZE 10 | 278 | #define OUTPUT_POOL_WORDS (1 << (OUTPUT_POOL_SHIFT-5)) |
279 | #define SEC_XFER_SIZE 512 | ||
280 | #define EXTRACT_SIZE 10 | ||
279 | 281 | ||
280 | #define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long)) | 282 | #define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long)) |
281 | 283 | ||
@@ -284,6 +286,9 @@ | |||
284 | * this many fractional bits: | 286 | * this many fractional bits: |
285 | * | 287 | * |
286 | * entropy_count, trickle_thresh | 288 | * entropy_count, trickle_thresh |
289 | * | ||
290 | * 2*(ENTROPY_SHIFT + log2(poolbits)) must <= 31, or the multiply in | ||
291 | * credit_entropy_bits() needs to be 64 bits wide. | ||
287 | */ | 292 | */ |
288 | #define ENTROPY_SHIFT 3 | 293 | #define ENTROPY_SHIFT 3 |
289 | #define ENTROPY_BITS(r) ((r)->entropy_count >> ENTROPY_SHIFT) | 294 | #define ENTROPY_BITS(r) ((r)->entropy_count >> ENTROPY_SHIFT) |
@@ -427,7 +432,7 @@ module_param(debug, bool, 0644); | |||
427 | struct entropy_store; | 432 | struct entropy_store; |
428 | struct entropy_store { | 433 | struct entropy_store { |
429 | /* read-only data: */ | 434 | /* read-only data: */ |
430 | struct poolinfo *poolinfo; | 435 | const struct poolinfo *poolinfo; |
431 | __u32 *pool; | 436 | __u32 *pool; |
432 | const char *name; | 437 | const char *name; |
433 | struct entropy_store *pull; | 438 | struct entropy_store *pull; |
@@ -596,6 +601,8 @@ static void fast_mix(struct fast_pool *f, const void *in, int nbytes) | |||
596 | static void credit_entropy_bits(struct entropy_store *r, int nbits) | 601 | static void credit_entropy_bits(struct entropy_store *r, int nbits) |
597 | { | 602 | { |
598 | int entropy_count, orig; | 603 | int entropy_count, orig; |
604 | const int pool_size = r->poolinfo->poolfracbits; | ||
605 | int nfrac = nbits << ENTROPY_SHIFT; | ||
599 | 606 | ||
600 | if (!nbits) | 607 | if (!nbits) |
601 | return; | 608 | return; |
@@ -603,13 +610,50 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) | |||
603 | DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); | 610 | DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); |
604 | retry: | 611 | retry: |
605 | entropy_count = orig = ACCESS_ONCE(r->entropy_count); | 612 | entropy_count = orig = ACCESS_ONCE(r->entropy_count); |
606 | entropy_count += nbits << ENTROPY_SHIFT; | 613 | if (nfrac < 0) { |
614 | /* Debit */ | ||
615 | entropy_count += nfrac; | ||
616 | } else { | ||
617 | /* | ||
618 | * Credit: we have to account for the possibility of | ||
619 | * overwriting already present entropy. Even in the | ||
620 | * ideal case of pure Shannon entropy, new contributions | ||
621 | * approach the full value asymptotically: | ||
622 | * | ||
623 | * entropy <- entropy + (pool_size - entropy) * | ||
624 | * (1 - exp(-add_entropy/pool_size)) | ||
625 | * | ||
626 | * For add_entropy <= pool_size/2 then | ||
627 | * (1 - exp(-add_entropy/pool_size)) >= | ||
628 | * (add_entropy/pool_size)*0.7869... | ||
629 | * so we can approximate the exponential with | ||
630 | * 3/4*add_entropy/pool_size and still be on the | ||
631 | * safe side by adding at most pool_size/2 at a time. | ||
632 | * | ||
633 | * The use of pool_size-2 in the while statement is to | ||
634 | * prevent rounding artifacts from making the loop | ||
635 | * arbitrarily long; this limits the loop to log2(pool_size)*2 | ||
636 | * turns no matter how large nbits is. | ||
637 | */ | ||
638 | int pnfrac = nfrac; | ||
639 | const int s = r->poolinfo->poolbitshift + ENTROPY_SHIFT + 2; | ||
640 | /* The +2 corresponds to the /4 in the denominator */ | ||
641 | |||
642 | do { | ||
643 | unsigned int anfrac = min(pnfrac, pool_size/2); | ||
644 | unsigned int add = | ||
645 | ((pool_size - entropy_count)*anfrac*3) >> s; | ||
646 | |||
647 | entropy_count += add; | ||
648 | pnfrac -= anfrac; | ||
649 | } while (unlikely(entropy_count < pool_size-2 && pnfrac)); | ||
650 | } | ||
607 | 651 | ||
608 | if (entropy_count < 0) { | 652 | if (entropy_count < 0) { |
609 | DEBUG_ENT("negative entropy/overflow\n"); | 653 | DEBUG_ENT("negative entropy/overflow\n"); |
610 | entropy_count = 0; | 654 | entropy_count = 0; |
611 | } else if (entropy_count > r->poolinfo->poolfracbits) | 655 | } else if (entropy_count > pool_size) |
612 | entropy_count = r->poolinfo->poolfracbits; | 656 | entropy_count = pool_size; |
613 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) | 657 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) |
614 | goto retry; | 658 | goto retry; |
615 | 659 | ||