| From foo@baz Thu Jun 16 06:59:24 PM CEST 2022 |
| From: "Jason A. Donenfeld" <Jason@zx2c4.com> |
| Date: Wed, 9 Feb 2022 18:42:13 +0100 |
| Subject: random: zero buffer after reading entropy from userspace |
| |
| From: "Jason A. Donenfeld" <Jason@zx2c4.com> |
| |
| commit 7b5164fb1279bf0251371848e40bae646b59b3a8 upstream. |
| |
| This buffer may contain entropic data that shouldn't stick around longer |
| than needed, so zero out the temporary buffer at the end of write_pool(). |
| |
| Reviewed-by: Dominik Brodowski <linux@dominikbrodowski.net> |
| Reviewed-by: Jann Horn <jannh@google.com> |
| Reviewed-by: Eric Biggers <ebiggers@google.com> |
| Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/char/random.c | 20 ++++++++++++++------ |
| 1 file changed, 14 insertions(+), 6 deletions(-) |
| |
| --- a/drivers/char/random.c |
| +++ b/drivers/char/random.c |
| @@ -552,6 +552,7 @@ static void crng_reseed(void) |
| int entropy_count; |
| unsigned long next_gen; |
| u8 key[CHACHA20_KEY_SIZE]; |
| + bool finalize_init = false; |
| |
| /* |
| * First we make sure we have POOL_MIN_BITS of entropy in the pool, |
| @@ -579,12 +580,14 @@ static void crng_reseed(void) |
| ++next_gen; |
| WRITE_ONCE(base_crng.generation, next_gen); |
| WRITE_ONCE(base_crng.birth, jiffies); |
| - spin_unlock_irqrestore(&base_crng.lock, flags); |
| - memzero_explicit(key, sizeof(key)); |
| - |
| if (crng_init < 2) { |
| invalidate_batched_entropy(); |
| crng_init = 2; |
| + finalize_init = true; |
| + } |
| + spin_unlock_irqrestore(&base_crng.lock, flags); |
| + memzero_explicit(key, sizeof(key)); |
| + if (finalize_init) { |
| process_random_ready_list(); |
| wake_up_interruptible(&crng_init_wait); |
| kill_fasync(&fasync, SIGIO, POLL_IN); |
| @@ -1386,19 +1389,24 @@ static unsigned int random_poll(struct f |
| static int write_pool(const char __user *ubuf, size_t count) |
| { |
| size_t len; |
| + int ret = 0; |
| u8 block[BLAKE2S_BLOCK_SIZE]; |
| |
| while (count) { |
| len = min(count, sizeof(block)); |
| - if (copy_from_user(block, ubuf, len)) |
| - return -EFAULT; |
| + if (copy_from_user(block, ubuf, len)) { |
| + ret = -EFAULT; |
| + goto out; |
| + } |
| count -= len; |
| ubuf += len; |
| mix_pool_bytes(block, len); |
| cond_resched(); |
| } |
| |
| - return 0; |
| +out: |
| + memzero_explicit(block, sizeof(block)); |
| + return ret; |
| } |
| |
| static ssize_t random_write(struct file *file, const char __user *buffer, |