Skip to content

Commit 64b4a25

Browse files
ebiggerstytso
authored andcommitted
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: aa75f4d ("ext4: main fast-commit commit path") Cc: <[email protected]> # v5.10+ Signed-off-by: Eric Biggers <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 594bc43 commit 64b4a25

File tree

2 files changed

+20
-20
lines changed

2 files changed

+20
-20
lines changed

fs/ext4/fast_commit.c

+19-19
Original file line numberDiff line numberDiff line change
@@ -1991,32 +1991,31 @@ void ext4_fc_replay_cleanup(struct super_block *sb)
19911991
kfree(sbi->s_fc_replay_state.fc_modified_inodes);
19921992
}
19931993

1994-
static inline bool ext4_fc_tag_len_isvalid(struct ext4_fc_tl *tl,
1995-
u8 *val, u8 *end)
1994+
static bool ext4_fc_value_len_isvalid(struct ext4_sb_info *sbi,
1995+
int tag, int len)
19961996
{
1997-
if (val + tl->fc_len > end)
1998-
return false;
1999-
2000-
/* Here only check ADD_RANGE/TAIL/HEAD which will read data when do
2001-
* journal rescan before do CRC check. Other tags length check will
2002-
* rely on CRC check.
2003-
*/
2004-
switch (tl->fc_tag) {
1997+
switch (tag) {
20051998
case EXT4_FC_TAG_ADD_RANGE:
2006-
return (sizeof(struct ext4_fc_add_range) == tl->fc_len);
2007-
case EXT4_FC_TAG_TAIL:
2008-
return (sizeof(struct ext4_fc_tail) <= tl->fc_len);
2009-
case EXT4_FC_TAG_HEAD:
2010-
return (sizeof(struct ext4_fc_head) == tl->fc_len);
1999+
return len == sizeof(struct ext4_fc_add_range);
20112000
case EXT4_FC_TAG_DEL_RANGE:
2001+
return len == sizeof(struct ext4_fc_del_range);
2002+
case EXT4_FC_TAG_CREAT:
20122003
case EXT4_FC_TAG_LINK:
20132004
case EXT4_FC_TAG_UNLINK:
2014-
case EXT4_FC_TAG_CREAT:
2005+
len -= sizeof(struct ext4_fc_dentry_info);
2006+
return len >= 1 && len <= EXT4_NAME_LEN;
20152007
case EXT4_FC_TAG_INODE:
2008+
len -= sizeof(struct ext4_fc_inode);
2009+
return len >= EXT4_GOOD_OLD_INODE_SIZE &&
2010+
len <= sbi->s_inode_size;
20162011
case EXT4_FC_TAG_PAD:
2017-
default:
2018-
return true;
2012+
return true; /* padding can have any length */
2013+
case EXT4_FC_TAG_TAIL:
2014+
return len >= sizeof(struct ext4_fc_tail);
2015+
case EXT4_FC_TAG_HEAD:
2016+
return len == sizeof(struct ext4_fc_head);
20192017
}
2018+
return false;
20202019
}
20212020

20222021
/*
@@ -2079,7 +2078,8 @@ static int ext4_fc_replay_scan(journal_t *journal,
20792078
cur = cur + EXT4_FC_TAG_BASE_LEN + tl.fc_len) {
20802079
ext4_fc_get_tl(&tl, cur);
20812080
val = cur + EXT4_FC_TAG_BASE_LEN;
2082-
if (!ext4_fc_tag_len_isvalid(&tl, val, end)) {
2081+
if (tl.fc_len > end - val ||
2082+
!ext4_fc_value_len_isvalid(sbi, tl.fc_tag, tl.fc_len)) {
20832083
ret = state->fc_replay_num_tags ?
20842084
JBD2_FC_REPLAY_STOP : -ECANCELED;
20852085
goto out_err;

fs/ext4/fast_commit.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ struct ext4_fc_dentry_info {
5858
__u8 fc_dname[];
5959
};
6060

61-
/* Value structure for EXT4_FC_TAG_INODE and EXT4_FC_TAG_INODE_PARTIAL. */
61+
/* Value structure for EXT4_FC_TAG_INODE. */
6262
struct ext4_fc_inode {
6363
__le32 fc_ino;
6464
__u8 fc_raw_inode[];

0 commit comments

Comments
 (0)