Sophie

Sophie

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

kernel-2.6.18-238.el5.src.rpm

From: Eric Sandeen <esandeen@redhat.com>
Subject: [PATCH RHEL5] catch blocks beyond pagecache limit in __getblk_slow
Date: Tue, 7 Nov 2006 10:03:45 -0600
Bugzilla: 214419
Message-Id: <200611071603.kA7G3jgQ008705@neon.msp.redhat.com>
Changelog: catch blocks beyond pagecache limit in __getblk_slow


And, the RHEL5 version:

Addresses:
Bugzilla Bug 214419: CVE-2006-5757 ISO9660 __find_get_block_slow() denial of service

X-Git-Tag: v2.6.19-rc2
X-Git-Url: http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=e5657933863f43cc6bb76a54d659303dafaa9e58

[PATCH] grow_buffers() infinite loop fix

If grow_buffers() is for some reason passed a block number which wants to lie
outside the maximum-addressable pagecache range (PAGE_SIZE * 4G bytes) then it
will accidentally truncate `index' and will then instnatiate a page at the
wrong pagecache offset.  This causes __getblk_slow() to go into an infinite
loop.

This can happen with corrupted disks, or with software errors elsewhere.

Detect that, and handle it.

Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

Index: latest/fs/buffer.c
===================================================================
--- latest.orig/fs/buffer.c
+++ latest/fs/buffer.c
@@ -1181,8 +1181,21 @@ grow_buffers(struct block_device *bdev, 
 	} while ((size << sizebits) < PAGE_SIZE);
 
 	index = block >> sizebits;
-	block = index << sizebits;
 
+	/*
+	 * Check for a block which wants to lie outside our maximum possible
+	 * pagecache index.  (this comparison is done using sector_t types).
+	 */
+	if (unlikely(index != block >> sizebits)) {
+		char b[BDEVNAME_SIZE];
+
+		printk(KERN_ERR "%s: requested out-of-range block %llu for "
+			"device %s\n",
+			__FUNCTION__, (unsigned long long)block,
+			bdevname(bdev, b));
+		return -EIO;
+	}
+	block = index << sizebits;
 	/* Create a page with the proper size buffers.. */
 	page = grow_dev_page(bdev, block, index, size);
 	if (!page)
@@ -1209,12 +1222,16 @@ __getblk_slow(struct block_device *bdev,
 
 	for (;;) {
 		struct buffer_head * bh;
+		int ret;
 
 		bh = __find_get_block(bdev, block, size);
 		if (bh)
 			return bh;
 
-		if (!grow_buffers(bdev, block, size))
+		ret = grow_buffers(bdev, block, size);
+		if (ret < 0)
+			return NULL;
+		if (ret == 0)
 			free_more_memory();
 	}
 }