Skip to content

Commit

Permalink
random: cleanup poolinfo abstraction
Browse files Browse the repository at this point in the history
commit 91ec0fe upstream.

Now that we're only using one polynomial, we can cleanup its
representation into constants, instead of passing around pointers
dynamically to select different polynomials. This improves the codegen
and makes the code a bit more straightforward.

Reviewed-by: Dominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
zx2c4 authored and gregkh committed May 30, 2022
1 parent 8a3b78f commit c9e108e
Showing 1 changed file with 30 additions and 37 deletions.
67 changes: 30 additions & 37 deletions drivers/char/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,14 +430,20 @@ static int random_write_wakeup_bits = 28 * OUTPUT_POOL_WORDS;
* polynomial which improves the resulting TGFSR polynomial to be
* irreducible, which we have made here.
*/
static const struct poolinfo {
int poolbitshift, poolwords, poolbytes, poolfracbits;
#define S(x) ilog2(x)+5, (x), (x)*4, (x) << (ENTROPY_SHIFT+5)
int tap1, tap2, tap3, tap4, tap5;
} poolinfo_table[] = {
/* was: x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 */
enum poolinfo {
POOL_WORDS = 128,
POOL_WORDMASK = POOL_WORDS - 1,
POOL_BYTES = POOL_WORDS * sizeof(u32),
POOL_BITS = POOL_BYTES * 8,
POOL_BITSHIFT = ilog2(POOL_WORDS) + 5,
POOL_FRACBITS = POOL_WORDS << (ENTROPY_SHIFT + 5),

/* x^128 + x^104 + x^76 + x^51 +x^25 + x + 1 */
{ S(128), 104, 76, 51, 25, 1 },
POOL_TAP1 = 104,
POOL_TAP2 = 76,
POOL_TAP3 = 51,
POOL_TAP4 = 25,
POOL_TAP5 = 1
};

/*
Expand Down Expand Up @@ -503,7 +509,6 @@ MODULE_PARM_DESC(ratelimit_disable, "Disable random ratelimit suppression");
struct entropy_store;
struct entropy_store {
/* read-only data: */
const struct poolinfo *poolinfo;
__u32 *pool;
const char *name;

Expand All @@ -525,7 +530,6 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r);
static __u32 input_pool_data[INPUT_POOL_WORDS] __latent_entropy;

static struct entropy_store input_pool = {
.poolinfo = &poolinfo_table[0],
.name = "input",
.lock = __SPIN_LOCK_UNLOCKED(input_pool.lock),
.pool = input_pool_data
Expand All @@ -548,33 +552,26 @@ static __u32 const twist_table[8] = {
static void _mix_pool_bytes(struct entropy_store *r, const void *in,
int nbytes)
{
unsigned long i, tap1, tap2, tap3, tap4, tap5;
unsigned long i;
int input_rotate;
int wordmask = r->poolinfo->poolwords - 1;
const unsigned char *bytes = in;
__u32 w;

tap1 = r->poolinfo->tap1;
tap2 = r->poolinfo->tap2;
tap3 = r->poolinfo->tap3;
tap4 = r->poolinfo->tap4;
tap5 = r->poolinfo->tap5;

input_rotate = r->input_rotate;
i = r->add_ptr;

/* mix one byte at a time to simplify size handling and churn faster */
while (nbytes--) {
w = rol32(*bytes++, input_rotate);
i = (i - 1) & wordmask;
i = (i - 1) & POOL_WORDMASK;

/* XOR in the various taps */
w ^= r->pool[i];
w ^= r->pool[(i + tap1) & wordmask];
w ^= r->pool[(i + tap2) & wordmask];
w ^= r->pool[(i + tap3) & wordmask];
w ^= r->pool[(i + tap4) & wordmask];
w ^= r->pool[(i + tap5) & wordmask];
w ^= r->pool[(i + POOL_TAP1) & POOL_WORDMASK];
w ^= r->pool[(i + POOL_TAP2) & POOL_WORDMASK];
w ^= r->pool[(i + POOL_TAP3) & POOL_WORDMASK];
w ^= r->pool[(i + POOL_TAP4) & POOL_WORDMASK];
w ^= r->pool[(i + POOL_TAP5) & POOL_WORDMASK];

/* Mix the result back in with a twist */
r->pool[i] = (w >> 3) ^ twist_table[w & 7];
Expand Down Expand Up @@ -672,7 +669,6 @@ static void process_random_ready_list(void)
static void credit_entropy_bits(struct entropy_store *r, int nbits)
{
int entropy_count, orig;
const int pool_size = r->poolinfo->poolfracbits;
int nfrac = nbits << ENTROPY_SHIFT;

if (!nbits)
Expand Down Expand Up @@ -706,25 +702,25 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits)
* turns no matter how large nbits is.
*/
int pnfrac = nfrac;
const int s = r->poolinfo->poolbitshift + ENTROPY_SHIFT + 2;
const int s = POOL_BITSHIFT + ENTROPY_SHIFT + 2;
/* The +2 corresponds to the /4 in the denominator */

do {
unsigned int anfrac = min(pnfrac, pool_size/2);
unsigned int anfrac = min(pnfrac, POOL_FRACBITS/2);
unsigned int add =
((pool_size - entropy_count)*anfrac*3) >> s;
((POOL_FRACBITS - entropy_count)*anfrac*3) >> s;

entropy_count += add;
pnfrac -= anfrac;
} while (unlikely(entropy_count < pool_size-2 && pnfrac));
} while (unlikely(entropy_count < POOL_FRACBITS-2 && pnfrac));
}

if (WARN_ON(entropy_count < 0)) {
pr_warn("negative entropy/overflow: pool %s count %d\n",
r->name, entropy_count);
entropy_count = 0;
} else if (entropy_count > pool_size)
entropy_count = pool_size;
} else if (entropy_count > POOL_FRACBITS)
entropy_count = POOL_FRACBITS;
if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
goto retry;

Expand All @@ -741,13 +737,11 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits)

static int credit_entropy_bits_safe(struct entropy_store *r, int nbits)
{
const int nbits_max = r->poolinfo->poolwords * 32;

if (nbits < 0)
return -EINVAL;

/* Cap the value to avoid overflows */
nbits = min(nbits, nbits_max);
nbits = min(nbits, POOL_BITS);

credit_entropy_bits(r, nbits);
return 0;
Expand Down Expand Up @@ -1343,7 +1337,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
int entropy_count, orig, have_bytes;
size_t ibytes, nfrac;

BUG_ON(r->entropy_count > r->poolinfo->poolfracbits);
BUG_ON(r->entropy_count > POOL_FRACBITS);

/* Can we pull enough? */
retry:
Expand Down Expand Up @@ -1409,8 +1403,7 @@ static void extract_buf(struct entropy_store *r, __u8 *out)

/* Generate a hash across the pool */
spin_lock_irqsave(&r->lock, flags);
blake2s_update(&state, (const u8 *)r->pool,
r->poolinfo->poolwords * sizeof(*r->pool));
blake2s_update(&state, (const u8 *)r->pool, POOL_BYTES);
blake2s_final(&state, hash); /* final zeros out state */

/*
Expand Down Expand Up @@ -1766,7 +1759,7 @@ static void __init init_std_data(struct entropy_store *r)
unsigned long rv;

mix_pool_bytes(r, &now, sizeof(now));
for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) {
for (i = POOL_BYTES; i > 0; i -= sizeof(rv)) {
if (!arch_get_random_seed_long(&rv) &&
!arch_get_random_long(&rv))
rv = random_get_entropy();
Expand Down

0 comments on commit c9e108e

Please sign in to comment.