diff options
author | Theodore Ts'o <tytso@mit.edu> | 2013-10-03 01:08:15 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-10-10 14:32:22 -0400 |
commit | 6265e169cd313d6f3aad3c33d0a5b0d9624f69f5 (patch) | |
tree | e029093b5e94f431f1d00cb13bf76bd024abfe7a /drivers/char | |
parent | 95b709b6be49e4ff3933ef6a5b5e623de2713a71 (diff) |
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" <tytso@mit.edu>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/random.c | 118 |
1 files changed, 86 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 @@ | |||
255 | #include <linux/fips.h> | 255 | #include <linux/fips.h> |
256 | #include <linux/ptrace.h> | 256 | #include <linux/ptrace.h> |
257 | #include <linux/kmemcheck.h> | 257 | #include <linux/kmemcheck.h> |
258 | #include <linux/workqueue.h> | ||
258 | 259 | ||
259 | #ifdef CONFIG_GENERIC_HARDIRQS | 260 | #ifdef CONFIG_GENERIC_HARDIRQS |
260 | # include <linux/irq.h> | 261 | # include <linux/irq.h> |
@@ -302,7 +303,7 @@ static int random_read_wakeup_thresh = 64; | |||
302 | * should wake up processes which are selecting or polling on write | 303 | * should wake up processes which are selecting or polling on write |
303 | * access to /dev/random. | 304 | * access to /dev/random. |
304 | */ | 305 | */ |
305 | static int random_write_wakeup_thresh = 128; | 306 | static int random_write_wakeup_thresh = 28 * OUTPUT_POOL_WORDS; |
306 | 307 | ||
307 | /* | 308 | /* |
308 | * The minimum number of seconds between urandom pool resending. We | 309 | * The minimum number of seconds between urandom pool resending. We |
@@ -428,6 +429,7 @@ struct entropy_store { | |||
428 | __u32 *pool; | 429 | __u32 *pool; |
429 | const char *name; | 430 | const char *name; |
430 | struct entropy_store *pull; | 431 | struct entropy_store *pull; |
432 | struct work_struct push_work; | ||
431 | 433 | ||
432 | /* read-write data: */ | 434 | /* read-write data: */ |
433 | unsigned long last_pulled; | 435 | unsigned long last_pulled; |
@@ -442,6 +444,7 @@ struct entropy_store { | |||
442 | __u8 last_data[EXTRACT_SIZE]; | 444 | __u8 last_data[EXTRACT_SIZE]; |
443 | }; | 445 | }; |
444 | 446 | ||
447 | static void push_to_pool(struct work_struct *work); | ||
445 | static __u32 input_pool_data[INPUT_POOL_WORDS]; | 448 | static __u32 input_pool_data[INPUT_POOL_WORDS]; |
446 | static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; | 449 | static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; |
447 | static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; | 450 | static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; |
@@ -460,7 +463,9 @@ static struct entropy_store blocking_pool = { | |||
460 | .limit = 1, | 463 | .limit = 1, |
461 | .pull = &input_pool, | 464 | .pull = &input_pool, |
462 | .lock = __SPIN_LOCK_UNLOCKED(blocking_pool.lock), | 465 | .lock = __SPIN_LOCK_UNLOCKED(blocking_pool.lock), |
463 | .pool = blocking_pool_data | 466 | .pool = blocking_pool_data, |
467 | .push_work = __WORK_INITIALIZER(blocking_pool.push_work, | ||
468 | push_to_pool), | ||
464 | }; | 469 | }; |
465 | 470 | ||
466 | static struct entropy_store nonblocking_pool = { | 471 | static struct entropy_store nonblocking_pool = { |
@@ -468,7 +473,9 @@ static struct entropy_store nonblocking_pool = { | |||
468 | .name = "nonblocking", | 473 | .name = "nonblocking", |
469 | .pull = &input_pool, | 474 | .pull = &input_pool, |
470 | .lock = __SPIN_LOCK_UNLOCKED(nonblocking_pool.lock), | 475 | .lock = __SPIN_LOCK_UNLOCKED(nonblocking_pool.lock), |
471 | .pool = nonblocking_pool_data | 476 | .pool = nonblocking_pool_data, |
477 | .push_work = __WORK_INITIALIZER(nonblocking_pool.push_work, | ||
478 | push_to_pool), | ||
472 | }; | 479 | }; |
473 | 480 | ||
474 | static __u32 const twist_table[8] = { | 481 | static __u32 const twist_table[8] = { |
@@ -655,21 +662,48 @@ retry: | |||
655 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) | 662 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) |
656 | goto retry; | 663 | goto retry; |
657 | 664 | ||
665 | r->entropy_total += nbits; | ||
658 | if (!r->initialized && nbits > 0) { | 666 | if (!r->initialized && nbits > 0) { |
659 | r->entropy_total += nbits; | 667 | if (r->entropy_total > 128) { |
660 | if (r->entropy_total > 128) | ||
661 | r->initialized = 1; | 668 | r->initialized = 1; |
669 | r->entropy_total = 0; | ||
670 | } | ||
662 | } | 671 | } |
663 | 672 | ||
664 | trace_credit_entropy_bits(r->name, nbits, | 673 | trace_credit_entropy_bits(r->name, nbits, |
665 | entropy_count >> ENTROPY_SHIFT, | 674 | entropy_count >> ENTROPY_SHIFT, |
666 | r->entropy_total, _RET_IP_); | 675 | r->entropy_total, _RET_IP_); |
667 | 676 | ||
668 | /* should we wake readers? */ | 677 | if (r == &input_pool) { |
669 | if (r == &input_pool && | 678 | int entropy_bytes = entropy_count >> ENTROPY_SHIFT; |
670 | (entropy_count >> ENTROPY_SHIFT) >= random_read_wakeup_thresh) { | 679 | |
671 | wake_up_interruptible(&random_read_wait); | 680 | /* should we wake readers? */ |
672 | kill_fasync(&fasync, SIGIO, POLL_IN); | 681 | if (entropy_bytes >= random_read_wakeup_thresh) { |
682 | wake_up_interruptible(&random_read_wait); | ||
683 | kill_fasync(&fasync, SIGIO, POLL_IN); | ||
684 | } | ||
685 | /* If the input pool is getting full, send some | ||
686 | * entropy to the two output pools, flipping back and | ||
687 | * forth between them, until the output pools are 75% | ||
688 | * full. | ||
689 | */ | ||
690 | if (entropy_bytes > random_write_wakeup_thresh && | ||
691 | r->initialized && | ||
692 | r->entropy_total >= 2*random_read_wakeup_thresh) { | ||
693 | static struct entropy_store *last = &blocking_pool; | ||
694 | struct entropy_store *other = &blocking_pool; | ||
695 | |||
696 | if (last == &blocking_pool) | ||
697 | other = &nonblocking_pool; | ||
698 | if (other->entropy_count <= | ||
699 | 3 * other->poolinfo->poolfracbits / 4) | ||
700 | last = other; | ||
701 | if (last->entropy_count <= | ||
702 | 3 * last->poolinfo->poolfracbits / 4) { | ||
703 | schedule_work(&last->push_work); | ||
704 | r->entropy_total = 0; | ||
705 | } | ||
706 | } | ||
673 | } | 707 | } |
674 | } | 708 | } |
675 | 709 | ||
@@ -877,10 +911,9 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, | |||
877 | * from the primary pool to the secondary extraction pool. We make | 911 | * from the primary pool to the secondary extraction pool. We make |
878 | * sure we pull enough for a 'catastrophic reseed'. | 912 | * sure we pull enough for a 'catastrophic reseed'. |
879 | */ | 913 | */ |
914 | static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes); | ||
880 | static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) | 915 | static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) |
881 | { | 916 | { |
882 | __u32 tmp[OUTPUT_POOL_WORDS]; | ||
883 | |||
884 | if (r->limit == 0 && random_min_urandom_seed) { | 917 | if (r->limit == 0 && random_min_urandom_seed) { |
885 | unsigned long now = jiffies; | 918 | unsigned long now = jiffies; |
886 | 919 | ||
@@ -891,26 +924,47 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) | |||
891 | } | 924 | } |
892 | if (r->pull && | 925 | if (r->pull && |
893 | r->entropy_count < (nbytes << (ENTROPY_SHIFT + 3)) && | 926 | r->entropy_count < (nbytes << (ENTROPY_SHIFT + 3)) && |
894 | r->entropy_count < r->poolinfo->poolfracbits) { | 927 | r->entropy_count < r->poolinfo->poolfracbits) |
895 | /* If we're limited, always leave two wakeup worth's BITS */ | 928 | _xfer_secondary_pool(r, nbytes); |
896 | int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; | 929 | } |
897 | int bytes = nbytes; | 930 | |
898 | 931 | static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes) | |
899 | /* pull at least as many as BYTES as wakeup BITS */ | 932 | { |
900 | bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); | 933 | __u32 tmp[OUTPUT_POOL_WORDS]; |
901 | /* but never more than the buffer size */ | 934 | |
902 | bytes = min_t(int, bytes, sizeof(tmp)); | 935 | /* For /dev/random's pool, always leave two wakeup worth's BITS */ |
903 | 936 | int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; | |
904 | DEBUG_ENT("going to reseed %s with %d bits " | 937 | int bytes = nbytes; |
905 | "(%zu of %d requested)\n", | 938 | |
906 | r->name, bytes * 8, nbytes * 8, | 939 | /* pull at least as many as BYTES as wakeup BITS */ |
907 | r->entropy_count >> ENTROPY_SHIFT); | 940 | bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); |
908 | 941 | /* but never more than the buffer size */ | |
909 | bytes = extract_entropy(r->pull, tmp, bytes, | 942 | bytes = min_t(int, bytes, sizeof(tmp)); |
910 | random_read_wakeup_thresh / 8, rsvd); | 943 | |
911 | mix_pool_bytes(r, tmp, bytes, NULL); | 944 | DEBUG_ENT("going to reseed %s with %d bits (%zu of %d requested)\n", |
912 | credit_entropy_bits(r, bytes*8); | 945 | r->name, bytes * 8, nbytes * 8, |
913 | } | 946 | r->entropy_count >> ENTROPY_SHIFT); |
947 | |||
948 | bytes = extract_entropy(r->pull, tmp, bytes, | ||
949 | random_read_wakeup_thresh / 8, rsvd); | ||
950 | mix_pool_bytes(r, tmp, bytes, NULL); | ||
951 | credit_entropy_bits(r, bytes*8); | ||
952 | } | ||
953 | |||
954 | /* | ||
955 | * Used as a workqueue function so that when the input pool is getting | ||
956 | * full, we can "spill over" some entropy to the output pools. That | ||
957 | * way the output pools can store some of the excess entropy instead | ||
958 | * of letting it go to waste. | ||
959 | */ | ||
960 | static void push_to_pool(struct work_struct *work) | ||
961 | { | ||
962 | struct entropy_store *r = container_of(work, struct entropy_store, | ||
963 | push_work); | ||
964 | BUG_ON(!r); | ||
965 | _xfer_secondary_pool(r, random_read_wakeup_thresh/8); | ||
966 | trace_push_to_pool(r->name, r->entropy_count >> ENTROPY_SHIFT, | ||
967 | r->pull->entropy_count >> ENTROPY_SHIFT); | ||
914 | } | 968 | } |
915 | 969 | ||
916 | /* | 970 | /* |