| From foo@baz Fri Jun 17 09:02:32 AM CEST 2022 |
| From: "Jason A. Donenfeld" <Jason@zx2c4.com> |
| Date: Fri, 11 Feb 2022 12:53:34 +0100 |
| Subject: random: group userspace read/write functions |
| |
| From: "Jason A. Donenfeld" <Jason@zx2c4.com> |
| |
| commit a6adf8e7a605250b911e94793fd077933709ff9e upstream. |
| |
| This pulls all of the userspace read/write-focused functions into the |
| fifth labeled section. |
| |
| No functional changes. |
| |
| Cc: Theodore Ts'o <tytso@mit.edu> |
| Reviewed-by: Eric Biggers <ebiggers@google.com> |
| Reviewed-by: Dominik Brodowski <linux@dominikbrodowski.net> |
| Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/char/random.c | 125 ++++++++++++++++++++++++++++++-------------------- |
| 1 file changed, 77 insertions(+), 48 deletions(-) |
| |
| --- a/drivers/char/random.c |
| +++ b/drivers/char/random.c |
| @@ -1472,30 +1472,61 @@ static void try_to_generate_entropy(void |
| mix_pool_bytes(&stack.now, sizeof(stack.now)); |
| } |
| |
| -static ssize_t urandom_read(struct file *file, char __user *buf, size_t nbytes, |
| - loff_t *ppos) |
| + |
| +/********************************************************************** |
| + * |
| + * Userspace reader/writer interfaces. |
| + * |
| + * getrandom(2) is the primary modern interface into the RNG and should |
| + * be used in preference to anything else. |
| + * |
| + * Reading from /dev/random has the same functionality as calling |
| + * getrandom(2) with flags=0. In earlier versions, however, it had |
| + * vastly different semantics and should therefore be avoided, to |
| + * prevent backwards compatibility issues. |
| + * |
| + * Reading from /dev/urandom has the same functionality as calling |
| + * getrandom(2) with flags=GRND_INSECURE. Because it does not block |
| + * waiting for the RNG to be ready, it should not be used. |
| + * |
| + * Writing to either /dev/random or /dev/urandom adds entropy to |
| + * the input pool but does not credit it. |
| + * |
| + * Polling on /dev/random indicates when the RNG is initialized, on |
| + * the read side, and when it wants new entropy, on the write side. |
| + * |
| + * Both /dev/random and /dev/urandom have the same set of ioctls for |
| + * adding entropy, getting the entropy count, zeroing the count, and |
| + * reseeding the crng. |
| + * |
| + **********************************************************************/ |
| + |
| +SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count, unsigned int, |
| + flags) |
| { |
| - static int maxwarn = 10; |
| + if (flags & ~(GRND_NONBLOCK | GRND_RANDOM | GRND_INSECURE)) |
| + return -EINVAL; |
| |
| - if (!crng_ready() && maxwarn > 0) { |
| - maxwarn--; |
| - if (__ratelimit(&urandom_warning)) |
| - pr_notice("%s: uninitialized urandom read (%zd bytes read)\n", |
| - current->comm, nbytes); |
| - } |
| + /* |
| + * Requesting insecure and blocking randomness at the same time makes |
| + * no sense. |
| + */ |
| + if ((flags & (GRND_INSECURE | GRND_RANDOM)) == (GRND_INSECURE | GRND_RANDOM)) |
| + return -EINVAL; |
| |
| - return get_random_bytes_user(buf, nbytes); |
| -} |
| + if (count > INT_MAX) |
| + count = INT_MAX; |
| |
| -static ssize_t random_read(struct file *file, char __user *buf, size_t nbytes, |
| - loff_t *ppos) |
| -{ |
| - int ret; |
| + if (!(flags & GRND_INSECURE) && !crng_ready()) { |
| + int ret; |
| |
| - ret = wait_for_random_bytes(); |
| - if (ret != 0) |
| - return ret; |
| - return get_random_bytes_user(buf, nbytes); |
| + if (flags & GRND_NONBLOCK) |
| + return -EAGAIN; |
| + ret = wait_for_random_bytes(); |
| + if (unlikely(ret)) |
| + return ret; |
| + } |
| + return get_random_bytes_user(buf, count); |
| } |
| |
| static __poll_t random_poll(struct file *file, poll_table *wait) |
| @@ -1547,6 +1578,32 @@ static ssize_t random_write(struct file |
| return (ssize_t)count; |
| } |
| |
| +static ssize_t urandom_read(struct file *file, char __user *buf, size_t nbytes, |
| + loff_t *ppos) |
| +{ |
| + static int maxwarn = 10; |
| + |
| + if (!crng_ready() && maxwarn > 0) { |
| + maxwarn--; |
| + if (__ratelimit(&urandom_warning)) |
| + pr_notice("%s: uninitialized urandom read (%zd bytes read)\n", |
| + current->comm, nbytes); |
| + } |
| + |
| + return get_random_bytes_user(buf, nbytes); |
| +} |
| + |
| +static ssize_t random_read(struct file *file, char __user *buf, size_t nbytes, |
| + loff_t *ppos) |
| +{ |
| + int ret; |
| + |
| + ret = wait_for_random_bytes(); |
| + if (ret != 0) |
| + return ret; |
| + return get_random_bytes_user(buf, nbytes); |
| +} |
| + |
| static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) |
| { |
| int size, ent_count; |
| @@ -1555,7 +1612,7 @@ static long random_ioctl(struct file *f, |
| |
| switch (cmd) { |
| case RNDGETENTCNT: |
| - /* inherently racy, no point locking */ |
| + /* Inherently racy, no point locking. */ |
| if (put_user(input_pool.entropy_count, p)) |
| return -EFAULT; |
| return 0; |
| @@ -1631,34 +1688,6 @@ const struct file_operations urandom_fop |
| .llseek = noop_llseek, |
| }; |
| |
| -SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count, unsigned int, |
| - flags) |
| -{ |
| - if (flags & ~(GRND_NONBLOCK | GRND_RANDOM | GRND_INSECURE)) |
| - return -EINVAL; |
| - |
| - /* |
| - * Requesting insecure and blocking randomness at the same time makes |
| - * no sense. |
| - */ |
| - if ((flags & (GRND_INSECURE | GRND_RANDOM)) == (GRND_INSECURE | GRND_RANDOM)) |
| - return -EINVAL; |
| - |
| - if (count > INT_MAX) |
| - count = INT_MAX; |
| - |
| - if (!(flags & GRND_INSECURE) && !crng_ready()) { |
| - int ret; |
| - |
| - if (flags & GRND_NONBLOCK) |
| - return -EAGAIN; |
| - ret = wait_for_random_bytes(); |
| - if (unlikely(ret)) |
| - return ret; |
| - } |
| - return get_random_bytes_user(buf, count); |
| -} |
| - |
| /******************************************************************** |
| * |
| * Sysctl interface |