* The minimum number of bits of entropy before we wake up a read on
* /dev/random. Should be enough to do a significant reseed.
*/
-static int random_read_wakeup_thresh = 64;
+static int random_read_wakeup_bits = 64;
/*
* If the entropy count falls under this number of bits, then we
* should wake up processes which are selecting or polling on write
* access to /dev/random.
*/
-static int random_write_wakeup_thresh = 28 * OUTPUT_POOL_WORDS;
+static int random_write_wakeup_bits = 28 * OUTPUT_POOL_WORDS;
/*
* The minimum number of seconds between urandom pool reseeding. We
r->entropy_total, _RET_IP_);
if (r == &input_pool) {
- int entropy_bytes = entropy_count >> ENTROPY_SHIFT;
+ int entropy_bits = entropy_count >> ENTROPY_SHIFT;
/* should we wake readers? */
- if (entropy_bytes >= random_read_wakeup_thresh) {
+ if (entropy_bits >= random_read_wakeup_bits) {
wake_up_interruptible(&random_read_wait);
kill_fasync(&fasync, SIGIO, POLL_IN);
}
* forth between them, until the output pools are 75%
* full.
*/
- if (entropy_bytes > random_write_wakeup_thresh &&
+ if (entropy_bits > random_write_wakeup_bits &&
r->initialized &&
- r->entropy_total >= 2*random_read_wakeup_thresh) {
+ r->entropy_total >= 2*random_read_wakeup_bits) {
static struct entropy_store *last = &blocking_pool;
struct entropy_store *other = &blocking_pool;
cycles_t cycles = random_get_entropy();
__u32 input[4], c_high, j_high;
__u64 ip;
+ unsigned long seed;
+ int credit;
c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0;
j_high = (sizeof(now) > 4) ? now >> 32 : 0;
r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
__mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool), NULL);
+
/*
* If we don't have a valid cycle counter, and we see
* back-to-back timer interrupts, then skip giving credit for
- * any entropy.
+ * any entropy, otherwise credit 1 bit.
*/
+ credit = 1;
if (cycles == 0) {
if (irq_flags & __IRQF_TIMER) {
if (fast_pool->last_timer_intr)
- return;
+ credit = 0;
fast_pool->last_timer_intr = 1;
} else
fast_pool->last_timer_intr = 0;
}
- credit_entropy_bits(r, 1);
+
+ /*
+ * If we have architectural seed generator, produce a seed and
+ * add it to the pool. For the sake of paranoia count it as
+ * 50% entropic.
+ */
+ if (arch_get_random_seed_long(&seed)) {
+ __mix_pool_bytes(r, &seed, sizeof(seed), NULL);
+ credit += sizeof(seed) * 4;
+ }
+
+ credit_entropy_bits(r, credit);
}
#ifdef CONFIG_BLOCK
{
__u32 tmp[OUTPUT_POOL_WORDS];
- /* For /dev/random's pool, always leave two wakeup worth's BITS */
- int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4;
+ /* For /dev/random's pool, always leave two wakeups' worth */
+ int rsvd_bytes = r->limit ? 0 : random_read_wakeup_bits / 4;
int bytes = nbytes;
- /* pull at least as many as BYTES as wakeup BITS */
- bytes = max_t(int, bytes, random_read_wakeup_thresh / 8);
+ /* pull at least as much as a wakeup */
+ bytes = max_t(int, bytes, random_read_wakeup_bits / 8);
/* but never more than the buffer size */
bytes = min_t(int, bytes, sizeof(tmp));
trace_xfer_secondary_pool(r->name, bytes * 8, nbytes * 8,
ENTROPY_BITS(r), ENTROPY_BITS(r->pull));
bytes = extract_entropy(r->pull, tmp, bytes,
- random_read_wakeup_thresh / 8, rsvd);
+ random_read_wakeup_bits / 8, rsvd_bytes);
mix_pool_bytes(r, tmp, bytes, NULL);
credit_entropy_bits(r, bytes*8);
}
struct entropy_store *r = container_of(work, struct entropy_store,
push_work);
BUG_ON(!r);
- _xfer_secondary_pool(r, random_read_wakeup_thresh/8);
+ _xfer_secondary_pool(r, random_read_wakeup_bits/8);
trace_push_to_pool(r->name, r->entropy_count >> ENTROPY_SHIFT,
r->pull->entropy_count >> ENTROPY_SHIFT);
}
static size_t account(struct entropy_store *r, size_t nbytes, int min,
int reserved)
{
- unsigned long flags;
- int wakeup_write = 0;
int have_bytes;
int entropy_count, orig;
size_t ibytes;
- /* Hold lock while accounting */
- spin_lock_irqsave(&r->lock, flags);
-
BUG_ON(r->entropy_count > r->poolinfo->poolfracbits);
/* Can we pull enough? */
entropy_count = orig = ACCESS_ONCE(r->entropy_count);
have_bytes = entropy_count >> (ENTROPY_SHIFT + 3);
ibytes = nbytes;
- if (have_bytes < min + reserved) {
+ /* If limited, never pull more than available */
+ if (r->limit)
+ ibytes = min_t(size_t, ibytes, have_bytes - reserved);
+ if (ibytes < min)
ibytes = 0;
- } else {
- /* If limited, never pull more than available */
- if (r->limit && ibytes + reserved >= have_bytes)
- ibytes = have_bytes - reserved;
-
- if (have_bytes >= ibytes + reserved)
- entropy_count -= ibytes << (ENTROPY_SHIFT + 3);
- else
- entropy_count = reserved << (ENTROPY_SHIFT + 3);
+ if (have_bytes >= ibytes + reserved)
+ entropy_count -= ibytes << (ENTROPY_SHIFT + 3);
+ else
+ entropy_count = reserved << (ENTROPY_SHIFT + 3);
- if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
- goto retry;
-
- if ((r->entropy_count >> ENTROPY_SHIFT)
- < random_write_wakeup_thresh)
- wakeup_write = 1;
- }
- spin_unlock_irqrestore(&r->lock, flags);
+ if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
+ goto retry;
trace_debit_entropy(r->name, 8 * ibytes);
- if (wakeup_write) {
+ if (ibytes &&
+ (r->entropy_count >> ENTROPY_SHIFT) < random_write_wakeup_bits) {
wake_up_interruptible(&random_write_wait);
kill_fasync(&fasync, SIGIO, POLL_OUT);
}
__u8 extract[64];
unsigned long flags;
- /* Generate a hash across the pool, 16 words (512 bits) at a time */
- sha_init(hash.w);
- spin_lock_irqsave(&r->lock, flags);
- for (i = 0; i < r->poolinfo->poolwords; i += 16)
- sha_transform(hash.w, (__u8 *)(r->pool + i), workspace);
-
/*
* If we have an architectural hardware random number
- * generator, mix that in, too.
+ * generator, use it for SHA's initial vector
*/
+ sha_init(hash.w);
for (i = 0; i < LONGS(20); i++) {
unsigned long v;
if (!arch_get_random_long(&v))
break;
- hash.l[i] ^= v;
+ hash.l[i] = v;
}
+ /* Generate a hash across the pool, 16 words (512 bits) at a time */
+ spin_lock_irqsave(&r->lock, flags);
+ for (i = 0; i < r->poolinfo->poolwords; i += 16)
+ sha_transform(hash.w, (__u8 *)(r->pool + i), workspace);
+
/*
* We mix the hash back into the pool to prevent backtracking
* attacks (where the attacker knows the state of the pool
r->last_pulled = jiffies;
mix_pool_bytes(r, &now, sizeof(now), NULL);
for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) {
- if (!arch_get_random_long(&rv))
+ if (!arch_get_random_seed_long(&rv) &&
+ !arch_get_random_long(&rv))
rv = random_get_entropy();
mix_pool_bytes(r, &rv, sizeof(rv), NULL);
}
}
#endif
+/*
+ * Attempt an emergency refill using arch_get_random_seed_long().
+ *
+ * As with add_interrupt_randomness() be paranoid and only
+ * credit the output as 50% entropic.
+ */
+static int arch_random_refill(void)
+{
+ const unsigned int nlongs = 64; /* Arbitrary number */
+ unsigned int n = 0;
+ unsigned int i;
+ unsigned long buf[nlongs];
+
+ if (!arch_has_random_seed())
+ return 0;
+
+ for (i = 0; i < nlongs; i++) {
+ if (arch_get_random_seed_long(&buf[n]))
+ n++;
+ }
+
+ if (n) {
+ unsigned int rand_bytes = n * sizeof(unsigned long);
+
+ mix_pool_bytes(&input_pool, buf, rand_bytes, NULL);
+ credit_entropy_bits(&input_pool, rand_bytes*4);
+ }
+
+ return n;
+}
+
static ssize_t
random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
ENTROPY_BITS(&input_pool));
if (n > 0)
return n;
+
/* Pool is (near) empty. Maybe wait and retry. */
+ /* First try an emergency refill */
+ if (arch_random_refill())
+ continue;
+
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
wait_event_interruptible(random_read_wait,
ENTROPY_BITS(&input_pool) >=
- random_read_wakeup_thresh);
+ random_read_wakeup_bits);
if (signal_pending(current))
return -ERESTARTSYS;
}
poll_wait(file, &random_read_wait, wait);
poll_wait(file, &random_write_wait, wait);
mask = 0;
- if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_thresh)
+ if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits)
mask |= POLLIN | POLLRDNORM;
- if (ENTROPY_BITS(&input_pool) < random_write_wakeup_thresh)
+ if (ENTROPY_BITS(&input_pool) < random_write_wakeup_bits)
mask |= POLLOUT | POLLWRNORM;
return mask;
}
#include <linux/sysctl.h>
static int min_read_thresh = 8, min_write_thresh;
-static int max_read_thresh = INPUT_POOL_WORDS * 32;
+static int max_read_thresh = OUTPUT_POOL_WORDS * 32;
static int max_write_thresh = INPUT_POOL_WORDS * 32;
static char sysctl_bootid[16];
},
{
.procname = "read_wakeup_threshold",
- .data = &random_read_wakeup_thresh,
+ .data = &random_read_wakeup_bits,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
},
{
.procname = "write_wakeup_threshold",
- .data = &random_write_wakeup_thresh,
+ .data = &random_write_wakeup_bits,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,