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.c82
1 files changed, 76 insertions, 6 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index c8224587123f..6c2717d421e8 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
@@ -134,6 +135,7 @@ EXPORT_SYMBOL_GPL(fuse_do_open);
134void fuse_finish_open(struct inode *inode, struct file *file) 135void fuse_finish_open(struct inode *inode, struct file *file)
135{ 136{
136 struct fuse_file *ff = file->private_data; 137 struct fuse_file *ff = file->private_data;
138 struct fuse_conn *fc = get_fuse_conn(inode);
137 139
138 if (ff->open_flags & FOPEN_DIRECT_IO) 140 if (ff->open_flags & FOPEN_DIRECT_IO)
139 file->f_op = &fuse_direct_io_file_operations; 141 file->f_op = &fuse_direct_io_file_operations;
@@ -141,6 +143,15 @@ void fuse_finish_open(struct inode *inode, struct file *file)
141 invalidate_inode_pages2(inode->i_mapping); 143 invalidate_inode_pages2(inode->i_mapping);
142 if (ff->open_flags & FOPEN_NONSEEKABLE) 144 if (ff->open_flags & FOPEN_NONSEEKABLE)
143 nonseekable_open(inode, file); 145 nonseekable_open(inode, file);
146 if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) {
147 struct fuse_inode *fi = get_fuse_inode(inode);
148
149 spin_lock(&fc->lock);
150 fi->attr_version = ++fc->attr_version;
151 i_size_write(inode, 0);
152 spin_unlock(&fc->lock);
153 fuse_invalidate_attr(inode);
154 }
144} 155}
145 156
146int fuse_open_common(struct inode *inode, struct file *file, bool isdir) 157int fuse_open_common(struct inode *inode, struct file *file, bool isdir)
@@ -1617,6 +1628,58 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
1617 return 0; 1628 return 0;
1618} 1629}
1619 1630
1631/* Make sure iov_length() won't overflow */
1632static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count)
1633{
1634 size_t n;
1635 u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT;
1636
1637 for (n = 0; n < count; n++) {
1638 if (iov->iov_len > (size_t) max)
1639 return -ENOMEM;
1640 max -= iov->iov_len;
1641 }
1642 return 0;
1643}
1644
1645/*
1646 * CUSE servers compiled on 32bit broke on 64bit kernels because the
1647 * ABI was defined to be 'struct iovec' which is different on 32bit
1648 * and 64bit. Fortunately we can determine which structure the server
1649 * used from the size of the reply.
1650 */
1651static int fuse_copy_ioctl_iovec(struct iovec *dst, void *src,
1652 size_t transferred, unsigned count,
1653 bool is_compat)
1654{
1655#ifdef CONFIG_COMPAT
1656 if (count * sizeof(struct compat_iovec) == transferred) {
1657 struct compat_iovec *ciov = src;
1658 unsigned i;
1659
1660 /*
1661 * With this interface a 32bit server cannot support
1662 * non-compat (i.e. ones coming from 64bit apps) ioctl
1663 * requests
1664 */
1665 if (!is_compat)
1666 return -EINVAL;
1667
1668 for (i = 0; i < count; i++) {
1669 dst[i].iov_base = compat_ptr(ciov[i].iov_base);
1670 dst[i].iov_len = ciov[i].iov_len;
1671 }
1672 return 0;
1673 }
1674#endif
1675
1676 if (count * sizeof(struct iovec) != transferred)
1677 return -EIO;
1678
1679 memcpy(dst, src, transferred);
1680 return 0;
1681}
1682
1620/* 1683/*
1621 * For ioctls, there is no generic way to determine how much memory 1684 * For ioctls, there is no generic way to determine how much memory
1622 * needs to be read and/or written. Furthermore, ioctls are allowed 1685 * needs to be read and/or written. Furthermore, ioctls are allowed
@@ -1798,18 +1861,25 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
1798 in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV) 1861 in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV)
1799 goto out; 1862 goto out;
1800 1863
1801 err = -EIO;
1802 if ((in_iovs + out_iovs) * sizeof(struct iovec) != transferred)
1803 goto out;
1804
1805 /* okay, copy in iovs and retry */
1806 vaddr = kmap_atomic(pages[0], KM_USER0); 1864 vaddr = kmap_atomic(pages[0], KM_USER0);
1807 memcpy(page_address(iov_page), vaddr, transferred); 1865 err = fuse_copy_ioctl_iovec(page_address(iov_page), vaddr,
1866 transferred, in_iovs + out_iovs,
1867 (flags & FUSE_IOCTL_COMPAT) != 0);
1808 kunmap_atomic(vaddr, KM_USER0); 1868 kunmap_atomic(vaddr, KM_USER0);
1869 if (err)
1870 goto out;
1809 1871
1810 in_iov = page_address(iov_page); 1872 in_iov = page_address(iov_page);
1811 out_iov = in_iov + in_iovs; 1873 out_iov = in_iov + in_iovs;
1812 1874
1875 err = fuse_verify_ioctl_iov(in_iov, in_iovs);
1876 if (err)
1877 goto out;
1878
1879 err = fuse_verify_ioctl_iov(out_iov, out_iovs);
1880 if (err)
1881 goto out;
1882
1813 goto retry; 1883 goto retry;
1814 } 1884 }
1815 1885