From 0fc7b9055c2069bdb2fae508cefaeef4d26f86aa Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sat, 30 Dec 2006 18:23:35 -0500 Subject: [PATCH] grow_buffers() infinite loop fix (CVE-2006-5757, CVE-2006-6060) 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 Signed-off-by: Linus Torvalds Signed-off-by: Chris Wright Signed-off-by: Greg Kroah-Hartman --- fs/buffer.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 5b329f0e4f09b..29fc99f833fe3 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1179,8 +1179,21 @@ grow_buffers(struct block_device *bdev, sector_t block, int size) } 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) @@ -1207,12 +1220,16 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) 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(); } } -- 2.47.2