MOKB-17-11-2006

Bug details
Title: Linux 2.6.x minix_bmap denial of service
Description: Linux 2.6.x minix filesystem code fails to properly handle corrupted data structures, leading to an exploitable denial of service issue when a crafted fs stream is being mounted.

Note: Many of these DoS related issues are actually caused by integer overflow and signedness problems, although, as these are extremely common (in the Linux kernel, that is), it became a tedious task to track them all. Have fun grep'ing around.
Author/Contributor:
References:
Proof of concept or exploit: The following minix filesystem image can be used to reproduce the bug: MOKB-17-11-2006.img.bz2
Use a loopback device to mount it: bunzip2 MOKB-17-11-2006.img.bz2 && mount -t minix -o loop MOKB-17-11-2006.img /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 16-11-2006. No operation except mount itself is necessary to trigger the bug. The architecture used to conduct the tests is IA32/x86, SMP enabled.

[root@fedora ~]# uname -a
Linux fedora 2.6.18-1.2798.fc6 #1 SMP Mon Oct 16 14:37:32 EDT 2006 i686 i686 i386 GNU/Linux

MINIX-fs: mounting unchecked file system, running fsck is recommended
Buffer I/O error on device loop0, logical block 53248
Buffer I/O error on device loop0, logical block 53248
Buffer I/O error on device loop0, logical block 63744
Buffer I/O error on device loop0, logical block 63744
Buffer I/O error on device loop0, logical block 29952
Buffer I/O error on device loop0, logical block 29952
Buffer I/O error on device loop0, logical block 8960
Buffer I/O error on device loop0, logical block 8960
Buffer I/O error on device loop0, logical block 33024
Buffer I/O error on device loop0, logical block 33024
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
minix_bmap: block>big
(... infinite loop ....)

334 static sector_t minix_bmap(struct address_space *mapping, sector_t block)
335 {
336         return generic_block_bmap(mapping,block,minix_get_block);
337 }
338 static const struct address_space_operations minix_aops = {
339         .readpage = minix_readpage,
340         .writepage = minix_writepage,
341         .sync_page = block_sync_page,
342         .prepare_write = minix_prepare_write,
343         .commit_write = generic_commit_write,
344         .bmap = minix_bmap
345 };

 23 static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
 24 {
 25         int n = 0;
 26 
 27         if (block < 0) {
 28                 printk("minix_bmap: block<0\n");
 29         } else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) {
 30                 printk("minix_bmap: block>big\n");
 31         } else if (block < 7) {
 32                 offsets[n++] = block;
 33         } else if ((block -= 7) < 256) {
 34                 offsets[n++] = 7;
 35                 offsets[n++] = block;
 36         } else if ((block -= 256) < 256*256) {
 37                 offsets[n++] = 8;
 38                 offsets[n++] = block>>8;
 39                 offsets[n++] = block & 255;
 40         } else {
 41                 block -= 256*256;
 42                 offsets[n++] = 9;
 43                 offsets[n++] = block>>16;
 44                 offsets[n++] = (block>>8) & 255;
 45                 offsets[n++] = block & 255;
 46         }
 47         return n;

 27 #define BLOCK_SIZE_BITS 10
 28 #define BLOCK_SIZE (1<