aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2008-03-10 14:43:59 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-03-10 21:01:20 -0400
commitf7009264c519603b8ec67c881bd368a56703cfc9 (patch)
tree163c2fa590e3de5c9084f1cba5c1c2815dbd2dde /mm
parent21bbb39c376ce6beeeb549d155f0d53dc76ed000 (diff)
iov_iter_advance() fix
iov_iter_advance() skips over zero-length iovecs, however it does not properly terminate at the end of the iovec array. Fix this by checking against i->count before we skip a zero-length iov. The bug was reproduced with a test program that continually randomly creates iovs to writev. The fix was also verified with the same program and also it could verify that the correct data was contained in the file after each writev. Signed-off-by: Nick Piggin <npiggin@suse.de> Tested-by: "Kevin Coffman" <kwc@citi.umich.edu> Cc: "Alexey Dobriyan" <adobriyan@gmail.com> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/filemap.c22
1 files changed, 10 insertions, 12 deletions
diff --git a/mm/filemap.c b/mm/filemap.c
index ab98557e228e..df343d1e6345 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1742,21 +1742,27 @@ size_t iov_iter_copy_from_user(struct page *page,
1742} 1742}
1743EXPORT_SYMBOL(iov_iter_copy_from_user); 1743EXPORT_SYMBOL(iov_iter_copy_from_user);
1744 1744
1745static void __iov_iter_advance_iov(struct iov_iter *i, size_t bytes) 1745void iov_iter_advance(struct iov_iter *i, size_t bytes)
1746{ 1746{
1747 BUG_ON(i->count < bytes);
1748
1747 if (likely(i->nr_segs == 1)) { 1749 if (likely(i->nr_segs == 1)) {
1748 i->iov_offset += bytes; 1750 i->iov_offset += bytes;
1751 i->count -= bytes;
1749 } else { 1752 } else {
1750 const struct iovec *iov = i->iov; 1753 const struct iovec *iov = i->iov;
1751 size_t base = i->iov_offset; 1754 size_t base = i->iov_offset;
1752 1755
1753 /* 1756 /*
1754 * The !iov->iov_len check ensures we skip over unlikely 1757 * The !iov->iov_len check ensures we skip over unlikely
1755 * zero-length segments. 1758 * zero-length segments (without overruning the iovec).
1756 */ 1759 */
1757 while (bytes || !iov->iov_len) { 1760 while (bytes || unlikely(!iov->iov_len && i->count)) {
1758 int copy = min(bytes, iov->iov_len - base); 1761 int copy;
1759 1762
1763 copy = min(bytes, iov->iov_len - base);
1764 BUG_ON(!i->count || i->count < copy);
1765 i->count -= copy;
1760 bytes -= copy; 1766 bytes -= copy;
1761 base += copy; 1767 base += copy;
1762 if (iov->iov_len == base) { 1768 if (iov->iov_len == base) {
@@ -1768,14 +1774,6 @@ static void __iov_iter_advance_iov(struct iov_iter *i, size_t bytes)
1768 i->iov_offset = base; 1774 i->iov_offset = base;
1769 } 1775 }
1770} 1776}
1771
1772void iov_iter_advance(struct iov_iter *i, size_t bytes)
1773{
1774 BUG_ON(i->count < bytes);
1775
1776 __iov_iter_advance_iov(i, bytes);
1777 i->count -= bytes;
1778}
1779EXPORT_SYMBOL(iov_iter_advance); 1777EXPORT_SYMBOL(iov_iter_advance);
1780 1778
1781/* 1779/*