random: convert to using fops->write_iter()
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>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
affa1ae522
commit
cf8f8d3758
@@ -1255,39 +1255,31 @@ static __poll_t random_poll(struct file *file, poll_table *wait)
|
|||||||
return crng_ready() ? EPOLLIN | EPOLLRDNORM : EPOLLOUT | EPOLLWRNORM;
|
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];
|
u8 block[BLAKE2S_BLOCK_SIZE];
|
||||||
|
ssize_t ret = 0;
|
||||||
|
size_t copied;
|
||||||
|
|
||||||
while (len) {
|
if (unlikely(!iov_iter_count(iter)))
|
||||||
block_len = min(len, sizeof(block));
|
return 0;
|
||||||
if (copy_from_user(block, ubuf, block_len)) {
|
|
||||||
ret = -EFAULT;
|
for (;;) {
|
||||||
goto out;
|
copied = copy_from_iter(block, sizeof(block), iter);
|
||||||
}
|
ret += copied;
|
||||||
len -= block_len;
|
mix_pool_bytes(block, copied);
|
||||||
ubuf += block_len;
|
if (!iov_iter_count(iter) || copied != sizeof(block))
|
||||||
mix_pool_bytes(block, block_len);
|
break;
|
||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
memzero_explicit(block, sizeof(block));
|
memzero_explicit(block, sizeof(block));
|
||||||
return ret;
|
return ret ? ret : -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t random_write(struct file *file, const char __user *ubuf,
|
static ssize_t random_write_iter(struct kiocb *kiocb, struct iov_iter *iter)
|
||||||
size_t len, loff_t *ppos)
|
|
||||||
{
|
{
|
||||||
int ret;
|
return write_pool(iter);
|
||||||
|
|
||||||
ret = write_pool(ubuf, len);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return (ssize_t)len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t urandom_read_iter(struct kiocb *kiocb, struct iov_iter *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)
|
static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
int size, ent_count;
|
|
||||||
int __user *p = (int __user *)arg;
|
int __user *p = (int __user *)arg;
|
||||||
int retval;
|
int ent_count;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case RNDGETENTCNT:
|
case RNDGETENTCNT:
|
||||||
@@ -1338,20 +1329,32 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
credit_init_bits(ent_count);
|
credit_init_bits(ent_count);
|
||||||
return 0;
|
return 0;
|
||||||
case RNDADDENTROPY:
|
case RNDADDENTROPY: {
|
||||||
|
struct iov_iter iter;
|
||||||
|
struct iovec iov;
|
||||||
|
ssize_t ret;
|
||||||
|
int len;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (get_user(ent_count, p++))
|
if (get_user(ent_count, p++))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (ent_count < 0)
|
if (ent_count < 0)
|
||||||
return -EINVAL;
|
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;
|
return -EFAULT;
|
||||||
retval = write_pool((const char __user *)p, size);
|
|
||||||
if (retval < 0)
|
|
||||||
return retval;
|
|
||||||
credit_init_bits(ent_count);
|
credit_init_bits(ent_count);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
case RNDZAPENTCNT:
|
case RNDZAPENTCNT:
|
||||||
case RNDCLEARPOOL:
|
case RNDCLEARPOOL:
|
||||||
/* No longer has any effect. */
|
/* 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 = {
|
const struct file_operations random_fops = {
|
||||||
.read_iter = random_read_iter,
|
.read_iter = random_read_iter,
|
||||||
.write = random_write,
|
.write_iter = random_write_iter,
|
||||||
.poll = random_poll,
|
.poll = random_poll,
|
||||||
.unlocked_ioctl = random_ioctl,
|
.unlocked_ioctl = random_ioctl,
|
||||||
.compat_ioctl = compat_ptr_ioctl,
|
.compat_ioctl = compat_ptr_ioctl,
|
||||||
@@ -1387,7 +1390,7 @@ const struct file_operations random_fops = {
|
|||||||
|
|
||||||
const struct file_operations urandom_fops = {
|
const struct file_operations urandom_fops = {
|
||||||
.read_iter = urandom_read_iter,
|
.read_iter = urandom_read_iter,
|
||||||
.write = random_write,
|
.write_iter = random_write_iter,
|
||||||
.unlocked_ioctl = random_ioctl,
|
.unlocked_ioctl = random_ioctl,
|
||||||
.compat_ioctl = compat_ptr_ioctl,
|
.compat_ioctl = compat_ptr_ioctl,
|
||||||
.fasync = random_fasync,
|
.fasync = random_fasync,
|
||||||
|
Reference in New Issue
Block a user