random: convert to using fops->write_iter()
authorJens Axboe <axboe@kernel.dk>
Thu, 19 May 2022 23:43:15 +0000 (17:43 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 30 May 2022 07:29:18 +0000 (09:29 +0200)
commit 22b0a222af4df8ee9bb8e07013ab44da9511b047 upstream.

Now that the read side has been converted to fix a regression with
splice, convert the write side as well to have some symmetry in the
interface used (and help deprecate ->write()).

Signed-off-by: Jens Axboe <axboe@kernel.dk>
[Jason: cleaned up random_ioctl a bit, require full writes in
 RNDADDENTROPY since it's crediting entropy, simplify control flow of
 write_pool(), and incorporate suggestions from Al.]
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/char/random.c

index 50af5da..e950f2f 100644 (file)
@@ -1255,39 +1255,31 @@ static __poll_t random_poll(struct file *file, poll_table *wait)
        return crng_ready() ? EPOLLIN | EPOLLRDNORM : EPOLLOUT | EPOLLWRNORM;
 }
 
-static int write_pool(const char __user *ubuf, size_t len)
+static ssize_t write_pool(struct iov_iter *iter)
 {
-       size_t block_len;
-       int ret = 0;
        u8 block[BLAKE2S_BLOCK_SIZE];
+       ssize_t ret = 0;
+       size_t copied;
 
-       while (len) {
-               block_len = min(len, sizeof(block));
-               if (copy_from_user(block, ubuf, block_len)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               len -= block_len;
-               ubuf += block_len;
-               mix_pool_bytes(block, block_len);
+       if (unlikely(!iov_iter_count(iter)))
+               return 0;
+
+       for (;;) {
+               copied = copy_from_iter(block, sizeof(block), iter);
+               ret += copied;
+               mix_pool_bytes(block, copied);
+               if (!iov_iter_count(iter) || copied != sizeof(block))
+                       break;
                cond_resched();
        }
 
-out:
        memzero_explicit(block, sizeof(block));
-       return ret;
+       return ret ? ret : -EFAULT;
 }
 
-static ssize_t random_write(struct file *file, const char __user *ubuf,
-                           size_t len, loff_t *ppos)
+static ssize_t random_write_iter(struct kiocb *kiocb, struct iov_iter *iter)
 {
-       int ret;
-
-       ret = write_pool(ubuf, len);
-       if (ret)
-               return ret;
-
-       return (ssize_t)len;
+       return write_pool(iter);
 }
 
 static ssize_t urandom_read_iter(struct kiocb *kiocb, struct iov_iter *iter)
@@ -1319,9 +1311,8 @@ static ssize_t random_read_iter(struct kiocb *kiocb, struct iov_iter *iter)
 
 static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
 {
-       int size, ent_count;
        int __user *p = (int __user *)arg;
-       int retval;
+       int ent_count;
 
        switch (cmd) {
        case RNDGETENTCNT:
@@ -1338,20 +1329,32 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
                        return -EINVAL;
                credit_init_bits(ent_count);
                return 0;
-       case RNDADDENTROPY:
+       case RNDADDENTROPY: {
+               struct iov_iter iter;
+               struct iovec iov;
+               ssize_t ret;
+               int len;
+
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
                if (get_user(ent_count, p++))
                        return -EFAULT;
                if (ent_count < 0)
                        return -EINVAL;
-               if (get_user(size, p++))
+               if (get_user(len, p++))
+                       return -EFAULT;
+               ret = import_single_range(WRITE, p, len, &iov, &iter);
+               if (unlikely(ret))
+                       return ret;
+               ret = write_pool(&iter);
+               if (unlikely(ret < 0))
+                       return ret;
+               /* Since we're crediting, enforce that it was all written into the pool. */
+               if (unlikely(ret != len))
                        return -EFAULT;
-               retval = write_pool((const char __user *)p, size);
-               if (retval < 0)
-                       return retval;
                credit_init_bits(ent_count);
                return 0;
+       }
        case RNDZAPENTCNT:
        case RNDCLEARPOOL:
                /* No longer has any effect. */
@@ -1377,7 +1380,7 @@ static int random_fasync(int fd, struct file *filp, int on)
 
 const struct file_operations random_fops = {
        .read_iter = random_read_iter,
-       .write = random_write,
+       .write_iter = random_write_iter,
        .poll = random_poll,
        .unlocked_ioctl = random_ioctl,
        .compat_ioctl = compat_ptr_ioctl,
@@ -1387,7 +1390,7 @@ const struct file_operations random_fops = {
 
 const struct file_operations urandom_fops = {
        .read_iter = urandom_read_iter,
-       .write = random_write,
+       .write_iter = random_write_iter,
        .unlocked_ioctl = random_ioctl,
        .compat_ioctl = compat_ptr_ioctl,
        .fasync = random_fasync,