diff --git a/backport-disk-mdraid1x_linux-Prevent-infinite-recursion.patch b/backport-disk-mdraid1x_linux-Prevent-infinite-recursion.patch new file mode 100644 index 0000000000000000000000000000000000000000..8f2197d49db56e3fd42cd95d381403a2e5974345 --- /dev/null +++ b/backport-disk-mdraid1x_linux-Prevent-infinite-recursion.patch @@ -0,0 +1,139 @@ +From 99b4c0c3841bf71b0f2ef83607e9d6f13874c67c Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Mon, 29 Apr 2024 16:38:03 +0000 +Subject: [PATCH] disk/mdraid1x_linux: Prevent infinite recursion + +The test corpus for version-1 RAID generated an infinite recursion +in grub_partition_iterate() while attempting to read the superblock. +The reason for the issue was that the data region overlapped with +the superblock. + +The infinite call loop looks like this: + grub_partition_iterate() -> partmap->iterate() -> + -> grub_disk_read() -> grub_disk_read_small() -> + -> grub_disk_read_small_real() -> grub_diskfilter_read() -> + -> read_lv() -> read_segment() -> grub_diskfilter_read_node() -> + -> grub_disk_read() -> grub_disk_read_small() -> ... + +The fix adds checks for both the superblock region and the data +region when parsing the superblock metadata in grub_mdraid_detect(). + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/disk/mdraid1x_linux.c | 78 +++++++++++++++++++++++++++++++++ + 1 file changed, 78 insertions(+) + +diff --git a/grub-core/disk/mdraid1x_linux.c b/grub-core/disk/mdraid1x_linux.c +index 72e5cb6f4..dd5d440a3 100644 +--- a/grub-core/disk/mdraid1x_linux.c ++++ b/grub-core/disk/mdraid1x_linux.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -103,6 +104,9 @@ struct grub_raid_super_1x + + #define WriteMostly1 1 /* Mask for writemostly flag in above devflags. */ + ++#define GRUB_MD_SECTOR_SHIFT 9 /* Follow Linux kernel v6.8. */ ++#define GRUB_MD_SECTOR_SIZE (1 << GRUB_MD_SECTOR_SHIFT) ++ + static struct grub_diskfilter_vg * + grub_mdraid_detect (grub_disk_t disk, + struct grub_diskfilter_pv_id *id, +@@ -129,6 +133,7 @@ grub_mdraid_detect (grub_disk_t disk, + grub_uint32_t level; + struct grub_diskfilter_vg *array; + char *uuid; ++ grub_uint64_t sb_sz, data_end, sb_end; + + if (size == GRUB_DISK_SIZE_UNKNOWN && minor_version == 0) + continue; +@@ -154,6 +159,79 @@ grub_mdraid_detect (grub_disk_t disk, + || grub_le_to_cpu64 (sb.super_offset) != sector) + continue; + ++ /* ++ * The first check follows the Linux kernel's data_size ++ * validation from v6.8-rc5. ++ */ ++ if (grub_le_to_cpu64 (sb.data_size) < 10 || ++ grub_le_to_cpu64 (sb.raid_disks) > GRUB_MDRAID_MAX_DISKS) ++ { ++ grub_dprintf ("mdraid1x", "Corrupted superblock\n"); ++ return NULL; ++ } ++ ++ /* ++ * Total size of superblock: 256 bytes plus 2 bytes per device ++ * in the array. ++ */ ++ sb_sz = sizeof (struct grub_raid_super_1x) + grub_le_to_cpu64 (sb.raid_disks) * 2; ++ ++ if (grub_add (grub_le_to_cpu64 (sb.super_offset), ++ (ALIGN_UP(sb_sz, GRUB_MD_SECTOR_SIZE) >> GRUB_MD_SECTOR_SHIFT), &sb_end)) ++ { ++ grub_dprintf ("mdraid1x", "Invalid superblock end.\n"); ++ return NULL; ++ } ++ ++ if (grub_add (grub_le_to_cpu64 (sb.data_offset), ++ grub_le_to_cpu64 (sb.data_size), &data_end)) ++ { ++ grub_dprintf ("mdraid1x", "Invalid data end.\n"); ++ return NULL; ++ } ++ ++ /* In minor versions 1 and 2, superblock is positioned before data. */ ++ if (minor_version) ++ { ++ if (grub_le_to_cpu64 (sb.data_offset) < sb_end) ++ { ++ grub_dprintf ("mdraid1x", ++ "The superblock either overlaps with the data " ++ "or is behind it.\n"); ++ return NULL; ++ } ++ ++ if (data_end > size) ++ { ++ grub_dprintf ("mdraid1x", ++ "The data region ends at %" PRIuGRUB_UINT64_T ", " ++ "past the end of the disk (%" PRIuGRUB_UINT64_T ")\n", ++ data_end, size); ++ return NULL; ++ } ++ } ++ else ++ { ++ /* In minor version 0, superblock is at the end of the device. */ ++ if (grub_le_to_cpu64 (sb.super_offset) < data_end) ++ { ++ grub_dprintf ("mdraid1x", ++ "The data either overlaps with the superblock " ++ "or is behind it.\n"); ++ return NULL; ++ } ++ ++ if (sb_end > size) ++ { ++ grub_dprintf ("mdraid1x", ++ "The superblock region ends at " ++ "%" PRIuGRUB_UINT64_T ", past the end of " ++ "the disk (%" PRIuGRUB_UINT64_T ")\n", ++ sb_end, size); ++ return NULL; ++ } ++ } ++ + if (sb.major_version != grub_cpu_to_le32_compile_time (1)) + /* Unsupported version. */ + return NULL; +-- +2.27.0 + diff --git a/grub.patches b/grub.patches index 0090e23284472bb8739cb3c7fee9c744af4d0032..fdf4fd251fbf6eb7857704e12de6ee76a17c73bd 100644 --- a/grub.patches +++ b/grub.patches @@ -233,3 +233,4 @@ Patch232: modify-efi_max_usable-addr.patch Patch233: LoongArch-Add-back-compatibility-for-linux-kernel.patch Patch234: Fix-that-patch-28dcf48482-introduced-old-code.patch Patch235: backport-CVE-2021-46848-lib-libtasn1-Fix-ETYPE_OK-off-by-one-array.patch +Patch236: backport-disk-mdraid1x_linux-Prevent-infinite-recursion.patch diff --git a/grub2.spec b/grub2.spec index 500d9f6bdce5a9dd5fe388440aa8375d8b9cf30c..deffc249a2dce69eb71873b961fde593ce644a6c 100644 --- a/grub2.spec +++ b/grub2.spec @@ -14,7 +14,7 @@ Name: grub2 Epoch: 1 Version: 2.12 -Release: 15 +Release: 16 Summary: Bootloader with support for Linux, Multiboot and more License: GPLv3+ URL: http://www.gnu.org/software/grub/ @@ -447,6 +447,12 @@ fi %{_datadir}/man/man* %changelog +* Mon Jun 17 2024 wangziliang - 1:2.12-16 +- Type:bugfix +- CVE:NA +- SUG:NA +- DESC:disk/mdraid1x_linux: Prevent infinite recursion + * Wed Jun 5 2024 zhangqiumiao - 1:2.12-15 - Type:CVE - CVE:CVE-2021-46848