From: Jens Axboe <axboe@kernel.dk>
Date: Thu, 19 May 2022 17:31:36 -0600
Subject: random: convert to using fops->read_iter()
Patch-mainline: v5.19-rc1
Git-commit: 1b388e7765f2eaa137cf5d92b47ef5925ad83ced
References: bsc#1204911
This is a pre-requisite to wiring up splice() again for the random
and urandom drivers. It also allows us to remove the INT_MAX check in
getrandom(), because import_single_range() applies capping internally.
Signed-off-by: Jens Axboe <axboe@kernel.dk>
[Jason: rewrote get_random_bytes_user() to simplify and also incorporate
additional suggestions from Al.]
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
[nstange@suse.de: adapted diff context for backport]
Acked-by: Nicolai Stange <nstange@suse.de>
---
drivers/char/random.c | 54 +++++++++++++++++++++++---------------------------
1 file changed, 25 insertions(+), 29 deletions(-)
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1082,27 +1082,20 @@ static void crng_backtrack_protect(__u8
_crng_backtrack_protect(select_crng(), tmp, used);
}
-static ssize_t extract_crng_user(void __user *buf, size_t nbytes)
+static ssize_t extract_crng_user(struct iov_iter *iter)
{
- size_t i, left, ret = 0;
__u8 tmp[CHACHA_BLOCK_SIZE] __aligned(4);
+ size_t ret = 0, copied;
- if (!nbytes)
+ if (unlikely(!iov_iter_count(iter)))
return 0;
for (;;) {
extract_crng(tmp);
- i = min_t(size_t, nbytes, CHACHA_BLOCK_SIZE);
- left = copy_to_user(buf, tmp, i);
- if (left) {
- ret += i - left;
- break;
- }
- buf += i;
- ret += i;
- nbytes -= i;
- if (!nbytes)
+ copied = copy_to_iter(tmp, sizeof(tmp), iter);
+ ret += copied;
+ if (!iov_iter_count(iter) || copied != sizeof(tmp))
break;
BUILD_BUG_ON(PAGE_SIZE % CHACHA_BLOCK_SIZE != 0);
@@ -1112,7 +1105,7 @@ static ssize_t extract_crng_user(void __
cond_resched();
}
}
- crng_backtrack_protect(tmp, i);
+ crng_backtrack_protect(tmp, copied);
/* Wipe data just written to memory */
memzero_explicit(tmp, sizeof(tmp));
@@ -1836,18 +1829,18 @@ void rand_initialize_disk(struct gendisk
#endif
static ssize_t
-urandom_read_nowarn(struct file *file, char __user *buf, size_t nbytes,
- loff_t *ppos)
+urandom_read_nowarn(struct iov_iter *iter)
{
ssize_t ret;
+ size_t nbytes = iov_iter_count(iter);
- ret = extract_crng_user(buf, nbytes);
+ ret = extract_crng_user(iter);
trace_urandom_read(8 * nbytes, 0, ENTROPY_BITS(&input_pool));
return ret;
}
static ssize_t
-urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+urandom_read_iter(struct kiocb *kiocb, struct iov_iter *iter)
{
unsigned long flags;
static int maxwarn = 10;
@@ -1855,25 +1848,25 @@ urandom_read(struct file *file, char __u
if (!crng_ready() && maxwarn > 0) {
maxwarn--;
if (__ratelimit(&urandom_warning))
- pr_notice("%s: uninitialized urandom read (%zd bytes read)\n",
- current->comm, nbytes);
+ pr_notice("%s: uninitialized urandom read (%zu bytes read)\n",
+ current->comm, iov_iter_count(iter));
spin_lock_irqsave(&primary_crng.lock, flags);
crng_init_cnt = 0;
spin_unlock_irqrestore(&primary_crng.lock, flags);
}
- return urandom_read_nowarn(file, buf, nbytes, ppos);
+ return urandom_read_nowarn(iter);
}
static ssize_t
-random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+random_read_iter(struct kiocb *kiocb, struct iov_iter *iter)
{
int ret;
ret = wait_for_random_bytes();
if (ret != 0)
return ret;
- return urandom_read_nowarn(file, buf, nbytes, ppos);
+ return urandom_read_nowarn(iter);
}
static __poll_t
@@ -1998,7 +1991,7 @@ static int random_fasync(int fd, struct
}
const struct file_operations random_fops = {
- .read = random_read,
+ .read_iter = random_read_iter,
.write = random_write,
.poll = random_poll,
.unlocked_ioctl = random_ioctl,
@@ -2008,7 +2001,7 @@ const struct file_operations random_fops
};
const struct file_operations urandom_fops = {
- .read = urandom_read,
+ .read_iter = urandom_read_iter,
.write = random_write,
.unlocked_ioctl = random_ioctl,
.compat_ioctl = compat_ptr_ioctl,
@@ -2019,6 +2012,8 @@ const struct file_operations urandom_fop
SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
unsigned int, flags)
{
+ struct iov_iter iter;
+ struct iovec iov;
int ret;
if (flags & ~(GRND_NONBLOCK|GRND_RANDOM|GRND_INSECURE))
@@ -2031,9 +2026,6 @@ SYSCALL_DEFINE3(getrandom, char __user *
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()) {
if (flags & GRND_NONBLOCK)
return -EAGAIN;
@@ -2041,7 +2033,11 @@ SYSCALL_DEFINE3(getrandom, char __user *
if (unlikely(ret))
return ret;
}
- return urandom_read_nowarn(NULL, buf, count, NULL);
+
+ ret = import_single_range(READ, buf, count, &iov, &iter);
+ if (unlikely(ret))
+ return ret;
+ return urandom_read_nowarn(&iter);
}
/********************************************************************