diff options
author | Theodore Ts'o <tytso@mit.edu> | 2009-04-24 13:43:20 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-04-24 13:43:20 -0400 |
commit | 485c26ec70f823f2a9cf45982b724893e53a859e (patch) | |
tree | 545ee089625b9b4131773eb26c57a51889deda78 /fs/ext4/inode.c | |
parent | 0c8454f56623505a99463405fd7d5664adfbb094 (diff) |
ext4: Fix softlockup caused by illegal i_file_acl value in on-disk inode
If the block containing external extended attributes (which is stored
in i_file_acl and i_file_acl_high) is larger than the on-disk
filesystem, the process which tried to access the extended attributes
will endlessly issue kernel printks complaining that
"__find_get_block_slow() failed", locking up that CPU until the system
is forcibly rebooted.
So when we read in the inode, make sure the i_file_acl value is legal,
and if not, flag the filesystem as being corrupted.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c6bd6ced3bb7..cab75bbcd57b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -4409,7 +4409,17 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4409 | (__u64)(le32_to_cpu(raw_inode->i_version_hi)) << 32; | 4409 | (__u64)(le32_to_cpu(raw_inode->i_version_hi)) << 32; |
4410 | } | 4410 | } |
4411 | 4411 | ||
4412 | if (ei->i_flags & EXT4_EXTENTS_FL) { | 4412 | if (ei->i_file_acl && |
4413 | ((ei->i_file_acl < | ||
4414 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) + | ||
4415 | EXT4_SB(sb)->s_gdb_count)) || | ||
4416 | (ei->i_file_acl >= ext4_blocks_count(EXT4_SB(sb)->s_es)))) { | ||
4417 | ext4_error(sb, __func__, | ||
4418 | "bad extended attribute block %llu in inode #%lu", | ||
4419 | ei->i_file_acl, inode->i_ino); | ||
4420 | ret = -EIO; | ||
4421 | goto bad_inode; | ||
4422 | } else if (ei->i_flags & EXT4_EXTENTS_FL) { | ||
4413 | /* Validate extent which is part of inode */ | 4423 | /* Validate extent which is part of inode */ |
4414 | ret = ext4_ext_check_inode(inode); | 4424 | ret = ext4_ext_check_inode(inode); |
4415 | } else if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | 4425 | } else if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || |