Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2233

kernel-2.6.18-238.el5.src.rpm

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);
 
 /*