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
ibytes = min_t(size_t, ibytes, have_bytes - reserved);
if (ibytes < min)
ibytes = 0;
- entropy_count = max_t(int, 0,
- entropy_count - (ibytes << (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;
__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;