Commit 6fe7bdc7 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Long Li
Browse files

xfs: fix log recovery buffer allocation for the legacy h_size fixup

mainline inclusion
from mainline-v6.9-rc4
commit 45cf976008ddef4a9c9a30310c9b4fb2a9a6602a
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IAB0JY
CVE: CVE-2024-39472

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=45cf976008ddef4a9c9a30310c9b4fb2a9a6602a



--------------------------------

Commit a70f9fe5 ("xfs: detect and handle invalid iclog size set by
mkfs") added a fixup for incorrect h_size values used for the initial
umount record in old xfsprogs versions.  Later commit 0c771b99
("xfs: clean up calculation of LR header blocks") cleaned up the log
reover buffer calculation, but stoped using the fixed up h_size value
to size the log recovery buffer, which can lead to an out of bounds
access when the incorrect h_size does not come from the old mkfs
tool, but a fuzzer.

Fix this by open coding xlog_logrec_hblks and taking the fixed h_size
into account for this calculation.

Fixes: 0c771b99 ("xfs: clean up calculation of LR header blocks")
Reported-by: default avatarSam Sun <samsun1006219@gmail.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
Reviewed-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
Conflicts:
	fs/xfs/xfs_log_recover.c
[Conflicts due to mainline code use kvfree() in context]
Signed-off-by: default avatarLong Li <leo.lilong@huawei.com>
parent 223a7beb
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -2952,7 +2952,7 @@ xlog_do_recovery_pass(
	int			error = 0, h_size, h_len;
	int			error2 = 0;
	int			bblks, split_bblks;
	int			hblks, split_hblks, wrapped_hblks;
	int			hblks = 1, split_hblks, wrapped_hblks;
	int			i;
	struct hlist_head	rhash[XLOG_RHASH_SIZE];
	LIST_HEAD		(buffer_list);
@@ -3008,14 +3008,22 @@ xlog_do_recovery_pass(
		if (error)
			goto bread_err1;

		hblks = xlog_logrec_hblks(log, rhead);
		if (hblks != 1) {
		/*
		 * This open codes xlog_logrec_hblks so that we can reuse the
		 * fixed up h_size value calculated above.  Without that we'd
		 * still allocate the buffer based on the incorrect on-disk
		 * size.
		 */
		if (h_size > XLOG_HEADER_CYCLE_SIZE &&
				(rhead->h_version & cpu_to_be32(XLOG_VERSION_2))) {
			hblks = DIV_ROUND_UP(h_size, XLOG_HEADER_CYCLE_SIZE);
			if (hblks > 1) {
				kmem_free(hbp);
				hbp = xlog_alloc_buffer(log, hblks);
			}
		}
	} else {
		ASSERT(log->l_sectBBsize == 1);
		hblks = 1;
		hbp = xlog_alloc_buffer(log, 1);
		h_size = XLOG_BIG_RECORD_BSIZE;
	}