diff options
Diffstat (limited to 'drivers/char/random.c')
-rw-r--r-- | drivers/char/random.c | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c index 4ad71ef2cd59..71529e196b84 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
@@ -641,7 +641,7 @@ retry: | |||
641 | } while (unlikely(entropy_count < pool_size-2 && pnfrac)); | 641 | } while (unlikely(entropy_count < pool_size-2 && pnfrac)); |
642 | } | 642 | } |
643 | 643 | ||
644 | if (entropy_count < 0) { | 644 | if (unlikely(entropy_count < 0)) { |
645 | pr_warn("random: negative entropy/overflow: pool %s count %d\n", | 645 | pr_warn("random: negative entropy/overflow: pool %s count %d\n", |
646 | r->name, entropy_count); | 646 | r->name, entropy_count); |
647 | WARN_ON(1); | 647 | WARN_ON(1); |
@@ -980,26 +980,37 @@ static void push_to_pool(struct work_struct *work) | |||
980 | static size_t account(struct entropy_store *r, size_t nbytes, int min, | 980 | static size_t account(struct entropy_store *r, size_t nbytes, int min, |
981 | int reserved) | 981 | int reserved) |
982 | { | 982 | { |
983 | int have_bytes; | ||
984 | int entropy_count, orig; | 983 | int entropy_count, orig; |
985 | size_t ibytes; | 984 | size_t ibytes, nfrac; |
986 | 985 | ||
987 | BUG_ON(r->entropy_count > r->poolinfo->poolfracbits); | 986 | BUG_ON(r->entropy_count > r->poolinfo->poolfracbits); |
988 | 987 | ||
989 | /* Can we pull enough? */ | 988 | /* Can we pull enough? */ |
990 | retry: | 989 | retry: |
991 | entropy_count = orig = ACCESS_ONCE(r->entropy_count); | 990 | entropy_count = orig = ACCESS_ONCE(r->entropy_count); |
992 | have_bytes = entropy_count >> (ENTROPY_SHIFT + 3); | ||
993 | ibytes = nbytes; | 991 | ibytes = nbytes; |
994 | /* If limited, never pull more than available */ | 992 | /* If limited, never pull more than available */ |
995 | if (r->limit) | 993 | if (r->limit) { |
996 | ibytes = min_t(size_t, ibytes, have_bytes - reserved); | 994 | int have_bytes = entropy_count >> (ENTROPY_SHIFT + 3); |
995 | |||
996 | if ((have_bytes -= reserved) < 0) | ||
997 | have_bytes = 0; | ||
998 | ibytes = min_t(size_t, ibytes, have_bytes); | ||
999 | } | ||
997 | if (ibytes < min) | 1000 | if (ibytes < min) |
998 | ibytes = 0; | 1001 | ibytes = 0; |
999 | if (have_bytes >= ibytes + reserved) | 1002 | |
1000 | entropy_count -= ibytes << (ENTROPY_SHIFT + 3); | 1003 | if (unlikely(entropy_count < 0)) { |
1004 | pr_warn("random: negative entropy count: pool %s count %d\n", | ||
1005 | r->name, entropy_count); | ||
1006 | WARN_ON(1); | ||
1007 | entropy_count = 0; | ||
1008 | } | ||
1009 | nfrac = ibytes << (ENTROPY_SHIFT + 3); | ||
1010 | if ((size_t) entropy_count > nfrac) | ||
1011 | entropy_count -= nfrac; | ||
1001 | else | 1012 | else |
1002 | entropy_count = reserved << (ENTROPY_SHIFT + 3); | 1013 | entropy_count = 0; |
1003 | 1014 | ||
1004 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) | 1015 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) |
1005 | goto retry; | 1016 | goto retry; |
@@ -1375,6 +1386,7 @@ urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) | |||
1375 | "with %d bits of entropy available\n", | 1386 | "with %d bits of entropy available\n", |
1376 | current->comm, nonblocking_pool.entropy_total); | 1387 | current->comm, nonblocking_pool.entropy_total); |
1377 | 1388 | ||
1389 | nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3)); | ||
1378 | ret = extract_entropy_user(&nonblocking_pool, buf, nbytes); | 1390 | ret = extract_entropy_user(&nonblocking_pool, buf, nbytes); |
1379 | 1391 | ||
1380 | trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool), | 1392 | trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool), |