aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r--fs/fuse/file.c50
1 files changed, 44 insertions, 6 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 9242d294fe90..0e2e25b114a6 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -13,6 +13,7 @@
13#include <linux/kernel.h> 13#include <linux/kernel.h>
14#include <linux/sched.h> 14#include <linux/sched.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/compat.h>
16 17
17static const struct file_operations fuse_direct_io_file_operations; 18static const struct file_operations fuse_direct_io_file_operations;
18 19
@@ -1628,6 +1629,44 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
1628} 1629}
1629 1630
1630/* 1631/*
1632 * CUSE servers compiled on 32bit broke on 64bit kernels because the
1633 * ABI was defined to be 'struct iovec' which is different on 32bit
1634 * and 64bit. Fortunately we can determine which structure the server
1635 * used from the size of the reply.
1636 */
1637static int fuse_copy_ioctl_iovec(struct iovec *dst, void *src,
1638 size_t transferred, unsigned count,
1639 bool is_compat)
1640{
1641#ifdef CONFIG_COMPAT
1642 if (count * sizeof(struct compat_iovec) == transferred) {
1643 struct compat_iovec *ciov = src;
1644 unsigned i;
1645
1646 /*
1647 * With this interface a 32bit server cannot support
1648 * non-compat (i.e. ones coming from 64bit apps) ioctl
1649 * requests
1650 */
1651 if (!is_compat)
1652 return -EINVAL;
1653
1654 for (i = 0; i < count; i++) {
1655 dst[i].iov_base = compat_ptr(ciov[i].iov_base);
1656 dst[i].iov_len = ciov[i].iov_len;
1657 }
1658 return 0;
1659 }
1660#endif
1661
1662 if (count * sizeof(struct iovec) != transferred)
1663 return -EIO;
1664
1665 memcpy(dst, src, transferred);
1666 return 0;
1667}
1668
1669/*
1631 * For ioctls, there is no generic way to determine how much memory 1670 * For ioctls, there is no generic way to determine how much memory
1632 * needs to be read and/or written. Furthermore, ioctls are allowed 1671 * needs to be read and/or written. Furthermore, ioctls are allowed
1633 * to dereference the passed pointer, so the parameter requires deep 1672 * to dereference the passed pointer, so the parameter requires deep
@@ -1808,14 +1847,13 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
1808 in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV) 1847 in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV)
1809 goto out; 1848 goto out;
1810 1849
1811 err = -EIO;
1812 if ((in_iovs + out_iovs) * sizeof(struct iovec) != transferred)
1813 goto out;
1814
1815 /* okay, copy in iovs and retry */
1816 vaddr = kmap_atomic(pages[0], KM_USER0); 1850 vaddr = kmap_atomic(pages[0], KM_USER0);
1817 memcpy(page_address(iov_page), vaddr, transferred); 1851 err = fuse_copy_ioctl_iovec(page_address(iov_page), vaddr,
1852 transferred, in_iovs + out_iovs,
1853 (flags & FUSE_IOCTL_COMPAT) != 0);
1818 kunmap_atomic(vaddr, KM_USER0); 1854 kunmap_atomic(vaddr, KM_USER0);
1855 if (err)
1856 goto out;
1819 1857
1820 in_iov = page_address(iov_page); 1858 in_iov = page_address(iov_page);
1821 out_iov = in_iov + in_iovs; 1859 out_iov = in_iov + in_iovs;