| Title: | Linux 2.6.x NTFS __find_get_block_slow() denial of service |
| Description: | The NTFS filesystem module of the Linux 2.6.x kernel fails to properly handle corrupted data structures, leading to an exploitable denial of service condition. This issue is similar to that explained in MOKB-05-11-2006. |
| Author/Contributor: | LMH <lmh[at]info-pull.com> |
| References: | |
| Proof of concept or exploit: |
The following filesystem image can be used to reproduce the bug:
MOKB-19-11-2006.img.bz2 Use a loopback device to mount it: bunzip2 MOKB-19-11-2006.img.bz2 && mount -t ntfs -o loop MOKB-19-11-2006.img /media/test && ls /media/test
|
| Debugging information: |
The bug has been found using the Linux version of fsfuzzer on a Fedora Core 6 installation, with up to date packages as of 18-11-2006. The architecture used to conduct the tests is IA32/x86, SMP enabled. [root@fedoravm ~]# uname -a Linux fedoravm 2.6.18-1.2798.fc6 #1 SMP Mon Oct 16 14:37:32 EDT 2006 i686 i686 i386 GNU/Linux Related debugging information and source code:
----------------------- fs/buffer.c (2.6.18)
1692 void unmap_underlying_metadata(struct block_device *bdev, sector_t block)
1693 {
1694 struct buffer_head *old_bh;
1695
1696 might_sleep();
1697
1698 old_bh = __find_get_block_slow(bdev, block);
1699 if (old_bh) {
1700 clear_buffer_dirty(old_bh);
1701 wait_on_buffer(old_bh);
1702 clear_buffer_req(old_bh);
1703 __brelse(old_bh);
1704 }
1705 }
1706 EXPORT_SYMBOL(unmap_underlying_metadata);
----------------------- fs/buffer.c (2.6.18)
----------------------- fs/buffer.c (2.6.18)
1444 /*
1445 * __getblk will locate (and, if necessary, create) the buffer_head
1446 * which corresponds to the passed block_device, block and size. The
1447 * returned buffer has its reference count incremented.
1448 *
1449 * __getblk() cannot fail - it just keeps trying. If you pass it an
1450 * illegal block number, __getblk() will happily return a buffer_head
1451 * which represents the non-existent block. Very weird.
1452 *
1453 * __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers()
1454 * attempt is failing. FIXME, perhaps?
1455 */
1456 struct buffer_head *
1457 __getblk(struct block_device *bdev, sector_t block, int size)
1458 {
1459 struct buffer_head *bh = __find_get_block(bdev, block, size); <---------- (!)
1460
1461 might_sleep();
1462 if (bh == NULL)
1463 bh = __getblk_slow(bdev, block, size);
1464 return bh;
1465 }
----------------------- fs/buffer.c (2.6.18)
----------------------- fs/buffer.c (2.6.18)
1423 /*
1424 * Perform a pagecache lookup for the matching buffer. If it's there, refresh
1425 * it in the LRU and mark it as accessed. If it is not present then return
1426 * NULL
1427 */
1428 struct buffer_head *
1429 __find_get_block(struct block_device *bdev, sector_t block, int size)
1430 {
1431 struct buffer_head *bh = lookup_bh_lru(bdev, block, size);
1432
1433 if (bh == NULL) {
1434 bh = __find_get_block_slow(bdev, block); <---------- (!)
1435 if (bh)
1436 bh_lru_install(bh);
1437 }
1438 if (bh)
1439 touch_buffer(bh);
1440 return bh;
1441 }
1442 EXPORT_SYMBOL(__find_get_block);
----------------------- fs/buffer.c (2.6.18)
----------------------- fs/buffer.c (2.6.18)
386 __find_get_block_slow(struct block_device *bdev, sector_t block)
387 {
388 struct inode *bd_inode = bdev->bd_inode;
389 struct address_space *bd_mapping = bd_inode->i_mapping;
390 struct buffer_head *ret = NULL;
391 pgoff_t index;
392 struct buffer_head *bh;
393 struct buffer_head *head;
394 struct page *page;
395 int all_mapped = 1;
396
397 index = block >> (PAGE_CACHE_SHIFT - bd_inode->i_blkbits);
398 page = find_get_page(bd_mapping, index);
399 if (!page)
400 goto out;
401
402 spin_lock(&bd_mapping->private_lock);
403 if (!page_has_buffers(page))
404 goto out_unlock;
405 head = page_buffers(page);
406 bh = head;
407 do {
408 if (bh->b_blocknr == block) {
409 ret = bh;
410 get_bh(bh);
411 goto out_unlock;
412 }
413 if (!buffer_mapped(bh))
414 all_mapped = 0; <------
415 bh = bh->b_this_page;
416 } while (bh != head);
417
418 /* we might be here because some of the buffers on this page are
419 * not mapped. This is due to various races between <------\
420 * file io on the block device and getblk. It gets dealt with <-------> 'elsewhere'
421 * elsewhere, don't buffer_error if we had some unmapped buffers <------/
422 */
423 if (all_mapped) {
424 printk("__find_get_block_slow() failed. "
425 "block=%llu, b_blocknr=%llu\n",
426 (unsigned long long)block,
427 (unsigned long long)bh->b_blocknr);
428 printk("b_state=0x%08lx, b_size=%zu\n",
429 bh->b_state, bh->b_size);
430 printk("device blocksize: %d\n", 1 << bd_inode->i_blkbits);
431 }
432 out_unlock:
433 spin_unlock(&bd_mapping->private_lock);
434 page_cache_release(page);
435 out:
436 return ret;
437 }
----------------------- fs/buffer.c (2.6.18)
kernel msg buffer:
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
__find_get_block_slow() failed. block=944892805152, b_blocknr=32
b_state=0x00000020, b_size=512
device blocksize: 512
(...)
|