aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2019-04-09 23:37:08 -0400
committerTheodore Ts'o <tytso@mit.edu>2019-04-09 23:37:08 -0400
commit345c0dbf3a30872d9b204db96b5857cd00808cae (patch)
treea24a40bc40343396f6a776d87b5d58d83617d476
parent1e83bc8156028a938845a869a3317c3cab9630ac (diff)
ext4: protect journal inode's blocks using block_validity
Add the blocks which belong to the journal inode to block_validity's system zone so attempts to deallocate or overwrite the journal due a corrupted file system where the journal blocks are also claimed by another inode. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=202879 Signed-off-by: Theodore Ts'o <tytso@mit.edu> Cc: stable@kernel.org
-rw-r--r--fs/ext4/block_validity.c48
-rw-r--r--fs/ext4/inode.c4
2 files changed, 52 insertions, 0 deletions
diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c
index 913061c0de1b..9409b1e11a22 100644
--- a/fs/ext4/block_validity.c
+++ b/fs/ext4/block_validity.c
@@ -137,6 +137,48 @@ static void debug_print_tree(struct ext4_sb_info *sbi)
137 printk(KERN_CONT "\n"); 137 printk(KERN_CONT "\n");
138} 138}
139 139
140static int ext4_protect_reserved_inode(struct super_block *sb, u32 ino)
141{
142 struct inode *inode;
143 struct ext4_sb_info *sbi = EXT4_SB(sb);
144 struct ext4_map_blocks map;
145 u32 i = 0, err = 0, num, n;
146
147 if ((ino < EXT4_ROOT_INO) ||
148 (ino > le32_to_cpu(sbi->s_es->s_inodes_count)))
149 return -EINVAL;
150 inode = ext4_iget(sb, ino, EXT4_IGET_SPECIAL);
151 if (IS_ERR(inode))
152 return PTR_ERR(inode);
153 num = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
154 while (i < num) {
155 map.m_lblk = i;
156 map.m_len = num - i;
157 n = ext4_map_blocks(NULL, inode, &map, 0);
158 if (n < 0) {
159 err = n;
160 break;
161 }
162 if (n == 0) {
163 i++;
164 } else {
165 if (!ext4_data_block_valid(sbi, map.m_pblk, n)) {
166 ext4_error(sb, "blocks %llu-%llu from inode %u "
167 "overlap system zone", map.m_pblk,
168 map.m_pblk + map.m_len - 1, ino);
169 err = -EFSCORRUPTED;
170 break;
171 }
172 err = add_system_zone(sbi, map.m_pblk, n);
173 if (err < 0)
174 break;
175 i += n;
176 }
177 }
178 iput(inode);
179 return err;
180}
181
140int ext4_setup_system_zone(struct super_block *sb) 182int ext4_setup_system_zone(struct super_block *sb)
141{ 183{
142 ext4_group_t ngroups = ext4_get_groups_count(sb); 184 ext4_group_t ngroups = ext4_get_groups_count(sb);
@@ -171,6 +213,12 @@ int ext4_setup_system_zone(struct super_block *sb)
171 if (ret) 213 if (ret)
172 return ret; 214 return ret;
173 } 215 }
216 if (ext4_has_feature_journal(sb) && sbi->s_es->s_journal_inum) {
217 ret = ext4_protect_reserved_inode(sb,
218 le32_to_cpu(sbi->s_es->s_journal_inum));
219 if (ret)
220 return ret;
221 }
174 222
175 if (test_opt(sb, DEBUG)) 223 if (test_opt(sb, DEBUG))
176 debug_print_tree(sbi); 224 debug_print_tree(sbi);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 190f0478582a..609c8366d029 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -399,6 +399,10 @@ static int __check_block_validity(struct inode *inode, const char *func,
399 unsigned int line, 399 unsigned int line,
400 struct ext4_map_blocks *map) 400 struct ext4_map_blocks *map)
401{ 401{
402 if (ext4_has_feature_journal(inode->i_sb) &&
403 (inode->i_ino ==
404 le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum)))
405 return 0;
402 if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk, 406 if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk,
403 map->m_len)) { 407 map->m_len)) {
404 ext4_error_inode(inode, func, line, map->m_pblk, 408 ext4_error_inode(inode, func, line, map->m_pblk,