From: Mate Kukri Date: Wed, 12 Jun 2024 15:10:49 +0000 (+0100) Subject: kern/efi/mm: Change grub_efi_mm_add_regions() to keep track of map allocation size X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dc0a3a27d67a6b1639d155cc69e8537077af1047;p=thirdparty%2Fgrub.git kern/efi/mm: Change grub_efi_mm_add_regions() to keep track of map allocation size If the map was too big for the initial allocation, it was freed and replaced with a bigger one, but the free call still used the hard-coded size. Seems like this wasn't hit for a long time, because most firmware maps fit into 12K. This bug was triggered on Project Mu firmware with a big memory map, and results in the heap getting trashed and the firmware ASSERTING on corrupted heap guard values when GRUB exits. Signed-off-by: Mate Kukri Reviewed-by: Daniel Kiper --- diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index 6a6fba891..739229e7b 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -574,13 +574,15 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags) grub_efi_memory_descriptor_t *memory_map_end; grub_efi_memory_descriptor_t *filtered_memory_map; grub_efi_memory_descriptor_t *filtered_memory_map_end; + grub_efi_uintn_t alloc_size; grub_efi_uintn_t map_size; grub_efi_uintn_t desc_size; grub_err_t err; int mm_status; /* Prepare a memory region to store two memory maps. */ - memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + alloc_size = 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE); + memory_map = grub_efi_allocate_any_pages (alloc_size); if (! memory_map) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map"); @@ -591,14 +593,13 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags) if (mm_status == 0) { - grub_efi_free_pages - ((grub_efi_physical_address_t) ((grub_addr_t) memory_map), - 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) memory_map, alloc_size); /* Freeing/allocating operations may increase memory map size. */ map_size += desc_size * 32; - memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size)); + alloc_size = 2 * BYTES_TO_PAGES (map_size); + memory_map = grub_efi_allocate_any_pages (alloc_size); if (! memory_map) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map"); @@ -642,8 +643,7 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags) #endif /* Release the memory maps. */ - grub_efi_free_pages ((grub_addr_t) memory_map, - 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) memory_map, alloc_size); return GRUB_ERR_NONE; }