Patchwork [maverick/ti-omap4,CVE,1/1] fuse: verify ioctl retries

login
register
mail settings
Submitter Andy Whitcroft
Date Jan. 30, 2012, 10:42 a.m.
Message ID <1327920160-30601-2-git-send-email-apw@canonical.com>
Download mbox | patch
Permalink /patch/138547/
State New
Headers show

Comments

Andy Whitcroft - Jan. 30, 2012, 10:42 a.m.
From: Miklos Szeredi <mszeredi@suse.cz>

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>
CC: <stable@kernel.org>         [2.6.31+]

(backported from commit 7572777eef78ebdee1ecb7c258c0ef94d35bad16)
CVE-2010-4650
BugLink: http://bugs.launchpad.net/bugs/917804
Signed-off-by: Andy Whitcroft <apw@canonical.com>
---
 fs/fuse/file.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)
Stefan Bader - Jan. 30, 2012, 11:35 a.m.
On 30.01.2012 11:42, Andy Whitcroft wrote:
> From: Miklos Szeredi <mszeredi@suse.cz>
> 
> 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>
> CC: <stable@kernel.org>         [2.6.31+]
> 
> (backported from commit 7572777eef78ebdee1ecb7c258c0ef94d35bad16)
> CVE-2010-4650
> BugLink: http://bugs.launchpad.net/bugs/917804
> Signed-off-by: Andy Whitcroft <apw@canonical.com>
> ---
>  fs/fuse/file.c |   22 ++++++++++++++++++++++
>  1 files changed, 22 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index ada0ade..0459219 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -1617,6 +1617,20 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
>  	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
> @@ -1810,6 +1824,14 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
>  		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;
>  	}
>  

Backport looks ok.

Acked-by: Stefan Bader <stefan.bader@canonical.com>
Herton Ronaldo Krzesinski - Jan. 30, 2012, 12:12 p.m.
On Mon, Jan 30, 2012 at 10:42:40AM +0000, Andy Whitcroft wrote:
> From: Miklos Szeredi <mszeredi@suse.cz>
> 
> 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>
> CC: <stable@kernel.org>         [2.6.31+]
> 
> (backported from commit 7572777eef78ebdee1ecb7c258c0ef94d35bad16)
> CVE-2010-4650
> BugLink: http://bugs.launchpad.net/bugs/917804
> Signed-off-by: Andy Whitcroft <apw@canonical.com>
> ---
>  fs/fuse/file.c |   22 ++++++++++++++++++++++
>  1 files changed, 22 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index ada0ade..0459219 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -1617,6 +1617,20 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
>  	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
> @@ -1810,6 +1824,14 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
>  		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;
>  	}
>  
> -- 
> 1.7.5.4
> 
> 
> -- 
> kernel-team mailing list
> kernel-team@lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team
>

Patch

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index ada0ade..0459219 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1617,6 +1617,20 @@  static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
 	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
@@ -1810,6 +1824,14 @@  long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
 		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;
 	}