From: Josef Bacik <jbacik@redhat.com> Date: Tue, 10 Feb 2009 13:49:33 -0500 Subject: [mm] iov_iter_advance fix, don't go off the end Message-id: 1234291777-15344-21-git-send-email-jbacik@redhat.com O-Subject: [PATCH 20/24] [RHEL 5.4] mm: iov_iter_advance fix, don't go off the end Bugzilla: 445433 RH-Acked-by: Jeff Layton <jlayton@redhat.com> This is a backport of upstream commit f7009264c519603b8ec67c881bd368a56703cfc9 94ad374a0751f40d25e22e036c37f7263569d24c and is in reference to bz 445433. This fixes a problem where we can go off the end of the iovec iter because we don't check the count. Signed-off-by: Josef Bacik <jbacik@redhat.com> diff --git a/mm/filemap.c b/mm/filemap.c index 53d78b5..c42c4da 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1981,21 +1981,27 @@ size_t iov_iter_copy_from_user(struct page *page, } EXPORT_SYMBOL(iov_iter_copy_from_user); -static void __iov_iter_advance_iov(struct iov_iter *i, size_t bytes) +void iov_iter_advance(struct iov_iter *i, size_t bytes) { + BUG_ON(i->count < bytes); + if (likely(i->nr_segs == 1)) { i->iov_offset += bytes; + i->count -= bytes; } else { const struct iovec *iov = i->iov; size_t base = i->iov_offset; /* * The !iov->iov_len check ensures we skip over unlikely - * zero-length segments. + * zero-length segments (without overruning the iovec). */ - while (bytes || !iov->iov_len) { - int copy = min(bytes, iov->iov_len - base); + while (bytes || unlikely(i->count && !iov->iov_len)) { + int copy; + copy = min(bytes, iov->iov_len - base); + BUG_ON(!i->count || i->count < copy); + i->count -= copy; bytes -= copy; base += copy; if (iov->iov_len == base) { @@ -2007,14 +2013,6 @@ static void __iov_iter_advance_iov(struct iov_iter *i, size_t bytes) i->iov_offset = base; } } - -void iov_iter_advance(struct iov_iter *i, size_t bytes) -{ - BUG_ON(i->count < bytes); - - __iov_iter_advance_iov(i, bytes); - i->count -= bytes; -} EXPORT_SYMBOL(iov_iter_advance); /*