|
@@ -2326,33 +2326,6 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence)
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
-static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
|
|
|
|
- unsigned int nr_segs, size_t bytes, bool to_user)
|
|
|
|
-{
|
|
|
|
- struct iov_iter ii;
|
|
|
|
- int page_idx = 0;
|
|
|
|
-
|
|
|
|
- if (!bytes)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- iov_iter_init(&ii, to_user ? READ : WRITE, iov, nr_segs, bytes);
|
|
|
|
-
|
|
|
|
- while (iov_iter_count(&ii)) {
|
|
|
|
- struct page *page = pages[page_idx++];
|
|
|
|
- size_t copied;
|
|
|
|
-
|
|
|
|
- if (!to_user)
|
|
|
|
- copied = copy_page_from_iter(page, 0, PAGE_SIZE, &ii);
|
|
|
|
- else
|
|
|
|
- copied = copy_page_to_iter(page, 0, PAGE_SIZE, &ii);
|
|
|
|
-
|
|
|
|
- if (unlikely(copied != PAGE_SIZE && iov_iter_count(&ii)))
|
|
|
|
- return -EFAULT;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* CUSE servers compiled on 32bit broke on 64bit kernels because the
|
|
* CUSE servers compiled on 32bit broke on 64bit kernels because the
|
|
* ABI was defined to be 'struct iovec' which is different on 32bit
|
|
* ABI was defined to be 'struct iovec' which is different on 32bit
|
|
@@ -2504,8 +2477,9 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
|
|
struct iovec *iov_page = NULL;
|
|
struct iovec *iov_page = NULL;
|
|
struct iovec *in_iov = NULL, *out_iov = NULL;
|
|
struct iovec *in_iov = NULL, *out_iov = NULL;
|
|
unsigned int in_iovs = 0, out_iovs = 0, num_pages = 0, max_pages;
|
|
unsigned int in_iovs = 0, out_iovs = 0, num_pages = 0, max_pages;
|
|
- size_t in_size, out_size, transferred;
|
|
|
|
- int err;
|
|
|
|
|
|
+ size_t in_size, out_size, transferred, c;
|
|
|
|
+ int err, i;
|
|
|
|
+ struct iov_iter ii;
|
|
|
|
|
|
#if BITS_PER_LONG == 32
|
|
#if BITS_PER_LONG == 32
|
|
inarg.flags |= FUSE_IOCTL_32BIT;
|
|
inarg.flags |= FUSE_IOCTL_32BIT;
|
|
@@ -2587,10 +2561,13 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
|
|
req->in.args[1].size = in_size;
|
|
req->in.args[1].size = in_size;
|
|
req->in.argpages = 1;
|
|
req->in.argpages = 1;
|
|
|
|
|
|
- err = fuse_ioctl_copy_user(pages, in_iov, in_iovs, in_size,
|
|
|
|
- false);
|
|
|
|
- if (err)
|
|
|
|
- goto out;
|
|
|
|
|
|
+ err = -EFAULT;
|
|
|
|
+ iov_iter_init(&ii, WRITE, in_iov, in_iovs, in_size);
|
|
|
|
+ for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= num_pages); i++) {
|
|
|
|
+ c = copy_page_from_iter(pages[i], 0, PAGE_SIZE, &ii);
|
|
|
|
+ if (c != PAGE_SIZE && iov_iter_count(&ii))
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
req->out.numargs = 2;
|
|
req->out.numargs = 2;
|
|
@@ -2656,7 +2633,14 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
|
|
if (transferred > inarg.out_size)
|
|
if (transferred > inarg.out_size)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- err = fuse_ioctl_copy_user(pages, out_iov, out_iovs, transferred, true);
|
|
|
|
|
|
+ err = -EFAULT;
|
|
|
|
+ iov_iter_init(&ii, READ, out_iov, out_iovs, transferred);
|
|
|
|
+ for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= num_pages); i++) {
|
|
|
|
+ c = copy_page_to_iter(pages[i], 0, PAGE_SIZE, &ii);
|
|
|
|
+ if (c != PAGE_SIZE && iov_iter_count(&ii))
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ err = 0;
|
|
out:
|
|
out:
|
|
if (req)
|
|
if (req)
|
|
fuse_put_request(fc, req);
|
|
fuse_put_request(fc, req);
|