Skip to content

Commit

Permalink
ext4: fix error handling in ext4_fc_record_modified_inode()
Browse files Browse the repository at this point in the history
commit cdce59a upstream.

Current code does not fully takes care of krealloc() error case, which
could lead to silent memory corruption or a kernel bug.  This patch
fixes that.

Also it cleans up some duplicated error handling logic from various
functions in fast_commit.c file.

Reported-by: luo penghao <luo.penghao@zte.com.cn>
Suggested-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: Ritesh Harjani <riteshh@linux.ibm.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/62e8b6a1cce9359682051deb736a3c0953c9d1e9.1642416995.git.riteshh@linux.ibm.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
riteshharjani authored and gregkh committed Feb 8, 2022
1 parent 627b44c commit 14aa3f4
Showing 1 changed file with 29 additions and 35 deletions.
64 changes: 29 additions & 35 deletions fs/ext4/fast_commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1435,14 +1435,15 @@ static int ext4_fc_record_modified_inode(struct super_block *sb, int ino)
if (state->fc_modified_inodes[i] == ino)
return 0;
if (state->fc_modified_inodes_used == state->fc_modified_inodes_size) {
state->fc_modified_inodes_size +=
EXT4_FC_REPLAY_REALLOC_INCREMENT;
state->fc_modified_inodes = krealloc(
state->fc_modified_inodes, sizeof(int) *
state->fc_modified_inodes_size,
GFP_KERNEL);
state->fc_modified_inodes,
sizeof(int) * (state->fc_modified_inodes_size +
EXT4_FC_REPLAY_REALLOC_INCREMENT),
GFP_KERNEL);
if (!state->fc_modified_inodes)
return -ENOMEM;
state->fc_modified_inodes_size +=
EXT4_FC_REPLAY_REALLOC_INCREMENT;
}
state->fc_modified_inodes[state->fc_modified_inodes_used++] = ino;
return 0;
Expand Down Expand Up @@ -1474,7 +1475,9 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl,
}
inode = NULL;

ext4_fc_record_modified_inode(sb, ino);
ret = ext4_fc_record_modified_inode(sb, ino);
if (ret)
goto out;

raw_fc_inode = (struct ext4_inode *)
(val + offsetof(struct ext4_fc_inode, fc_raw_inode));
Expand Down Expand Up @@ -1674,6 +1677,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
}

ret = ext4_fc_record_modified_inode(sb, inode->i_ino);
if (ret)
goto out;

start = le32_to_cpu(ex->ee_block);
start_pblk = ext4_ext_pblock(ex);
Expand All @@ -1691,18 +1696,14 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
map.m_pblk = 0;
ret = ext4_map_blocks(NULL, inode, &map, 0);

if (ret < 0) {
iput(inode);
return 0;
}
if (ret < 0)
goto out;

if (ret == 0) {
/* Range is not mapped */
path = ext4_find_extent(inode, cur, NULL, 0);
if (IS_ERR(path)) {
iput(inode);
return 0;
}
if (IS_ERR(path))
goto out;
memset(&newex, 0, sizeof(newex));
newex.ee_block = cpu_to_le32(cur);
ext4_ext_store_pblock(
Expand All @@ -1716,10 +1717,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
up_write((&EXT4_I(inode)->i_data_sem));
ext4_ext_drop_refs(path);
kfree(path);
if (ret) {
iput(inode);
return 0;
}
if (ret)
goto out;
goto next;
}

Expand All @@ -1732,10 +1731,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
ret = ext4_ext_replay_update_ex(inode, cur, map.m_len,
ext4_ext_is_unwritten(ex),
start_pblk + cur - start);
if (ret) {
iput(inode);
return 0;
}
if (ret)
goto out;
/*
* Mark the old blocks as free since they aren't used
* anymore. We maintain an array of all the modified
Expand All @@ -1755,10 +1752,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
ext4_ext_is_unwritten(ex), map.m_pblk);
ret = ext4_ext_replay_update_ex(inode, cur, map.m_len,
ext4_ext_is_unwritten(ex), map.m_pblk);
if (ret) {
iput(inode);
return 0;
}
if (ret)
goto out;
/*
* We may have split the extent tree while toggling the state.
* Try to shrink the extent tree now.
Expand All @@ -1770,6 +1765,7 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
}
ext4_ext_replay_shrink_inode(inode, i_size_read(inode) >>
sb->s_blocksize_bits);
out:
iput(inode);
return 0;
}
Expand Down Expand Up @@ -1799,6 +1795,8 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
}

ret = ext4_fc_record_modified_inode(sb, inode->i_ino);
if (ret)
goto out;

jbd_debug(1, "DEL_RANGE, inode %ld, lblk %d, len %d\n",
inode->i_ino, le32_to_cpu(lrange.fc_lblk),
Expand All @@ -1808,10 +1806,8 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
map.m_len = remaining;

ret = ext4_map_blocks(NULL, inode, &map, 0);
if (ret < 0) {
iput(inode);
return 0;
}
if (ret < 0)
goto out;
if (ret > 0) {
remaining -= ret;
cur += ret;
Expand All @@ -1826,15 +1822,13 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
ret = ext4_ext_remove_space(inode, lrange.fc_lblk,
lrange.fc_lblk + lrange.fc_len - 1);
up_write(&EXT4_I(inode)->i_data_sem);
if (ret) {
iput(inode);
return 0;
}
if (ret)
goto out;
ext4_ext_replay_shrink_inode(inode,
i_size_read(inode) >> sb->s_blocksize_bits);
ext4_mark_inode_dirty(NULL, inode);
out:
iput(inode);

return 0;
}

Expand Down

0 comments on commit 14aa3f4

Please sign in to comment.