diff options
| author | Theodore Ts'o <tytso@mit.edu> | 2019-04-09 23:37:08 -0400 |
|---|---|---|
| committer | Theodore Ts'o <tytso@mit.edu> | 2019-04-09 23:37:08 -0400 |
| commit | 345c0dbf3a30872d9b204db96b5857cd00808cae (patch) | |
| tree | a24a40bc40343396f6a776d87b5d58d83617d476 | |
| parent | 1e83bc8156028a938845a869a3317c3cab9630ac (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.c | 48 | ||||
| -rw-r--r-- | fs/ext4/inode.c | 4 |
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 | ||
| 140 | static 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 | |||
| 140 | int ext4_setup_system_zone(struct super_block *sb) | 182 | int 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, |
