Message ID | 1327920160-30601-2-git-send-email-apw@canonical.com |
---|---|
State | New |
Headers | show |
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>
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 >
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; }