Skip to content

Commit

Permalink
drivers/char/random.c: fix priming of last_data
Browse files Browse the repository at this point in the history
Commit ec8f02d ("random: prime last_data value per fips
requirements") added priming of last_data per fips requirements.

Unfortuantely, it did so in a way that can lead to multiple threads all
incrementing nbytes, but only one actually doing anything with the extra
data, which leads to some fun random corruption and panics.

The fix is to simply do everything needed to prime last_data in a single
shot, so there's no window for multiple cpus to increment nbytes -- in
fact, we won't even increment or decrement nbytes anymore, we'll just
extract the needed EXTRACT_SIZE one time per pool and then carry on with
the normal routine.

All these changes have been tested across multiple hosts and
architectures where panics were previously encoutered.  The code changes
are are strictly limited to areas only touched when when booted in fips
mode.

This change should also go into 3.8-stable, to make the myriads of fips
users on 3.8.x happy.

Signed-off-by: Jarod Wilson <[email protected]>
Tested-by: Jan Stancek <[email protected]>
Tested-by: Jan Stodola <[email protected]>
Cc: Herbert Xu <[email protected]>
Acked-by: Neil Horman <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: Matt Mackall <[email protected]>
Cc: "Theodore Ts'o" <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
jarodwilson authored and torvalds committed May 24, 2013
1 parent 348f9f0 commit 1e7e2e0
Showing 1 changed file with 15 additions and 15 deletions.
30 changes: 15 additions & 15 deletions drivers/char/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -957,10 +957,23 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
{
ssize_t ret = 0, i;
__u8 tmp[EXTRACT_SIZE];
unsigned long flags;

/* if last_data isn't primed, we need EXTRACT_SIZE extra bytes */
if (fips_enabled && !r->last_data_init)
nbytes += EXTRACT_SIZE;
if (fips_enabled) {
spin_lock_irqsave(&r->lock, flags);
if (!r->last_data_init) {
r->last_data_init = true;
spin_unlock_irqrestore(&r->lock, flags);
trace_extract_entropy(r->name, EXTRACT_SIZE,
r->entropy_count, _RET_IP_);
xfer_secondary_pool(r, EXTRACT_SIZE);
extract_buf(r, tmp);
spin_lock_irqsave(&r->lock, flags);
memcpy(r->last_data, tmp, EXTRACT_SIZE);
}
spin_unlock_irqrestore(&r->lock, flags);
}

trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_);
xfer_secondary_pool(r, nbytes);
Expand All @@ -970,19 +983,6 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
extract_buf(r, tmp);

if (fips_enabled) {
unsigned long flags;


/* prime last_data value if need be, per fips 140-2 */
if (!r->last_data_init) {
spin_lock_irqsave(&r->lock, flags);
memcpy(r->last_data, tmp, EXTRACT_SIZE);
r->last_data_init = true;
nbytes -= EXTRACT_SIZE;
spin_unlock_irqrestore(&r->lock, flags);
extract_buf(r, tmp);
}

spin_lock_irqsave(&r->lock, flags);
if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
panic("Hardware RNG duplicated output!\n");
Expand Down

0 comments on commit 1e7e2e0

Please sign in to comment.