mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
ext4: add missing validation of fast-commit record lengths
Validate the inode and filename lengths in fast-commit journal records
so that a malicious fast-commit journal cannot cause a crash by having
invalid values for these. Also validate EXT4_FC_TAG_DEL_RANGE.
Fixes: aa75f4d3da
("ext4: main fast-commit commit path")
Cc: <stable@vger.kernel.org> # v5.10+
Signed-off-by: Eric Biggers <ebiggers@google.com>
Link: https://lore.kernel.org/r/20221106224841.279231-5-ebiggers@kernel.org
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
594bc43b41
commit
64b4a25c3d
@ -1991,32 +1991,31 @@ void ext4_fc_replay_cleanup(struct super_block *sb)
|
|||||||
kfree(sbi->s_fc_replay_state.fc_modified_inodes);
|
kfree(sbi->s_fc_replay_state.fc_modified_inodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool ext4_fc_tag_len_isvalid(struct ext4_fc_tl *tl,
|
static bool ext4_fc_value_len_isvalid(struct ext4_sb_info *sbi,
|
||||||
u8 *val, u8 *end)
|
int tag, int len)
|
||||||
{
|
{
|
||||||
if (val + tl->fc_len > end)
|
switch (tag) {
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Here only check ADD_RANGE/TAIL/HEAD which will read data when do
|
|
||||||
* journal rescan before do CRC check. Other tags length check will
|
|
||||||
* rely on CRC check.
|
|
||||||
*/
|
|
||||||
switch (tl->fc_tag) {
|
|
||||||
case EXT4_FC_TAG_ADD_RANGE:
|
case EXT4_FC_TAG_ADD_RANGE:
|
||||||
return (sizeof(struct ext4_fc_add_range) == tl->fc_len);
|
return len == sizeof(struct ext4_fc_add_range);
|
||||||
case EXT4_FC_TAG_TAIL:
|
|
||||||
return (sizeof(struct ext4_fc_tail) <= tl->fc_len);
|
|
||||||
case EXT4_FC_TAG_HEAD:
|
|
||||||
return (sizeof(struct ext4_fc_head) == tl->fc_len);
|
|
||||||
case EXT4_FC_TAG_DEL_RANGE:
|
case EXT4_FC_TAG_DEL_RANGE:
|
||||||
|
return len == sizeof(struct ext4_fc_del_range);
|
||||||
|
case EXT4_FC_TAG_CREAT:
|
||||||
case EXT4_FC_TAG_LINK:
|
case EXT4_FC_TAG_LINK:
|
||||||
case EXT4_FC_TAG_UNLINK:
|
case EXT4_FC_TAG_UNLINK:
|
||||||
case EXT4_FC_TAG_CREAT:
|
len -= sizeof(struct ext4_fc_dentry_info);
|
||||||
|
return len >= 1 && len <= EXT4_NAME_LEN;
|
||||||
case EXT4_FC_TAG_INODE:
|
case EXT4_FC_TAG_INODE:
|
||||||
|
len -= sizeof(struct ext4_fc_inode);
|
||||||
|
return len >= EXT4_GOOD_OLD_INODE_SIZE &&
|
||||||
|
len <= sbi->s_inode_size;
|
||||||
case EXT4_FC_TAG_PAD:
|
case EXT4_FC_TAG_PAD:
|
||||||
default:
|
return true; /* padding can have any length */
|
||||||
return true;
|
case EXT4_FC_TAG_TAIL:
|
||||||
|
return len >= sizeof(struct ext4_fc_tail);
|
||||||
|
case EXT4_FC_TAG_HEAD:
|
||||||
|
return len == sizeof(struct ext4_fc_head);
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2079,7 +2078,8 @@ static int ext4_fc_replay_scan(journal_t *journal,
|
|||||||
cur = cur + EXT4_FC_TAG_BASE_LEN + tl.fc_len) {
|
cur = cur + EXT4_FC_TAG_BASE_LEN + tl.fc_len) {
|
||||||
ext4_fc_get_tl(&tl, cur);
|
ext4_fc_get_tl(&tl, cur);
|
||||||
val = cur + EXT4_FC_TAG_BASE_LEN;
|
val = cur + EXT4_FC_TAG_BASE_LEN;
|
||||||
if (!ext4_fc_tag_len_isvalid(&tl, val, end)) {
|
if (tl.fc_len > end - val ||
|
||||||
|
!ext4_fc_value_len_isvalid(sbi, tl.fc_tag, tl.fc_len)) {
|
||||||
ret = state->fc_replay_num_tags ?
|
ret = state->fc_replay_num_tags ?
|
||||||
JBD2_FC_REPLAY_STOP : -ECANCELED;
|
JBD2_FC_REPLAY_STOP : -ECANCELED;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
@ -58,7 +58,7 @@ struct ext4_fc_dentry_info {
|
|||||||
__u8 fc_dname[];
|
__u8 fc_dname[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Value structure for EXT4_FC_TAG_INODE and EXT4_FC_TAG_INODE_PARTIAL. */
|
/* Value structure for EXT4_FC_TAG_INODE. */
|
||||||
struct ext4_fc_inode {
|
struct ext4_fc_inode {
|
||||||
__le32 fc_ino;
|
__le32 fc_ino;
|
||||||
__u8 fc_raw_inode[];
|
__u8 fc_raw_inode[];
|
||||||
|
Loading…
Reference in New Issue
Block a user