random: account for entropy loss due to overwrites
authorH. Peter Anvin <hpa@linux.intel.com>
Wed, 11 Sep 2013 03:16:17 +0000 (23:16 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 10 Oct 2013 18:32:15 +0000 (14:32 -0400)
commit30e37ec516ae5a6957596de7661673c615c82ea4
treef05b433d712c0d74e2e86dea92de700b940c6a42
parenta283b5c459784f9762a74c312b134e9a524f5a5f
random: account for entropy loss due to overwrites

When we write entropy into a non-empty pool, we currently don't
account at all for the fact that we will probabilistically overwrite
some of the entropy in that pool.  This means that unless the pool is
fully empty, we are currently *guaranteed* to overestimate the amount
of entropy in the pool!

Assuming Shannon entropy with zero correlations we end up with an
exponentally decaying value of new entropy added:

entropy <- entropy + (pool_size - entropy) *
(1 - exp(-add_entropy/pool_size))

However, calculations involving fractional exponentials are not
practical in the kernel, so apply a piecewise linearization:

  For add_entropy <= pool_size/2 then

  (1 - exp(-add_entropy/pool_size)) >= (add_entropy/pool_size)*0.7869...

  ... so we can approximate the exponential with
  3/4*add_entropy/pool_size and still be on the
  safe side by adding at most pool_size/2 at a time.

In order for the loop not to take arbitrary amounts of time if a bad
ioctl is received, terminate if we are within one bit of full.  This
way the loop is guaranteed to terminate after no more than
log2(poolsize) iterations, no matter what the input value is.  The
vast majority of the time the loop will be executed exactly once.

The piecewise linearization is very conservative, approaching 3/4 of
the usable input value for small inputs, however, our entropy
estimation is pretty weak at best, especially for small values; we
have no handle on correlation; and the Shannon entropy measure (Rényi
entropy of order 1) is not the correct one to use in the first place,
but rather the correct entropy measure is the min-entropy, the Rényi
entropy of infinite order.

As such, this conservatism seems more than justified.

This does introduce fractional bit values.  I have left it to have 3
bits of fraction, so that with a pool of 2^12 bits the multiply in
credit_entropy_bits() can still fit into an int, as 2*(3+12) < 31.  It
is definitely possible to allow for more fractional accounting, but
that multiply then would have to be turned into a 32*32 -> 64 multiply.

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: DJ Johnston <dj.johnston@intel.com>
drivers/char/random.c