diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index a6386c1d237f..b2ec222b15e4 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1951,6 +1951,25 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, goto journal_error; } map -= count; + /* + * The map is built from the on-disk dirents, so its entries should + * always refer to valid dirents. However, if the leaf block is + * corrupted (e.g. a crafted image), a bogus map entry can make + * dx_move_dirents() read a rec_len from an arbitrary location and use + * it as the length of a memset(), writing far out of bounds. Validate + * every entry we are about to move before using it. + */ + for (i = 0; i < count; i++) { + unsigned int off = map[i].offs << 2; + + if (off > blocksize - sizeof(struct ext4_dir_entry_2) || + ext4_check_dir_entry(dir, NULL, + (struct ext4_dir_entry_2 *)(data1 + off), + *bh, data1, blocksize, off)) { + err = -EFSCORRUPTED; + goto out; + } + } dx_sort_map(map, count); /* Ensure that neither split block is over half full */ size = 0;