summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2014-10-06 06:47:07 +0400
committerZefan Li <lizefan@huawei.com>2015-02-02 12:04:52 +0300
commit07048f9e15e456be7d216e6f4515c33cafc6fc2b (patch)
tree4e6ad2fad0e9c6c43cdd4cdab6bc0d2571986c55
parent60e7100a311b7b0d4ad87f20d6a13f1f4a4d786d (diff)
downloadlinux-07048f9e15e456be7d216e6f4515c33cafc6fc2b.tar.xz
ext4: don't orphan or truncate the boot loader inode
commit e2bfb088fac03c0f621886a04cffc7faa2b49b1d upstream. The boot loader inode (inode #5) should never be visible in the directory hierarchy, but it's possible if the file system is corrupted that there will be a directory entry that points at inode #5. In order to avoid accidentally trashing it, when such a directory inode is opened, the inode will be marked as a bad inode, so that it's not possible to modify (or read) the inode from userspace. Unfortunately, when we unlink this (invalid/illegal) directory entry, we will put the bad inode on the ophan list, and then when try to unlink the directory, we don't actually remove the bad inode from the orphan list before freeing in-memory inode structure. This means the in-memory orphan list is corrupted, leading to a kernel oops. In addition, avoid truncating a bad inode in ext4_destroy_inode(), since truncating the boot loader inode is not a smart thing to do. Reported-by: Sami Liedes <sami.liedes@iki.fi> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu> [lizf: Backported to 3.4: adjust context] Signed-off-by: Zefan Li <lizefan@huawei.com>
-rw-r--r--fs/ext4/inode.c8
-rw-r--r--fs/ext4/namei.c2
2 files changed, 4 insertions, 6 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 5b6dcba304b1..b9c3995269de 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -157,16 +157,14 @@ void ext4_evict_inode(struct inode *inode)
goto no_delete;
}
- if (!is_bad_inode(inode))
- dquot_initialize(inode);
+ if (is_bad_inode(inode))
+ goto no_delete;
+ dquot_initialize(inode);
if (ext4_should_order_data(inode))
ext4_begin_ordered_truncate(inode, 0);
truncate_inode_pages(&inode->i_data, 0);
- if (is_bad_inode(inode))
- goto no_delete;
-
handle = ext4_journal_start(inode, ext4_blocks_for_truncate(inode)+3);
if (IS_ERR(handle)) {
ext4_std_error(inode->i_sb, PTR_ERR(handle));
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 665e55ca208c..11566d7560e1 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1992,7 +1992,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
struct ext4_iloc iloc;
int err = 0, rc;
- if (!ext4_handle_valid(handle))
+ if (!ext4_handle_valid(handle) || is_bad_inode(inode))
return 0;
mutex_lock(&EXT4_SB(sb)->s_orphan_lock);