Unverified Commit c654da7d authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!10979 CVE-2024-42304

Merge Pull Request from: @ci-robot 
 
PR sync from: Yifan Qiao <qiaoyifan4@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/OIMV5C2A3LOH7QABTGOG6VNYSPKEW5BL/ 
Baokun Li (2):
  ext4: check dot and dotdot of dx_root before making dir indexed
  ext4: make sure the first directory block is not a hole


-- 
2.39.2
 
https://gitee.com/src-openeuler/kernel/issues/IAKQB7 
 
Link:https://gitee.com/openeuler/kernel/pulls/10979

 

Reviewed-by: default avatarYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
parents d235b796 349050b9
Loading
Loading
Loading
Loading
+57 −16
Original line number Diff line number Diff line
@@ -150,10 +150,11 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode,

		return bh;
	}
	if (!bh && (type == INDEX || type == DIRENT_HTREE)) {
	/* The first directory block must not be a hole. */
	if (!bh && (type == INDEX || type == DIRENT_HTREE || block == 0)) {
		ext4_error_inode(inode, func, line, block,
				 "Directory hole found for htree %s block",
				 (type == INDEX) ? "index" : "leaf");
				 "Directory hole found for htree %s block %u",
				 (type == INDEX) ? "index" : "leaf", block);
		return ERR_PTR(-EFSCORRUPTED);
	}
	if (!bh)
@@ -2126,6 +2127,52 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
	return err ? err : err2;
}

static bool ext4_check_dx_root(struct inode *dir, struct dx_root *root)
{
	struct fake_dirent *fde;
	const char *error_msg;
	unsigned int rlen;
	unsigned int blocksize = dir->i_sb->s_blocksize;
	char *blockend = (char *)root + dir->i_sb->s_blocksize;

	fde = &root->dot;
	if (unlikely(fde->name_len != 1)) {
		error_msg = "invalid name_len for '.'";
		goto corrupted;
	}
	if (unlikely(strncmp(root->dot_name, ".", fde->name_len))) {
		error_msg = "invalid name for '.'";
		goto corrupted;
	}
	rlen = ext4_rec_len_from_disk(fde->rec_len, blocksize);
	if (unlikely((char *)fde + rlen >= blockend)) {
		error_msg = "invalid rec_len for '.'";
		goto corrupted;
	}

	fde = &root->dotdot;
	if (unlikely(fde->name_len != 2)) {
		error_msg = "invalid name_len for '..'";
		goto corrupted;
	}
	if (unlikely(strncmp(root->dotdot_name, "..", fde->name_len))) {
		error_msg = "invalid name for '..'";
		goto corrupted;
	}
	rlen = ext4_rec_len_from_disk(fde->rec_len, blocksize);
	if (unlikely((char *)fde + rlen >= blockend)) {
		error_msg = "invalid rec_len for '..'";
		goto corrupted;
	}

	return true;

corrupted:
	EXT4_ERROR_INODE(dir, "Corrupt dir, %s, running e2fsck is recommended",
			 error_msg);
	return false;
}

/*
 * This converts a one block unindexed directory to a 3 block indexed
 * directory, and adds the dentry to the indexed directory.
@@ -2159,17 +2206,17 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
		brelse(bh);
		return retval;
	}

	root = (struct dx_root *) bh->b_data;
	if (!ext4_check_dx_root(dir, root)) {
		brelse(bh);
		return -EFSCORRUPTED;
	}

	/* The 0th block becomes the root, move the dirents out */
	fde = &root->dotdot;
	de = (struct ext4_dir_entry_2 *)((char *)fde +
		ext4_rec_len_from_disk(fde->rec_len, blocksize));
	if ((char *) de >= (((char *) root) + blocksize)) {
		EXT4_ERROR_INODE(dir, "invalid rec_len for '..'");
		brelse(bh);
		return -EFSCORRUPTED;
	}
	len = ((char *) root) + (blocksize - csum_size) - (char *) de;

	/* Allocate new block for the 0th block's dirents */
@@ -2978,10 +3025,7 @@ bool ext4_empty_dir(struct inode *inode)
		EXT4_ERROR_INODE(inode, "invalid size");
		return false;
	}
	/* The first directory block must not be a hole,
	 * so treat it as DIRENT_HTREE
	 */
	bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE);
	bh = ext4_read_dirblock(inode, 0, EITHER);
	if (IS_ERR(bh))
		return false;

@@ -3618,10 +3662,7 @@ static struct buffer_head *ext4_get_first_dir_block(handle_t *handle,
		struct ext4_dir_entry_2 *de;
		unsigned int offset;

		/* The first directory block must not be a hole, so
		 * treat it as DIRENT_HTREE
		 */
		bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE);
		bh = ext4_read_dirblock(inode, 0, EITHER);
		if (IS_ERR(bh)) {
			*retval = PTR_ERR(bh);
			return NULL;