diff -Nru grub2-2.12~rc1/debian/build-efi-images grub2-2.12~rc1/debian/build-efi-images --- grub2-2.12~rc1/debian/build-efi-images 2023-10-02 14:23:58.000000000 +0000 +++ grub2-2.12~rc1/debian/build-efi-images 2024-03-21 09:16:17.000000000 +0000 @@ -194,7 +194,6 @@ gcry_twofish gcry_whirlpool luks - luks2 lvm mdraid09 mdraid1x diff -Nru grub2-2.12~rc1/debian/changelog grub2-2.12~rc1/debian/changelog --- grub2-2.12~rc1/debian/changelog 2023-10-02 14:23:58.000000000 +0000 +++ grub2-2.12~rc1/debian/changelog 2024-03-21 09:16:17.000000000 +0000 @@ -1,3 +1,22 @@ +grub2 (2.12~rc1-10ubuntu4.2) mantic; urgency=medium + + * Revert "efi: Eliminate globals from the `peimage.c` chainloader" + (LP: #2057679) (LP: #2054127) + * Increase SBAT level to "grub.ubuntu,2" and "grub.peimage,2" + * SECURITY UPDATE: Use-after-free in peimage module [LP: #2054127] + - CVE-2024-2312 + + -- Mate Kukri Thu, 21 Mar 2024 09:16:17 +0000 + +grub2 (2.12~rc1-10ubuntu4.1) mantic; urgency=medium + + [ Julian Andres Klode ] + * Cherry-pick upstream XFS directory extent parsing fixes (Closes: #1051543) + (LP: #2039172) + * UBUNTU: Drop luks2 (LP: #2043101) + + -- Mate Kukri Thu, 09 Nov 2023 15:04:44 +0200 + grub2 (2.12~rc1-10ubuntu4) mantic; urgency=high * SECURITY UPDATE: Crafted file system images can cause out-of-bounds write diff -Nru grub2-2.12~rc1/debian/patches/secure-boot/efi-use-peimage-shim.patch grub2-2.12~rc1/debian/patches/secure-boot/efi-use-peimage-shim.patch --- grub2-2.12~rc1/debian/patches/secure-boot/efi-use-peimage-shim.patch 2023-10-02 14:23:58.000000000 +0000 +++ grub2-2.12~rc1/debian/patches/secure-boot/efi-use-peimage-shim.patch 2024-03-21 09:16:17.000000000 +0000 @@ -33,9 +33,9 @@ Signed-off-by: Julian Andres Klode --- grub-core/Makefile.core.def | 12 + - grub-core/loader/efi/peimage.c | 899 +++++++++++++++++++++++++++++++++++++++++ + grub-core/loader/efi/peimage.c | 845 +++++++++++++++++++++++++++++++++++++++++ include/grub/efi/peimage.h | 23 ++ - 3 files changed, 934 insertions(+) + 3 files changed, 880 insertions(+) create mode 100644 grub-core/loader/efi/peimage.c create mode 100644 include/grub/efi/peimage.h @@ -64,10 +64,10 @@ efi = loader/efi/fdt.c; diff --git a/grub-core/loader/efi/peimage.c b/grub-core/loader/efi/peimage.c new file mode 100644 -index 0000000..d24871e +index 0000000..f199555 --- /dev/null +++ b/grub-core/loader/efi/peimage.c -@@ -0,0 +1,899 @@ +@@ -0,0 +1,845 @@ +// SPDX-License-Identifier: GPL-3.0+ + +#include @@ -83,22 +83,6 @@ + +GRUB_MOD_LICENSE ("GPLv3+"); + -+#define GRUB_PEIMAGE_MARKER_GUID \ -+ { \ -+ 0xda24567a, 0xf899, 0x4566, \ -+ { \ -+ 0xb8, 0x27, 0x9f, 0x66, 0x00, 0xc2, 0x14, 0x39 \ -+ } \ -+ } -+ -+#define GRUB_EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \ -+ { \ -+ 0xbc62157e, 0x3e33, 0x4fec, \ -+ { \ -+ 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf \ -+ } \ -+ } -+ +static grub_dl_t my_mod; + +struct image_info @@ -118,12 +102,18 @@ + grub_uint32_t alloc_pages; + void *image_addr; + grub_efi_entry_point __grub_efi_api entry_point; ++}; + -+ grub_efi_loaded_image_t loaded_image; -+ ++static struct ++{ + grub_jmp_buf jmp; ++ grub_efi_handle_t image_handle; + grub_efi_status_t exit_status; -+}; ++ grub_efi_status_t (__grub_efi_api *exit) (grub_efi_handle_t image_handle, ++ grub_efi_status_t exit_status, ++ grub_efi_uintn_t exit_data_size, ++ grub_efi_char16_t *exit_data); ++} started_image; + +static int +debug_enabled (const char *condition) @@ -354,8 +344,7 @@ + section < &info->section[info->num_sections]; ++section) + { + if (section->virtual_address < info->header_size -+ || (section->raw_data_size -+ && section->raw_data_offset < info->header_size)) ++ || section->raw_data_offset < info->header_size) + { + grub_error (GRUB_ERR_BAD_OS, "section inside header"); + return GRUB_EFI_LOAD_ERROR; @@ -719,11 +708,6 @@ + return GRUB_EFI_LOAD_ERROR; +} + -+// Original exit handler -+static grub_efi_status_t (__grub_efi_api *exit_orig) ( -+ grub_efi_handle_t image_handle, grub_efi_status_t exit_status, -+ grub_efi_uintn_t exit_data_size, grub_efi_char16_t *exit_data); -+ +/** + * efi_exit() - replacement for EFI_BOOT_SERVICES.Exit() + * @@ -737,26 +721,22 @@ + * @exit_data: null terminated string followed by optional data + */ +static grub_efi_status_t __grub_efi_api -+exit_hook (grub_efi_handle_t image_handle, grub_efi_status_t exit_status, -+ grub_efi_uintn_t exit_data_size, grub_efi_char16_t *exit_data) ++efi_exit (grub_efi_handle_t image_handle, grub_efi_status_t exit_status, ++ grub_efi_uintn_t exit_data_size, grub_efi_char16_t *exit_data) +{ -+ struct image_info *info; ++ grub_efi_system_table->boot_services->exit = started_image.exit; + + if (!image_handle) + return GRUB_EFI_INVALID_PARAMETER; + -+ info = grub_efi_open_protocol ( -+ image_handle, -+ &(grub_guid_t)GRUB_PEIMAGE_MARKER_GUID, -+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); -+ if (!info) ++ if (image_handle != started_image.image_handle) + { + grub_dprintf ("linux", "delegating Exit()\n"); -+ return exit_orig (image_handle, exit_status, exit_data_size, -+ (grub_efi_char16_t *)exit_data); ++ return started_image.exit (image_handle, exit_status, exit_data_size, ++ (grub_efi_char16_t *)exit_data); + } + -+ info->exit_status = exit_status; ++ started_image.exit_status = exit_status; + + if (exit_status != GRUB_EFI_SUCCESS) + { @@ -776,169 +756,143 @@ + /* exit data must be freed by the caller */ + grub_efi_system_table->boot_services->free_pool (exit_data); + } -+ grub_longjmp (info->jmp, 1); -+} -+ -+static grub_efi_status_t do_unload_image (grub_efi_handle_t image_handle -+ __attribute__ ((unused))); -+ -+static grub_efi_status_t __grub_efi_api -+do_unload_image_ms (grub_efi_handle_t image_handle) -+{ -+ return do_unload_image (image_handle); ++ grub_longjmp (started_image.jmp, 1); +} + -+/* TODO: move the creation of the load options here */ ++/** ++ * start_image() - our implementation of StartImage() ++ * ++ * As we do not load the image via LoadImage() we need our own implementation ++ * of StartImage() to launch the PE-COFF image. ++ */ +static grub_efi_status_t -+do_load_image (grub_efi_boolean_t boot_policy __attribute__ ((unused)), -+ grub_efi_handle_t parent_image_handle, -+ grub_efi_device_path_t *file_path, void *source_buffer, -+ grub_efi_uintn_t source_size, grub_efi_handle_t *image_handle) ++start_image (struct image_info *info) +{ ++ int ret; + grub_efi_status_t status; -+ struct image_info *info; ++ grub_efi_loaded_image_t *loaded_image; + -+ info = grub_efi_allocate_pages_real ( -+ GRUB_EFI_MAX_USABLE_ADDRESS, GRUB_EFI_BYTES_TO_PAGES (sizeof *info), -+ GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA); -+ if (!info) -+ return GRUB_EFI_OUT_OF_RESOURCES; ++ /* ++ * TODO: It would better comply to the UEFI specification to ++ * use a separate handle for the image we are running. ++ */ ++ started_image.image_handle = grub_efi_image_handle; + -+ grub_memset (info, 0, sizeof *info); ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (loaded_image) ++ { ++ loaded_image->image_base = info->image_addr; ++ loaded_image->image_size = info->image_size; ++ // FIXME: We should be pulling file_path apart into dev_handle and ++ // file_path, however there are no functions to do so, and Windows ++ // chainloads fine this way, so meh? ++ loaded_image->file_path = info->file_path; ++ } ++ else ++ { ++ grub_dprintf ("linux", "Loaded image protocol missing\n"); ++ } + -+ // Load PE -+ info->data = source_buffer, info->data_size = source_size, -+ info->file_path = grub_efi_duplicate_device_path (file_path), ++ ret = grub_setjmp (started_image.jmp); ++ if (ret) ++ { ++ started_image.image_handle = NULL; + -+ status = check_pe_header (info); -+ if (status != GRUB_EFI_SUCCESS) -+ goto err; ++ return started_image.exit_status; ++ } + -+ status = load_sections (info); -+ if (status != GRUB_EFI_SUCCESS) -+ goto err; ++ started_image.exit = grub_efi_system_table->boot_services->exit; ++ grub_efi_system_table->boot_services->exit = efi_exit; + -+ status = relocate (info); -+ if (status != GRUB_EFI_SUCCESS) -+ goto err; ++ grub_dprintf ( ++ "linux", ++ "Executing image loaded at 0x%lx\nEntry point 0x%lx\nSize 0x%08x\n", ++ (unsigned long)info->image_addr, (unsigned long)info->entry_point, ++ info->image_size); + -+ // Setup EFI_LOADED_IMAGE_PROTOCOL -+ info->loaded_image.revision = 0x1000; -+ info->loaded_image.parent_handle = parent_image_handle; -+ info->loaded_image.system_table = grub_efi_system_table; -+ -+ // FIXME: We should be pulling file_path apart into dev_handle and -+ // file_path, however there are no functions to do so, and Windows -+ // chainloads fine this way, so meh? -+ // info.loaded_image->device_handle = ?; -+ info->loaded_image.file_path = info->file_path; -+ -+ info->loaded_image.image_base = info->image_addr; -+ info->loaded_image.image_size = info->image_size; -+ // FIXME2: we may want to support loading drivers? -+ // this should be good enough for chainloading bootloaders -+ info->loaded_image.image_code_type = GRUB_EFI_LOADER_CODE; -+ info->loaded_image.image_data_type = GRUB_EFI_LOADER_DATA; -+ info->loaded_image.unload = do_unload_image_ms; ++ /* Invalidate the instruction cache */ ++ grub_arch_sync_caches (info->image_addr, info->image_size); + -+ // Instruct EFI to create a new handle -+ *image_handle = NULL; ++ debug ("pestart"); + status -+ = grub_efi_system_table->boot_services -+ ->install_multiple_protocol_interfaces ( -+ image_handle, &(grub_guid_t)GRUB_PEIMAGE_MARKER_GUID, info, -+ &(grub_guid_t)GRUB_EFI_LOADED_IMAGE_GUID, &info->loaded_image, -+ &(grub_guid_t)GRUB_EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID, -+ info->file_path, NULL); -+ if (status != GRUB_EFI_SUCCESS) -+ goto err; -+ -+ // Increment module refcount -+ grub_dl_ref (my_mod); ++ = info->entry_point (started_image.image_handle, grub_efi_system_table); + -+ return status; ++ grub_dprintf ("linux", "Application returned\n"); + -+err: -+ grub_efi_free_pages ((unsigned long)info, -+ GRUB_EFI_BYTES_TO_PAGES (sizeof *info)); -+ return status; ++ return efi_exit (started_image.image_handle, status, 0, NULL); +} + ++static struct image_info info; ++ ++/* TODO: move the creation of the load options here */ +static grub_efi_status_t -+do_start_image (grub_efi_handle_t image_handle, -+ grub_efi_uintn_t *exit_data_size __attribute__ ((unused)), -+ grub_efi_char16_t **exit_data __attribute__ ((unused))) ++do_load_image (grub_efi_boolean_t boot_policy __attribute__ ((unused)), ++ grub_efi_handle_t parent_image_handle __attribute__ ((unused)), ++ grub_efi_device_path_t *file_path, ++ void *source_buffer, grub_efi_uintn_t source_size, ++ grub_efi_handle_t *image_handle) +{ -+ int ret; -+ grub_efi_status_t status; -+ struct image_info *info; -+ -+ info = grub_efi_open_protocol ( -+ image_handle, -+ &(grub_guid_t)GRUB_PEIMAGE_MARKER_GUID, -+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); -+ if (!info) ++ grub_efi_status_t ret = GRUB_EFI_SUCCESS; ++ if (info.data != NULL) + { -+ grub_error (GRUB_ERR_BAD_OS, "image not loaded"); ++ grub_error (GRUB_ERR_BAD_OS, "cannot load multiple images"); + return GRUB_EFI_LOAD_ERROR; + } + -+ ret = grub_setjmp (info->jmp); -+ if (ret) -+ return info->exit_status; ++ grub_dl_ref (my_mod); + -+ grub_dprintf ("linux", -+ "Executing image loaded at 0x%lx\n" -+ "Entry point 0x%lx\n" -+ "Size 0x%08x\n", -+ (unsigned long)info->image_addr, -+ (unsigned long)info->entry_point, info->image_size); ++ info = (struct image_info){ ++ .data = source_buffer, ++ .data_size = source_size, ++ .file_path = grub_efi_duplicate_device_path(file_path), ++ }; + -+ /* Invalidate the instruction cache */ -+ grub_arch_sync_caches (info->image_addr, info->image_size); ++ ret = check_pe_header (&info); ++ if (ret != GRUB_EFI_SUCCESS) ++ goto err; + -+ debug ("pestart"); -+ status = info->entry_point (image_handle, grub_efi_system_table); ++ ret = load_sections (&info); ++ if (ret != GRUB_EFI_SUCCESS) ++ goto err; + -+ grub_dprintf ("linux", "Application returned\n"); ++ ret = relocate (&info); ++ if (ret != GRUB_EFI_SUCCESS) ++ goto err; + -+ return exit_hook (image_handle, status, 0, NULL); ++ // We are hacking this up as we go along ++ *image_handle = grub_efi_image_handle; ++err: ++ return ret; +} + +static grub_efi_status_t -+do_unload_image (grub_efi_handle_t image_handle) ++do_start_image (grub_efi_handle_t image_handle __attribute__ ((unused)), ++ grub_efi_uintn_t *exit_data_size __attribute__ ((unused)), ++ grub_efi_char16_t **exit_data __attribute__ ((unused))) +{ -+ grub_efi_status_t status; -+ struct image_info *info; -+ -+ info = grub_efi_open_protocol ( -+ image_handle, -+ &(grub_guid_t)GRUB_PEIMAGE_MARKER_GUID, -+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); -+ if (!info) ++ if (info.data == NULL) + { + grub_error (GRUB_ERR_BAD_OS, "image not loaded"); + return GRUB_EFI_LOAD_ERROR; + } ++ return start_image (&info); ++} + -+ status = grub_efi_system_table->boot_services -+ ->uninstall_multiple_protocol_interfaces ( -+ image_handle, &(grub_guid_t)GRUB_PEIMAGE_MARKER_GUID, info, -+ &(grub_guid_t)GRUB_EFI_LOADED_IMAGE_GUID, &info->loaded_image, -+ &(grub_guid_t)GRUB_EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID, -+ info->file_path, NULL); -+ if (status != GRUB_EFI_SUCCESS) -+ return GRUB_EFI_LOAD_ERROR; -+ -+ if (info->alloc_addr) -+ grub_efi_free_pages ((unsigned long)info->alloc_addr, info->alloc_pages); -+ if (info->file_path) -+ grub_free (info->file_path); -+ -+ grub_efi_free_pages ((unsigned long)info, -+ GRUB_EFI_BYTES_TO_PAGES (sizeof *info)); ++static grub_efi_status_t ++do_unload_image (grub_efi_handle_t image_handle __attribute__ ((unused))) ++{ ++ if (info.data == NULL) ++ { ++ grub_error (GRUB_ERR_BAD_OS, "image not loaded"); ++ return GRUB_EFI_LOAD_ERROR; ++ } ++ if (info.alloc_addr) ++ grub_efi_free_pages ((unsigned long)info.alloc_addr, info.alloc_pages); ++ if (info.file_path) ++ grub_free(info.file_path); + + grub_dl_unref (my_mod); ++ info = (struct image_info){}; + + return GRUB_EFI_SUCCESS; +} @@ -953,18 +907,10 @@ +{ + grub_efi_register_loader (&peimage_loader); + my_mod = mod; -+ -+ // Backup exit pointer -+ exit_orig = grub_efi_system_table->boot_services->exit; -+ // Replace exit handler -+ grub_efi_system_table->boot_services->exit = exit_hook; +} + +GRUB_MOD_FINI (peimage) +{ -+ // Restore exit handler -+ grub_efi_system_table->boot_services->exit = exit_orig; -+ + grub_efi_unregister_loader (&peimage_loader); +} diff --git a/include/grub/efi/peimage.h b/include/grub/efi/peimage.h diff -Nru grub2-2.12~rc1/debian/patches/series grub2-2.12~rc1/debian/patches/series --- grub2-2.12~rc1/debian/patches/series 2023-10-02 14:23:58.000000000 +0000 +++ grub2-2.12~rc1/debian/patches/series 2024-03-21 09:16:17.000000000 +0000 @@ -94,3 +94,5 @@ ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-index-at.patch ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch ntfs-cve-fixes/fs-ntfs-Make-code-more-readable.patch +upstream/xfs-incorrect-directory-data-boundary-check.patch +upstream/xfs-fix-directory-extend-parsing.patch diff -Nru grub2-2.12~rc1/debian/patches/upstream/xfs-fix-directory-extend-parsing.patch grub2-2.12~rc1/debian/patches/upstream/xfs-fix-directory-extend-parsing.patch --- grub2-2.12~rc1/debian/patches/upstream/xfs-fix-directory-extend-parsing.patch 1970-01-01 00:00:00.000000000 +0000 +++ grub2-2.12~rc1/debian/patches/upstream/xfs-fix-directory-extend-parsing.patch 2024-03-21 09:16:17.000000000 +0000 @@ -0,0 +1,171 @@ +From: Jon DeVree +Date: Tue, 17 Oct 2023 23:03:47 -0400 +Subject: fs/xfs: Fix XFS directory extent parsing + +The XFS directory entry parsing code has never been completely correct +for extent based directories. The parser correctly handles the case +where the directory is contained in a single extent, but then mistakenly +assumes the data blocks for the multiple extent case are each identical +to the single extent case. The difference in the format of the data +blocks between the two cases is tiny enough that its gone unnoticed for +a very long time. + +A recent change introduced some additional bounds checking into the XFS +parser. Like GRUB's existing parser, it is correct for the single extent +case but incorrect for the multiple extent case. When parsing a directory +with multiple extents, this new bounds checking is sometimes (but not +always) tripped and triggers an "invalid XFS directory entry" error. This +probably would have continued to go unnoticed but the /boot/grub/ +directory is large enough that it often has multiple extents. + +The difference between the two cases is that when there are multiple +extents, the data blocks do not contain a trailer nor do they contain +any leaf information. That information is stored in a separate set of +extents dedicated to just the leaf information. These extents come after +the directory entry extents and are not included in the inode size. So +the existing parser already ignores the leaf extents. + +The only reason to read the trailer/leaf information at all is so that +the parser can avoid misinterpreting that data as directory entries. So +this updates the parser as follows: + +For the single extent case the parser doesn't change much: +1. Read the size of the leaf information from the trailer +2. Set the end pointer for the parser to the start of the leaf + information. (The previous bounds checking set the end pointer to the + start of the trailer, so this is actually a small improvement.) +3. Set the entries variable to the expected number of directory entries. + +For the multiple extent case: +1. Set the end pointer to the end of the block. +2. Do not set up the entries variable. Figuring out how many entries are + in each individual block is complex and does not seem worth it when + it appears to be safe to just iterate over the entire block. + +The bounds check itself was also dependent upon the faulty XFS parser +because it accidentally used "filename + length - 1". Presumably this +was able to pass the fuzzer because in the old parser there was always +8 bytes of slack space between the tail pointer and the actual end of +the block. Since this is no longer the case the bounds check needs to be +updated to "filename + length + 1" in order to prevent a regression in +the handling of corrupt fliesystems. + +Notes: +* When there is only one extent there will only ever be one block. If + more than one block is required then XFS will always switch to holding + leaf information in a separate extent. +* B-tree based directories seems to be parsed properly by the same code + that handles multiple extents. This is unlikely to ever occur within + /boot though because its only used when there are an extremely large + number of directory entries. + +Fixes: ef7850c75 (fs/xfs: Fix issues found while fuzzing the XFS filesystem) +Fixes: b2499b29c (Adds support for the XFS filesystem.) +Fixes: https://savannah.gnu.org/bugs/?64376 + +Signed-off-by: Jon DeVree +Reviewed-by: Daniel Kiper +Tested-by: Sebastian Andrzej Siewior +Tested-by: Marta Lewandowska + +Origin: upstream +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1051543 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/2039172 +--- + grub-core/fs/xfs.c | 52 ++++++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 38 insertions(+), 14 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index ebf9627..18edfcf 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -223,6 +223,12 @@ struct grub_xfs_inode + /* Size of struct grub_xfs_inode v2, up to unused4 member included. */ + #define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 76) + ++struct grub_xfs_dir_leaf_entry ++{ ++ grub_uint32_t hashval; ++ grub_uint32_t address; ++} GRUB_PACKED; ++ + struct grub_xfs_dirblock_tail + { + grub_uint32_t leaf_count; +@@ -874,9 +880,8 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + { + struct grub_xfs_dir2_entry *direntry = + grub_xfs_first_de(dir->data, dirblock); +- int entries; +- struct grub_xfs_dirblock_tail *tail = +- grub_xfs_dir_tail(dir->data, dirblock); ++ int entries = -1; ++ char *end = dirblock + dirblk_size; + + numread = grub_xfs_read_file (dir, 0, 0, + blk << dirblk_log2, +@@ -887,14 +892,27 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + return 0; + } + +- entries = (grub_be_to_cpu32 (tail->leaf_count) +- - grub_be_to_cpu32 (tail->leaf_stale)); ++ /* ++ * Leaf and tail information are only in the data block if the number ++ * of extents is 1. ++ */ ++ if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1)) ++ { ++ struct grub_xfs_dirblock_tail *tail = grub_xfs_dir_tail (dir->data, dirblock); ++ ++ end = (char *) tail; ++ ++ /* Subtract the space used by leaf nodes. */ ++ end -= grub_be_to_cpu32 (tail->leaf_count) * sizeof (struct grub_xfs_dir_leaf_entry); + +- if (!entries) +- continue; ++ entries = grub_be_to_cpu32 (tail->leaf_count) - grub_be_to_cpu32 (tail->leaf_stale); ++ ++ if (!entries) ++ continue; ++ } + + /* Iterate over all entries within this block. */ +- while ((char *)direntry < (char *)tail) ++ while ((char *) direntry < (char *) end) + { + grub_uint8_t *freetag; + char *filename; +@@ -914,7 +932,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + } + + filename = (char *)(direntry + 1); +- if (filename + direntry->len - 1 > (char *) tail) ++ if (filename + direntry->len + 1 > (char *) end) + return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry"); + + /* The byte after the filename is for the filetype, padding, or +@@ -928,11 +946,17 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + return 1; + } + +- /* Check if last direntry in this block is +- reached. */ +- entries--; +- if (!entries) +- break; ++ /* ++ * The expected number of directory entries is only tracked for the ++ * single extent case. ++ */ ++ if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1)) ++ { ++ /* Check if last direntry in this block is reached. */ ++ entries--; ++ if (!entries) ++ break; ++ } + + /* Select the next directory entry. */ + direntry = grub_xfs_next_de(dir->data, direntry); diff -Nru grub2-2.12~rc1/debian/patches/upstream/xfs-incorrect-directory-data-boundary-check.patch grub2-2.12~rc1/debian/patches/upstream/xfs-incorrect-directory-data-boundary-check.patch --- grub2-2.12~rc1/debian/patches/upstream/xfs-incorrect-directory-data-boundary-check.patch 1970-01-01 00:00:00.000000000 +0000 +++ grub2-2.12~rc1/debian/patches/upstream/xfs-incorrect-directory-data-boundary-check.patch 2024-03-21 09:16:17.000000000 +0000 @@ -0,0 +1,48 @@ +From: Lidong Chen +Date: Thu, 28 Sep 2023 22:33:44 +0000 +Subject: fs/xfs: Incorrect short form directory data boundary check + +After parsing of the current entry, the entry pointer is advanced +to the next entry at the end of the "for" loop. In case where the +last entry is at the end of the data boundary, the advanced entry +pointer can point off the data boundary. The subsequent boundary +check for the advanced entry pointer can cause a failure. + +The fix is to include the boundary check into the "for" loop +condition. + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +Tested-by: Sebastian Andrzej Siewior +Tested-by: Marta Lewandowska + +Origin: upstream +--- + grub-core/fs/xfs.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index b91cd32..ebf9627 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -810,7 +810,8 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + if (iterate_dir_call_hook (parent, "..", &ctx)) + return 1; + +- for (i = 0; i < head->count; i++) ++ for (i = 0; i < head->count && ++ (grub_uint8_t *) de < ((grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data)); i++) + { + grub_uint64_t ino; + grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de); +@@ -845,10 +846,6 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + de->name[de->len] = c; + + de = grub_xfs_inline_next_de(dir->data, head, de); +- +- if ((grub_uint8_t *) de >= (grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data)) +- return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry"); +- + } + break; + } diff -Nru grub2-2.12~rc1/debian/sbat.ubuntu.csv.in grub2-2.12~rc1/debian/sbat.ubuntu.csv.in --- grub2-2.12~rc1/debian/sbat.ubuntu.csv.in 2023-10-02 14:23:58.000000000 +0000 +++ grub2-2.12~rc1/debian/sbat.ubuntu.csv.in 2024-03-21 09:16:17.000000000 +0000 @@ -1,4 +1,4 @@ sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md grub,4,Free Software Foundation,grub,@UPSTREAM_VERSION@,https://www.gnu.org/software/grub/ -grub.ubuntu,1,Ubuntu,grub2,@DEB_VERSION@,https://www.ubuntu.com/ -grub.peimage,1,Canonical,grub2,@DEB_VERSION@,https://salsa.debian.org/grub-team/grub/-/blob/master/debian/patches/secure-boot/efi-use-peimage-shim.patch +grub.ubuntu,2,Ubuntu,grub2,@DEB_VERSION@,https://www.ubuntu.com/ +grub.peimage,2,Canonical,grub2,@DEB_VERSION@,https://salsa.debian.org/grub-team/grub/-/blob/master/debian/patches/secure-boot/efi-use-peimage-shim.patch