Add cc:stable@vger.kernel org tags
[ext4-patch-queue.git] / disallow-metadata-inodes-in-ext4_iget
blobc039277d0c564aa55288b178d6f66d916a274fb6
1 ext4: add ext4_iget_normal() which is to be used for dir tree lookups
3 If there is a corrupted file system which has directory entries that
4 point at reserved, metadata inodes, prohibit them from being used by
5 treating them the same way we treat Boot Loader inodes --- that is,
6 mark them to be bad inodes.  This prohibits them from being opened,
7 deleted, or modified via chmod, chown, utimes, etc.
9 In particular, this prevents a corrupted file system which has a
10 directory entry which points at the journal inode from being deleted
11 and its blocks released, after which point Much Hilarity Ensues.
13 Reported-by: Sami Liedes <sami.liedes@iki.fi>
14 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
15 Cc: stable@vger.kernel.org
16 ---
17  fs/ext4/ext4.h  | 1 +
18  fs/ext4/inode.c | 7 +++++++
19  fs/ext4/namei.c | 4 ++--
20  fs/ext4/super.c | 2 +-
21  4 files changed, 11 insertions(+), 3 deletions(-)
23 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
24 index 1eb5b7b..012e89b 100644
25 --- a/fs/ext4/ext4.h
26 +++ b/fs/ext4/ext4.h
27 @@ -2109,6 +2109,7 @@ int do_journal_get_write_access(handle_t *handle,
28  #define CONVERT_INLINE_DATA     2
30  extern struct inode *ext4_iget(struct super_block *, unsigned long);
31 +extern struct inode *ext4_iget_normal(struct super_block *, unsigned long);
32  extern int  ext4_write_inode(struct inode *, struct writeback_control *);
33  extern int  ext4_setattr(struct dentry *, struct iattr *);
34  extern int  ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
35 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
36 index 59983b2..e204d8a 100644
37 --- a/fs/ext4/inode.c
38 +++ b/fs/ext4/inode.c
39 @@ -4104,6 +4104,13 @@ bad_inode:
40         return ERR_PTR(ret);
41  }
43 +struct inode *ext4_iget_normal(struct super_block *sb, unsigned long ino)
45 +       if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO)
46 +               return ERR_PTR(-EIO);
47 +       return ext4_iget(sb, ino);
50  static int ext4_inode_blocks_set(handle_t *handle,
51                                 struct ext4_inode *raw_inode,
52                                 struct ext4_inode_info *ei)
53 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
54 index a2a9d40..7037ecf 100644
55 --- a/fs/ext4/namei.c
56 +++ b/fs/ext4/namei.c
57 @@ -1417,7 +1417,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
58                                          dentry);
59                         return ERR_PTR(-EIO);
60                 }
61 -               inode = ext4_iget(dir->i_sb, ino);
62 +               inode = ext4_iget_normal(dir->i_sb, ino);
63                 if (inode == ERR_PTR(-ESTALE)) {
64                         EXT4_ERROR_INODE(dir,
65                                          "deleted inode referenced: %u",
66 @@ -1450,7 +1450,7 @@ struct dentry *ext4_get_parent(struct dentry *child)
67                 return ERR_PTR(-EIO);
68         }
70 -       return d_obtain_alias(ext4_iget(child->d_inode->i_sb, ino));
71 +       return d_obtain_alias(ext4_iget_normal(child->d_inode->i_sb, ino));
72  }
74  /*
75 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
76 index 1070d6e..a0811cc 100644
77 --- a/fs/ext4/super.c
78 +++ b/fs/ext4/super.c
79 @@ -1001,7 +1001,7 @@ static struct inode *ext4_nfs_get_inode(struct super_block *sb,
80          * Currently we don't know the generation for parent directory, so
81          * a generation of 0 means "accept any"
82          */
83 -       inode = ext4_iget(sb, ino);
84 +       inode = ext4_iget_normal(sb, ino);
85         if (IS_ERR(inode))
86                 return ERR_CAST(inode);
87         if (generation && inode->i_generation != generation) {