| From a21102b55c4f8dfd3adb4a15a34cd62237b46039 Mon Sep 17 00:00:00 2001 |
| From: Theodore Ts'o <tytso@mit.edu> |
| Date: Fri, 16 Jan 2009 11:13:47 -0500 |
| Subject: ext3: Add sanity check to make_indexed_dir |
| |
| From: Theodore Ts'o <tytso@mit.edu> |
| |
| commit a21102b55c4f8dfd3adb4a15a34cd62237b46039 upstream. |
| |
| Make sure the rec_len field in the '..' entry is sane, lest we overrun |
| the directory block and cause a kernel oops on a purposefully |
| corrupted filesystem. |
| |
| This fixes a bug related to a bug originally reported by Sami Liedes |
| for ext4 at: |
| |
| http://bugzilla.kernel.org/show_bug.cgi?id=12430 |
| |
| Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| fs/ext3/namei.c | 20 ++++++++++++++------ |
| 1 file changed, 14 insertions(+), 6 deletions(-) |
| |
| --- a/fs/ext3/namei.c |
| +++ b/fs/ext3/namei.c |
| @@ -1374,7 +1374,7 @@ static int make_indexed_dir(handle_t *ha |
| struct fake_dirent *fde; |
| |
| blocksize = dir->i_sb->s_blocksize; |
| - dxtrace(printk("Creating index\n")); |
| + dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); |
| retval = ext3_journal_get_write_access(handle, bh); |
| if (retval) { |
| ext3_std_error(dir->i_sb, retval); |
| @@ -1383,6 +1383,19 @@ static int make_indexed_dir(handle_t *ha |
| } |
| root = (struct dx_root *) bh->b_data; |
| |
| + /* The 0th block becomes the root, move the dirents out */ |
| + fde = &root->dotdot; |
| + de = (struct ext3_dir_entry_2 *)((char *)fde + |
| + ext3_rec_len_from_disk(fde->rec_len)); |
| + if ((char *) de >= (((char *) root) + blocksize)) { |
| + ext3_error(dir->i_sb, __func__, |
| + "invalid rec_len for '..' in inode %lu", |
| + dir->i_ino); |
| + brelse(bh); |
| + return -EIO; |
| + } |
| + len = ((char *) root) + blocksize - (char *) de; |
| + |
| bh2 = ext3_append (handle, dir, &block, &retval); |
| if (!(bh2)) { |
| brelse(bh); |
| @@ -1391,11 +1404,6 @@ static int make_indexed_dir(handle_t *ha |
| EXT3_I(dir)->i_flags |= EXT3_INDEX_FL; |
| data1 = bh2->b_data; |
| |
| - /* The 0th block becomes the root, move the dirents out */ |
| - fde = &root->dotdot; |
| - de = (struct ext3_dir_entry_2 *)((char *)fde + |
| - ext3_rec_len_from_disk(fde->rec_len)); |
| - len = ((char *) root) + blocksize - (char *) de; |
| memcpy (data1, de, len); |
| de = (struct ext3_dir_entry_2 *) data1; |
| top = data1 + len; |