| From 7572777eef78ebdee1ecb7c258c0ef94d35bad16 Mon Sep 17 00:00:00 2001 |
| From: Miklos Szeredi <mszeredi@suse.cz> |
| Date: Tue, 30 Nov 2010 16:39:27 +0100 |
| Subject: fuse: verify ioctl retries |
| |
| From: Miklos Szeredi <mszeredi@suse.cz> |
| |
| commit 7572777eef78ebdee1ecb7c258c0ef94d35bad16 upstream. |
| |
| Verify that the total length of the iovec returned in FUSE_IOCTL_RETRY |
| doesn't overflow iov_length(). |
| |
| Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> |
| CC: Tejun Heo <tj@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| fs/fuse/file.c | 22 ++++++++++++++++++++++ |
| 1 file changed, 22 insertions(+) |
| |
| --- a/fs/fuse/file.c |
| +++ b/fs/fuse/file.c |
| @@ -1627,6 +1627,20 @@ static int fuse_ioctl_copy_user(struct p |
| return 0; |
| } |
| |
| +/* Make sure iov_length() won't overflow */ |
| +static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count) |
| +{ |
| + size_t n; |
| + u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT; |
| + |
| + for (n = 0; n < count; n++) { |
| + if (iov->iov_len > (size_t) max) |
| + return -ENOMEM; |
| + max -= iov->iov_len; |
| + } |
| + return 0; |
| +} |
| + |
| /* |
| * For ioctls, there is no generic way to determine how much memory |
| * needs to be read and/or written. Furthermore, ioctls are allowed |
| @@ -1820,6 +1834,14 @@ long fuse_do_ioctl(struct file *file, un |
| in_iov = page_address(iov_page); |
| out_iov = in_iov + in_iovs; |
| |
| + err = fuse_verify_ioctl_iov(in_iov, in_iovs); |
| + if (err) |
| + goto out; |
| + |
| + err = fuse_verify_ioctl_iov(out_iov, out_iovs); |
| + if (err) |
| + goto out; |
| + |
| goto retry; |
| } |
| |