diff options
author | H. Peter Anvin <hpa@zytor.com> | 2013-09-10 23:16:17 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-10-10 14:32:14 -0400 |
commit | a283b5c459784f9762a74c312b134e9a524f5a5f (patch) | |
tree | 4d95a6686ce716f1ca69a7a23120647b1aa6220d /drivers/char/random.c | |
parent | 9ed17b70b409dc48c134a80b5a6df582ba759de2 (diff) |
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 <hpa@linux.intel.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'drivers/char/random.c')
-rw-r--r-- | drivers/char/random.c | 138 |
1 files 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 | |||
@@ -280,6 +280,15 @@ | |||
280 | #define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long)) | 280 | #define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long)) |
281 | 281 | ||
282 | /* | 282 | /* |
283 | * To allow fractional bits to be tracked, the following fields contain | ||
284 | * this many fractional bits: | ||
285 | * | ||
286 | * entropy_count, trickle_thresh | ||
287 | */ | ||
288 | #define ENTROPY_SHIFT 3 | ||
289 | #define ENTROPY_BITS(r) ((r)->entropy_count >> ENTROPY_SHIFT) | ||
290 | |||
291 | /* | ||
283 | * The minimum number of bits of entropy before we wake up a read on | 292 | * The minimum number of bits of entropy before we wake up a read on |
284 | * /dev/random. Should be enough to do a significant reseed. | 293 | * /dev/random. Should be enough to do a significant reseed. |
285 | */ | 294 | */ |
@@ -296,8 +305,7 @@ static int random_write_wakeup_thresh = 128; | |||
296 | * When the input pool goes over trickle_thresh, start dropping most | 305 | * When the input pool goes over trickle_thresh, start dropping most |
297 | * samples to avoid wasting CPU time and reduce lock contention. | 306 | * samples to avoid wasting CPU time and reduce lock contention. |
298 | */ | 307 | */ |
299 | 308 | static const int trickle_thresh = (INPUT_POOL_WORDS * 28) << ENTROPY_SHIFT; | |
300 | static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; | ||
301 | 309 | ||
302 | static DEFINE_PER_CPU(int, trickle_count); | 310 | static DEFINE_PER_CPU(int, trickle_count); |
303 | 311 | ||
@@ -311,8 +319,8 @@ static DEFINE_PER_CPU(int, trickle_count); | |||
311 | */ | 319 | */ |
312 | 320 | ||
313 | static struct poolinfo { | 321 | static struct poolinfo { |
314 | int poolbitshift, poolwords, poolbytes, poolbits; | 322 | int poolbitshift, poolwords, poolbytes, poolbits, poolfracbits; |
315 | #define S(x) ilog2(x)+5, (x), (x)*4, (x)*32 | 323 | #define S(x) ilog2(x)+5, (x), (x)*4, (x)*32, (x) << (ENTROPY_SHIFT+5) |
316 | int tap1, tap2, tap3, tap4, tap5; | 324 | int tap1, tap2, tap3, tap4, tap5; |
317 | } poolinfo_table[] = { | 325 | } poolinfo_table[] = { |
318 | /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ | 326 | /* 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) | |||
581 | } | 589 | } |
582 | 590 | ||
583 | /* | 591 | /* |
584 | * Credit (or debit) the entropy store with n bits of entropy | 592 | * Credit (or debit) the entropy store with n bits of entropy. |
593 | * Use credit_entropy_bits_safe() if the value comes from userspace | ||
594 | * or otherwise should be checked for extreme values. | ||
585 | */ | 595 | */ |
586 | static void credit_entropy_bits(struct entropy_store *r, int nbits) | 596 | static void credit_entropy_bits(struct entropy_store *r, int nbits) |
587 | { | 597 | { |
@@ -593,13 +603,13 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) | |||
593 | DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); | 603 | DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); |
594 | retry: | 604 | retry: |
595 | entropy_count = orig = ACCESS_ONCE(r->entropy_count); | 605 | entropy_count = orig = ACCESS_ONCE(r->entropy_count); |
596 | entropy_count += nbits; | 606 | entropy_count += nbits << ENTROPY_SHIFT; |
597 | 607 | ||
598 | if (entropy_count < 0) { | 608 | if (entropy_count < 0) { |
599 | DEBUG_ENT("negative entropy/overflow\n"); | 609 | DEBUG_ENT("negative entropy/overflow\n"); |
600 | entropy_count = 0; | 610 | entropy_count = 0; |
601 | } else if (entropy_count > r->poolinfo->poolbits) | 611 | } else if (entropy_count > r->poolinfo->poolfracbits) |
602 | entropy_count = r->poolinfo->poolbits; | 612 | entropy_count = r->poolinfo->poolfracbits; |
603 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) | 613 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) |
604 | goto retry; | 614 | goto retry; |
605 | 615 | ||
@@ -609,16 +619,29 @@ retry: | |||
609 | r->initialized = 1; | 619 | r->initialized = 1; |
610 | } | 620 | } |
611 | 621 | ||
612 | trace_credit_entropy_bits(r->name, nbits, entropy_count, | 622 | trace_credit_entropy_bits(r->name, nbits, |
623 | entropy_count >> ENTROPY_SHIFT, | ||
613 | r->entropy_total, _RET_IP_); | 624 | r->entropy_total, _RET_IP_); |
614 | 625 | ||
615 | /* should we wake readers? */ | 626 | /* should we wake readers? */ |
616 | if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) { | 627 | if (r == &input_pool && |
628 | (entropy_count >> ENTROPY_SHIFT) >= random_read_wakeup_thresh) { | ||
617 | wake_up_interruptible(&random_read_wait); | 629 | wake_up_interruptible(&random_read_wait); |
618 | kill_fasync(&fasync, SIGIO, POLL_IN); | 630 | kill_fasync(&fasync, SIGIO, POLL_IN); |
619 | } | 631 | } |
620 | } | 632 | } |
621 | 633 | ||
634 | static void credit_entropy_bits_safe(struct entropy_store *r, int nbits) | ||
635 | { | ||
636 | const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1)); | ||
637 | |||
638 | /* Cap the value to avoid overflows */ | ||
639 | nbits = min(nbits, nbits_max); | ||
640 | nbits = max(nbits, -nbits_max); | ||
641 | |||
642 | credit_entropy_bits(r, nbits); | ||
643 | } | ||
644 | |||
622 | /********************************************************************* | 645 | /********************************************************************* |
623 | * | 646 | * |
624 | * Entropy input management | 647 | * Entropy input management |
@@ -674,7 +697,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) | |||
674 | 697 | ||
675 | preempt_disable(); | 698 | preempt_disable(); |
676 | /* if over the trickle threshold, use only 1 in 4096 samples */ | 699 | /* if over the trickle threshold, use only 1 in 4096 samples */ |
677 | if (input_pool.entropy_count > trickle_thresh && | 700 | if (ENTROPY_BITS(&input_pool) > trickle_thresh && |
678 | ((__this_cpu_inc_return(trickle_count) - 1) & 0xfff)) | 701 | ((__this_cpu_inc_return(trickle_count) - 1) & 0xfff)) |
679 | goto out; | 702 | goto out; |
680 | 703 | ||
@@ -813,8 +836,9 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) | |||
813 | { | 836 | { |
814 | __u32 tmp[OUTPUT_POOL_WORDS]; | 837 | __u32 tmp[OUTPUT_POOL_WORDS]; |
815 | 838 | ||
816 | if (r->pull && r->entropy_count < nbytes * 8 && | 839 | if (r->pull && |
817 | r->entropy_count < r->poolinfo->poolbits) { | 840 | r->entropy_count < (nbytes << (ENTROPY_SHIFT + 3)) && |
841 | r->entropy_count < r->poolinfo->poolfracbits) { | ||
818 | /* If we're limited, always leave two wakeup worth's BITS */ | 842 | /* If we're limited, always leave two wakeup worth's BITS */ |
819 | int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; | 843 | int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; |
820 | int bytes = nbytes; | 844 | int bytes = nbytes; |
@@ -826,7 +850,8 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) | |||
826 | 850 | ||
827 | DEBUG_ENT("going to reseed %s with %d bits " | 851 | DEBUG_ENT("going to reseed %s with %d bits " |
828 | "(%zu of %d requested)\n", | 852 | "(%zu of %d requested)\n", |
829 | r->name, bytes * 8, nbytes * 8, r->entropy_count); | 853 | r->name, bytes * 8, nbytes * 8, |
854 | r->entropy_count >> ENTROPY_SHIFT); | ||
830 | 855 | ||
831 | bytes = extract_entropy(r->pull, tmp, bytes, | 856 | bytes = extract_entropy(r->pull, tmp, bytes, |
832 | random_read_wakeup_thresh / 8, rsvd); | 857 | random_read_wakeup_thresh / 8, rsvd); |
@@ -852,41 +877,44 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, | |||
852 | { | 877 | { |
853 | unsigned long flags; | 878 | unsigned long flags; |
854 | int wakeup_write = 0; | 879 | int wakeup_write = 0; |
880 | int have_bytes; | ||
881 | int entropy_count, orig; | ||
882 | size_t ibytes; | ||
855 | 883 | ||
856 | /* Hold lock while accounting */ | 884 | /* Hold lock while accounting */ |
857 | spin_lock_irqsave(&r->lock, flags); | 885 | spin_lock_irqsave(&r->lock, flags); |
858 | 886 | ||
859 | BUG_ON(r->entropy_count > r->poolinfo->poolbits); | 887 | BUG_ON(r->entropy_count > r->poolinfo->poolfracbits); |
860 | DEBUG_ENT("trying to extract %zu bits from %s\n", | 888 | DEBUG_ENT("trying to extract %zu bits from %s\n", |
861 | nbytes * 8, r->name); | 889 | nbytes * 8, r->name); |
862 | 890 | ||
863 | /* Can we pull enough? */ | 891 | /* Can we pull enough? */ |
864 | if (r->entropy_count / 8 < min + reserved) { | ||
865 | nbytes = 0; | ||
866 | } else { | ||
867 | int entropy_count, orig; | ||
868 | retry: | 892 | retry: |
869 | entropy_count = orig = ACCESS_ONCE(r->entropy_count); | 893 | entropy_count = orig = ACCESS_ONCE(r->entropy_count); |
894 | have_bytes = entropy_count >> (ENTROPY_SHIFT + 3); | ||
895 | ibytes = nbytes; | ||
896 | if (have_bytes < min + reserved) { | ||
897 | ibytes = 0; | ||
898 | } else { | ||
870 | /* If limited, never pull more than available */ | 899 | /* If limited, never pull more than available */ |
871 | if (r->limit && nbytes + reserved >= entropy_count / 8) | 900 | if (r->limit && ibytes + reserved >= have_bytes) |
872 | nbytes = entropy_count/8 - reserved; | 901 | ibytes = have_bytes - reserved; |
873 | 902 | ||
874 | if (entropy_count / 8 >= nbytes + reserved) { | 903 | if (have_bytes >= ibytes + reserved) |
875 | entropy_count -= nbytes*8; | 904 | entropy_count -= ibytes << (ENTROPY_SHIFT + 3); |
876 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) | 905 | else |
877 | goto retry; | 906 | entropy_count = reserved << (ENTROPY_SHIFT + 3); |
878 | } else { | ||
879 | entropy_count = reserved; | ||
880 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) | ||
881 | goto retry; | ||
882 | } | ||
883 | 907 | ||
884 | if (entropy_count < random_write_wakeup_thresh) | 908 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) |
909 | goto retry; | ||
910 | |||
911 | if ((r->entropy_count >> ENTROPY_SHIFT) | ||
912 | < random_write_wakeup_thresh) | ||
885 | wakeup_write = 1; | 913 | wakeup_write = 1; |
886 | } | 914 | } |
887 | 915 | ||
888 | DEBUG_ENT("debiting %zu entropy credits from %s%s\n", | 916 | DEBUG_ENT("debiting %zu entropy credits from %s%s\n", |
889 | nbytes * 8, r->name, r->limit ? "" : " (unlimited)"); | 917 | ibytes * 8, r->name, r->limit ? "" : " (unlimited)"); |
890 | 918 | ||
891 | spin_unlock_irqrestore(&r->lock, flags); | 919 | spin_unlock_irqrestore(&r->lock, flags); |
892 | 920 | ||
@@ -895,7 +923,7 @@ retry: | |||
895 | kill_fasync(&fasync, SIGIO, POLL_OUT); | 923 | kill_fasync(&fasync, SIGIO, POLL_OUT); |
896 | } | 924 | } |
897 | 925 | ||
898 | return nbytes; | 926 | return ibytes; |
899 | } | 927 | } |
900 | 928 | ||
901 | static void extract_buf(struct entropy_store *r, __u8 *out) | 929 | 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, | |||
973 | r->last_data_init = true; | 1001 | r->last_data_init = true; |
974 | spin_unlock_irqrestore(&r->lock, flags); | 1002 | spin_unlock_irqrestore(&r->lock, flags); |
975 | trace_extract_entropy(r->name, EXTRACT_SIZE, | 1003 | trace_extract_entropy(r->name, EXTRACT_SIZE, |
976 | r->entropy_count, _RET_IP_); | 1004 | ENTROPY_BITS(r), _RET_IP_); |
977 | xfer_secondary_pool(r, EXTRACT_SIZE); | 1005 | xfer_secondary_pool(r, EXTRACT_SIZE); |
978 | extract_buf(r, tmp); | 1006 | extract_buf(r, tmp); |
979 | spin_lock_irqsave(&r->lock, flags); | 1007 | spin_lock_irqsave(&r->lock, flags); |
@@ -982,7 +1010,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, | |||
982 | spin_unlock_irqrestore(&r->lock, flags); | 1010 | spin_unlock_irqrestore(&r->lock, flags); |
983 | } | 1011 | } |
984 | 1012 | ||
985 | trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_); | 1013 | trace_extract_entropy(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_); |
986 | xfer_secondary_pool(r, nbytes); | 1014 | xfer_secondary_pool(r, nbytes); |
987 | nbytes = account(r, nbytes, min, reserved); | 1015 | nbytes = account(r, nbytes, min, reserved); |
988 | 1016 | ||
@@ -1015,7 +1043,7 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, | |||
1015 | ssize_t ret = 0, i; | 1043 | ssize_t ret = 0, i; |
1016 | __u8 tmp[EXTRACT_SIZE]; | 1044 | __u8 tmp[EXTRACT_SIZE]; |
1017 | 1045 | ||
1018 | trace_extract_entropy_user(r->name, nbytes, r->entropy_count, _RET_IP_); | 1046 | trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_); |
1019 | xfer_secondary_pool(r, nbytes); | 1047 | xfer_secondary_pool(r, nbytes); |
1020 | nbytes = account(r, nbytes, 0, 0); | 1048 | nbytes = account(r, nbytes, 0, 0); |
1021 | 1049 | ||
@@ -1187,8 +1215,8 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) | |||
1187 | DEBUG_ENT("sleeping?\n"); | 1215 | DEBUG_ENT("sleeping?\n"); |
1188 | 1216 | ||
1189 | wait_event_interruptible(random_read_wait, | 1217 | wait_event_interruptible(random_read_wait, |
1190 | input_pool.entropy_count >= | 1218 | ENTROPY_BITS(&input_pool) >= |
1191 | random_read_wakeup_thresh); | 1219 | random_read_wakeup_thresh); |
1192 | 1220 | ||
1193 | DEBUG_ENT("awake\n"); | 1221 | DEBUG_ENT("awake\n"); |
1194 | 1222 | ||
@@ -1224,9 +1252,9 @@ random_poll(struct file *file, poll_table * wait) | |||
1224 | poll_wait(file, &random_read_wait, wait); | 1252 | poll_wait(file, &random_read_wait, wait); |
1225 | poll_wait(file, &random_write_wait, wait); | 1253 | poll_wait(file, &random_write_wait, wait); |
1226 | mask = 0; | 1254 | mask = 0; |
1227 | if (input_pool.entropy_count >= random_read_wakeup_thresh) | 1255 | if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_thresh) |
1228 | mask |= POLLIN | POLLRDNORM; | 1256 | mask |= POLLIN | POLLRDNORM; |
1229 | if (input_pool.entropy_count < random_write_wakeup_thresh) | 1257 | if (ENTROPY_BITS(&input_pool) < random_write_wakeup_thresh) |
1230 | mask |= POLLOUT | POLLWRNORM; | 1258 | mask |= POLLOUT | POLLWRNORM; |
1231 | return mask; | 1259 | return mask; |
1232 | } | 1260 | } |
@@ -1277,7 +1305,8 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | |||
1277 | switch (cmd) { | 1305 | switch (cmd) { |
1278 | case RNDGETENTCNT: | 1306 | case RNDGETENTCNT: |
1279 | /* inherently racy, no point locking */ | 1307 | /* inherently racy, no point locking */ |
1280 | if (put_user(input_pool.entropy_count, p)) | 1308 | ent_count = ENTROPY_BITS(&input_pool); |
1309 | if (put_user(ent_count, p)) | ||
1281 | return -EFAULT; | 1310 | return -EFAULT; |
1282 | return 0; | 1311 | return 0; |
1283 | case RNDADDTOENTCNT: | 1312 | case RNDADDTOENTCNT: |
@@ -1285,7 +1314,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | |||
1285 | return -EPERM; | 1314 | return -EPERM; |
1286 | if (get_user(ent_count, p)) | 1315 | if (get_user(ent_count, p)) |
1287 | return -EFAULT; | 1316 | return -EFAULT; |
1288 | credit_entropy_bits(&input_pool, ent_count); | 1317 | credit_entropy_bits_safe(&input_pool, ent_count); |
1289 | return 0; | 1318 | return 0; |
1290 | case RNDADDENTROPY: | 1319 | case RNDADDENTROPY: |
1291 | if (!capable(CAP_SYS_ADMIN)) | 1320 | if (!capable(CAP_SYS_ADMIN)) |
@@ -1300,7 +1329,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | |||
1300 | size); | 1329 | size); |
1301 | if (retval < 0) | 1330 | if (retval < 0) |
1302 | return retval; | 1331 | return retval; |
1303 | credit_entropy_bits(&input_pool, ent_count); | 1332 | credit_entropy_bits_safe(&input_pool, ent_count); |
1304 | return 0; | 1333 | return 0; |
1305 | case RNDZAPENTCNT: | 1334 | case RNDZAPENTCNT: |
1306 | case RNDCLEARPOOL: | 1335 | case RNDCLEARPOOL: |
@@ -1407,6 +1436,23 @@ static int proc_do_uuid(struct ctl_table *table, int write, | |||
1407 | return proc_dostring(&fake_table, write, buffer, lenp, ppos); | 1436 | return proc_dostring(&fake_table, write, buffer, lenp, ppos); |
1408 | } | 1437 | } |
1409 | 1438 | ||
1439 | /* | ||
1440 | * Return entropy available scaled to integral bits | ||
1441 | */ | ||
1442 | static int proc_do_entropy(ctl_table *table, int write, | ||
1443 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
1444 | { | ||
1445 | ctl_table fake_table; | ||
1446 | int entropy_count; | ||
1447 | |||
1448 | entropy_count = *(int *)table->data >> ENTROPY_SHIFT; | ||
1449 | |||
1450 | fake_table.data = &entropy_count; | ||
1451 | fake_table.maxlen = sizeof(entropy_count); | ||
1452 | |||
1453 | return proc_dointvec(&fake_table, write, buffer, lenp, ppos); | ||
1454 | } | ||
1455 | |||
1410 | static int sysctl_poolsize = INPUT_POOL_WORDS * 32; | 1456 | static int sysctl_poolsize = INPUT_POOL_WORDS * 32; |
1411 | extern struct ctl_table random_table[]; | 1457 | extern struct ctl_table random_table[]; |
1412 | struct ctl_table random_table[] = { | 1458 | struct ctl_table random_table[] = { |
@@ -1421,7 +1467,7 @@ struct ctl_table random_table[] = { | |||
1421 | .procname = "entropy_avail", | 1467 | .procname = "entropy_avail", |
1422 | .maxlen = sizeof(int), | 1468 | .maxlen = sizeof(int), |
1423 | .mode = 0444, | 1469 | .mode = 0444, |
1424 | .proc_handler = proc_dointvec, | 1470 | .proc_handler = proc_do_entropy, |
1425 | .data = &input_pool.entropy_count, | 1471 | .data = &input_pool.entropy_count, |
1426 | }, | 1472 | }, |
1427 | { | 1473 | { |