Bug 215419

Summary: CVE-2006-6054 ext2_check_page denial of service
Product: [Fedora] Fedora Reporter: Eric Sandeen <esandeen>
Component: kernelAssignee: Eric Sandeen <esandeen>
Status: CLOSED CURRENTRELEASE QA Contact: Brian Brock <bbrock>
Severity: medium Docs Contact:
Priority: medium    
Version: 6CC: davej, security-response-team, wtogami
Target Milestone: ---   
Target Release: ---   
Hardware: All   
OS: Linux   
URL: http://kernelfun.blogspot.com/2006/11/mokb-09-11-2006-linux-26x-ext2checkpage.html
Whiteboard:
Fixed In Version: kernel-2.6.19-1.2895.fc6 Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2007-01-25 15:45:52 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
upstream patch sent to LKML today none

Description Eric Sandeen 2006-11-13 21:29:33 UTC
The image present at
http://kernelfun.blogspot.com/2006/11/mokb-09-11-2006-linux-26x-ext2checkpage.html
contains a root directory which has a corrupt i_size, which is extremely large.

This causes 

ext2_lookup
	ext2_inode_by_name
		ext2_find_entry

to go off and try to check every page <= i_size (via ext2_check_page()), and of
course each one fails, but there is a huge number to check.  These failures
cause a storm of printk's which could in theory result in a DoS, esp. if you
have only one cpu to work with.

A quick fix for this corruption case would be to simply check the directory size
vs. block count; ext2 directories cannot be sparse so if this fails, we can
abort the operation early:

--- linux-2.6.18.orig/fs/ext2/namei.c
+++ linux-2.6.18/fs/ext2/namei.c
@@ -60,6 +60,12 @@ static struct dentry *ext2_lookup(struct
        if (dentry->d_name.len > EXT2_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
 
+       if (dir->i_size > dir->i_blocks << 9) {
+               printk("corrupted dir #%lu (sparse) len %llu blocks %llu\n",
+                       dir->i_ino, dir->i_size, dir->i_blocks);
+               return ERR_PTR(-EIO);
+       }
+
        ino = ext2_inode_by_name(dir, dentry);
        inode = NULL;
        if (ino) {

This results in an error such as:

EXT2-fs error (device loop0): ext2_readdir: bad page in #2
corrupted dir #2 (sparse) len 3238004736 blocks 4

when we try to look up files in the directory:

[root@bear-04 ~]# cat mnt/*
cat: mnt/*: Input/output error

If the corruption were more intentional, and a very large i_size and i_blocks
correlate, then additional checking might be needed to address this; perhaps
something like keeping a count of the number of bad pages found, and aborting
the operation if it exceeds a threshold...

Alternately, I notice that ext2_readdir aborts on the first bad page it finds,
while ext2_lookup tries to soldier on, page after page.  Seems like maybe these
should be consistent; if so just bailing on the first bad page we find would
catch all cases.

I'll bring this up on the ext4 list.

Comment 1 Eric Sandeen 2006-12-21 19:00:06 UTC
Created attachment 144206 [details]
upstream patch sent to LKML today

Comment 2 Eric Sandeen 2007-01-15 17:24:30 UTC
This fix is now in 2.6.19.2, so when FC6 rebases to that or higher this bug
will be resolved.  Dave, if you want a patch for 2.6.18 FC6 kernels please let
me know.

Comment 3 Eric Sandeen 2007-01-25 15:45:52 UTC
kernel-2.6.19-1.2895.fc6 from fc6 updates has this fixed now.

Thanks,
-Eric