Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5e126f68 authored by Jason A. Donenfeld's avatar Jason A. Donenfeld Committed by Greg Kroah-Hartman
Browse files

random: do not throw away excess input to crng_fast_load



[ Upstream commit 73c7733f122e8d0107f88655a12011f68f69e74b ]

When crng_fast_load() is called by add_hwgenerator_randomness(), we
currently will advance to crng_init==1 once we've acquired 64 bytes, and
then throw away the rest of the buffer. Usually, that is not a problem:
When add_hwgenerator_randomness() gets called via EFI or DT during
setup_arch(), there won't be any IRQ randomness. Therefore, the 64 bytes
passed by EFI exactly matches what is needed to advance to crng_init==1.
Usually, DT seems to pass 64 bytes as well -- with one notable exception
being kexec, which hands over 128 bytes of entropy to the kexec'd kernel.
In that case, we'll advance to crng_init==1 once 64 of those bytes are
consumed by crng_fast_load(), but won't continue onward feeding in bytes
to progress to crng_init==2. This commit fixes the issue by feeding
any leftover bytes into the next phase in add_hwgenerator_randomness().

[linux@dominikbrodowski.net: rewrite commit message]
Signed-off-by: default avatarDominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: default avatarJason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 8f6cecff
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -975,12 +975,14 @@ static struct crng_state *select_crng(void)

/*
 * crng_fast_load() can be called by code in the interrupt service
 * path.  So we can't afford to dilly-dally.
 * path.  So we can't afford to dilly-dally. Returns the number of
 * bytes processed from cp.
 */
static int crng_fast_load(const char *cp, size_t len)
static size_t crng_fast_load(const char *cp, size_t len)
{
	unsigned long flags;
	char *p;
	size_t ret = 0;

	if (!spin_trylock_irqsave(&primary_crng.lock, flags))
		return 0;
@@ -991,7 +993,7 @@ static int crng_fast_load(const char *cp, size_t len)
	p = (unsigned char *) &primary_crng.state[4];
	while (len > 0 && crng_init_cnt < CRNG_INIT_CNT_THRESH) {
		p[crng_init_cnt % CHACHA_KEY_SIZE] ^= *cp;
		cp++; crng_init_cnt++; len--;
		cp++; crng_init_cnt++; len--; ret++;
	}
	spin_unlock_irqrestore(&primary_crng.lock, flags);
	if (crng_init_cnt >= CRNG_INIT_CNT_THRESH) {
@@ -1000,7 +1002,7 @@ static int crng_fast_load(const char *cp, size_t len)
		wake_up_interruptible(&crng_init_wait);
		pr_notice("random: fast init done\n");
	}
	return 1;
	return ret;
}

/*
@@ -1353,7 +1355,7 @@ void add_interrupt_randomness(int irq, int irq_flags)
	if (unlikely(crng_init == 0)) {
		if ((fast_pool->count >= 64) &&
		    crng_fast_load((char *) fast_pool->pool,
				   sizeof(fast_pool->pool))) {
				   sizeof(fast_pool->pool)) > 0) {
			fast_pool->count = 0;
			fast_pool->last = now;
		}
@@ -2501,7 +2503,10 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,
	struct entropy_store *poolp = &input_pool;

	if (unlikely(crng_init == 0)) {
		crng_fast_load(buffer, count);
		size_t ret = crng_fast_load(buffer, count);
		count -= ret;
		buffer += ret;
		if (!count || crng_init == 0)
			return;
	}