diff options
author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2014-07-18 17:26:41 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2014-07-19 01:42:13 -0400 |
commit | 79a8468747c5f95ed3d5ce8376a3e82e0c5857fc (patch) | |
tree | c84aca1e2222c1966b62bd87f9b702f7782b8f9c | |
parent | 1795cd9b3a91d4b5473c97f491d63892442212ab (diff) |
random: check for increase of entropy_count because of signed conversion
The expression entropy_count -= ibytes << (ENTROPY_SHIFT + 3) could
actually increase entropy_count if during assignment of the unsigned
expression on the RHS (mind the -=) we reduce the value modulo
2^width(int) and assign it to entropy_count. Trinity found this.
[ Commit modified by tytso to add an additional safety check for a
negative entropy_count -- which should never happen, and to also add
an additional paranoia check to prevent overly large count values to
be passed into urandom_read(). ]
Reported-by: Dave Jones <davej@redhat.com>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@vger.kernel.org
-rw-r--r-- | drivers/char/random.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c index 0a7ac0a7b252..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); |
@@ -981,7 +981,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, | |||
981 | int reserved) | 981 | int reserved) |
982 | { | 982 | { |
983 | int entropy_count, orig; | 983 | int entropy_count, orig; |
984 | size_t ibytes; | 984 | size_t ibytes, nfrac; |
985 | 985 | ||
986 | BUG_ON(r->entropy_count > r->poolinfo->poolfracbits); | 986 | BUG_ON(r->entropy_count > r->poolinfo->poolfracbits); |
987 | 987 | ||
@@ -999,7 +999,17 @@ retry: | |||
999 | } | 999 | } |
1000 | if (ibytes < min) | 1000 | if (ibytes < min) |
1001 | ibytes = 0; | 1001 | ibytes = 0; |
1002 | if ((entropy_count -= ibytes << (ENTROPY_SHIFT + 3)) < 0) | 1002 | |
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; | ||
1012 | else | ||
1003 | entropy_count = 0; | 1013 | entropy_count = 0; |
1004 | 1014 | ||
1005 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) | 1015 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) |
@@ -1376,6 +1386,7 @@ urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) | |||
1376 | "with %d bits of entropy available\n", | 1386 | "with %d bits of entropy available\n", |
1377 | current->comm, nonblocking_pool.entropy_total); | 1387 | current->comm, nonblocking_pool.entropy_total); |
1378 | 1388 | ||
1389 | nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3)); | ||
1379 | ret = extract_entropy_user(&nonblocking_pool, buf, nbytes); | 1390 | ret = extract_entropy_user(&nonblocking_pool, buf, nbytes); |
1380 | 1391 | ||
1381 | trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool), | 1392 | trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool), |