]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
random: check for increase of entropy_count because of signed conversion
authorHannes Frederic Sowa <hannes@stressinduktion.org>
Fri, 18 Jul 2014 21:26:41 +0000 (17:26 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 28 Jul 2014 15:08:27 +0000 (08:08 -0700)
commit 79a8468747c5f95ed3d5ce8376a3e82e0c5857fc upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/char/random.c

index 2b6e4cd8de8e8a9686d8b743339e3a0d034ab4de..18ec40459598ec6d46dd17105fe9c70d6f6fe415 100644 (file)
@@ -641,7 +641,7 @@ retry:
                } while (unlikely(entropy_count < pool_size-2 && pnfrac));
        }
 
-       if (entropy_count < 0) {
+       if (unlikely(entropy_count < 0)) {
                pr_warn("random: negative entropy/overflow: pool %s count %d\n",
                        r->name, entropy_count);
                WARN_ON(1);
@@ -980,7 +980,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
                      int reserved)
 {
        int entropy_count, orig;
-       size_t ibytes;
+       size_t ibytes, nfrac;
 
        BUG_ON(r->entropy_count > r->poolinfo->poolfracbits);
 
@@ -998,7 +998,17 @@ retry:
        }
        if (ibytes < min)
                ibytes = 0;
-       if ((entropy_count -= ibytes << (ENTROPY_SHIFT + 3)) < 0)
+
+       if (unlikely(entropy_count < 0)) {
+               pr_warn("random: negative entropy count: pool %s count %d\n",
+                       r->name, entropy_count);
+               WARN_ON(1);
+               entropy_count = 0;
+       }
+       nfrac = ibytes << (ENTROPY_SHIFT + 3);
+       if ((size_t) entropy_count > nfrac)
+               entropy_count -= nfrac;
+       else
                entropy_count = 0;
 
        if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
@@ -1375,6 +1385,7 @@ urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
                            "with %d bits of entropy available\n",
                            current->comm, nonblocking_pool.entropy_total);
 
+       nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3));
        ret = extract_entropy_user(&nonblocking_pool, buf, nbytes);
 
        trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool),